Browse Source

attempt to lower idle CPU usage when reading list/blist

git.mgm/mediaproxy-ng/master
Richard Fuchs 12 years ago
parent
commit
9edb5a3677
1 changed files with 186 additions and 81 deletions
  1. +186
    -81
      kernel-module/xt_MEDIAPROXY.c

+ 186
- 81
kernel-module/xt_MEDIAPROXY.c View File

@ -153,6 +153,16 @@ struct mediaproxy_target {
struct mp_crypto_context encrypt;
};
struct mp_bitfield {
unsigned long b[256 / (sizeof(unsigned long) * 8)];
unsigned int used;
};
struct mp_bucket {
struct mp_bitfield targets;
struct mediaproxy_target *target[256];
};
struct mediaproxy_table {
atomic_t refcnt;
rwlock_t target_lock;
@ -165,9 +175,9 @@ struct mediaproxy_table {
struct proc_dir_entry *list;
struct proc_dir_entry *blist;
struct mediaproxy_target **target[256];
struct mp_bitfield buckets;
struct mp_bucket *bucket[256];
unsigned int buckets;
unsigned int targets;
};
@ -481,6 +491,7 @@ static void clear_proc(struct proc_dir_entry **e) {
static void table_push(struct mediaproxy_table *t) {
int i, j;
struct mp_bucket *b;
if (!t)
return;
@ -491,19 +502,20 @@ static void table_push(struct mediaproxy_table *t) {
DBG("Freeing table\n");
for (i = 0; i < 256; i++) {
if (!t->target[i])
b = t->bucket[i];
if (!b)
continue;
for (j = 0; j < 256; j++) {
if (!t->target[i][j])
if (!b->target[j])
continue;
t->target[i][j]->table = -1;
target_push(t->target[i][j]);
t->target[i][j] = NULL;
b->target[j]->table = -1;
target_push(b->target[j]);
b->target[j] = NULL;
}
kfree(t->target[i]);
t->target[i] = NULL;
kfree(b);
t->bucket[i] = NULL;
}
clear_proc(&t->status);
@ -599,7 +611,7 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o)
len += sprintf(buf + len, "Refcount: %u\n", atomic_read(&t->refcnt) - 1);
len += sprintf(buf + len, "Control PID: %u\n", t->pid);
len += sprintf(buf + len, "Targets: %u\n", t->targets);
len += sprintf(buf + len, "Buckets: %u\n", t->buckets);
len += sprintf(buf + len, "Buckets: %u\n", t->buckets.used);
read_unlock_irqrestore(&t->target_lock, flags);
table_push(t);
@ -664,6 +676,105 @@ static int proc_main_list_show(struct seq_file *f, void *v) {
static inline unsigned char bitfield_next_slot(unsigned int slot) {
unsigned char c;
c = slot * (sizeof(unsigned long) * 8);
c += sizeof(unsigned long) * 8;
return c;
}
static inline unsigned int bitfield_slot(unsigned char i) {
return i / (sizeof(unsigned long) * 8);
}
static inline unsigned int bitfield_bit(unsigned char i) {
return i % (sizeof(unsigned long) * 8);
}
static inline void bitfield_set(struct mp_bitfield *bf, unsigned char i) {
unsigned int b, m;
unsigned long k;
b = bitfield_slot(i);
m = bitfield_bit(i);
k = 1 << m;
if ((bf->b[b] & k))
return;
bf->b[b] |= k;
bf->used++;
}
static inline void bitfield_clear(struct mp_bitfield *bf, unsigned char i) {
unsigned int b, m;
unsigned long k;
b = bitfield_slot(i);
m = bitfield_bit(i);
k = 1 << m;
if (!(bf->b[b] & k))
return;
bf->b[b] &= ~k;
bf->used--;
}
static inline struct mediaproxy_target *find_next_target(struct mediaproxy_table *t, int *port) {
unsigned long flags;
struct mp_bucket *b;
unsigned char hi, lo;
unsigned int hi_b, lo_b;
struct mediaproxy_target *g;
if (*port < 0 || *port > 0xffff)
return NULL;
hi = (*port & 0xff00) >> 8;
lo = *port & 0xff;
read_lock_irqsave(&t->target_lock, flags);
for (;;) {
hi_b = bitfield_slot(hi);
if (!t->buckets.b[hi_b]) {
hi = bitfield_next_slot(hi_b);
lo = 0;
goto next;
}
b = t->bucket[hi];
if (!b) {
hi++;
lo = 0;
goto next;
}
lo_b = bitfield_slot(lo);
if (!b->targets.b[lo_b]) {
lo = bitfield_next_slot(lo_b);
goto next_lo;
}
g = b->target[lo];
if (!g) {
lo++;
goto next_lo;
}
target_hold(g);
break;
next_lo:
if (!lo)
hi++;
next:
if (!hi && !lo)
break;
}
read_unlock_irqrestore(&t->target_lock, flags);
*port = (hi << 8) | lo;
(*port)++;
return g;
}
static int proc_blist_open(struct inode *i, struct file *f) {
u_int32_t id;
struct mediaproxy_table *t;
@ -700,6 +811,7 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
int err;
struct mediaproxy_target *g;
unsigned long flags;
int port;
if (l != sizeof(op))
return -EINVAL;
@ -712,15 +824,12 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
if (!t)
return -ENOENT;
for (;;) {
err = 0;
if (*o > 0xffff)
goto err;
g = get_target(t, (*o)++);
if (g)
break;
}
port = (int) *o;
g = find_next_target(t, &port);
*o = port;
err = 0;
if (!g)
goto err;
memset(&op, 0, sizeof(op));
memcpy(&op.target, &g->target, sizeof(op.target));
@ -789,46 +898,19 @@ static void proc_list_stop(struct seq_file *f, void *v) {
static void *proc_list_next(struct seq_file *f, void *v, loff_t *o) { /* v is invalid */
u_int32_t id = (u_int32_t) (unsigned long) f->private;
struct mediaproxy_target *g = NULL;
struct mediaproxy_table *t;
u_int16_t port;
unsigned char hi, lo;
unsigned long flags;
struct mediaproxy_target *g;
int port;
if (*o < 0 || *o > 0xffff)
return NULL;
port = (u_int16_t) *o;
port = (int) *o;
t = get_table(id);
if (!t)
return NULL;
hi = (port & 0xff00) >> 8;
lo = port & 0xff;
read_lock_irqsave(&t->target_lock, flags);
for (;;) {
lo++; /* will make the iteration start from 1 */
if (lo == 0) {
hi++;
if (hi == 0)
break;
}
if (!t->target[hi]) {
lo = 0xff;
continue;
}
g = t->target[hi][lo];
if (!g)
continue;
target_hold(g);
break;
}
read_unlock_irqrestore(&t->target_lock, flags);
g = find_next_target(t, &port);
*o = (hi << 8) | lo;
*o = port;
table_push(t);
return g;
@ -902,7 +984,8 @@ static int proc_list_show(struct seq_file *f, void *v) {
static int table_del_target(struct mediaproxy_table *t, u_int16_t port) {
unsigned char hi, lo;
struct mediaproxy_target *g;
struct mp_bucket *b;
struct mediaproxy_target *g = NULL;
unsigned long flags;
if (!port)
@ -912,15 +995,30 @@ static int table_del_target(struct mediaproxy_table *t, u_int16_t port) {
lo = port & 0xff;
write_lock_irqsave(&t->target_lock, flags);
g = t->target[hi] ? t->target[hi][lo] : NULL;
if (g) {
t->target[hi][lo] = NULL;
t->targets--;
b = t->bucket[hi];
if (!b)
goto out;
g = b->target[lo];
if (!g)
goto out;
b->target[lo] = NULL;
bitfield_clear(&b->targets, lo);
t->targets--;
if (!b->targets.used) {
t->bucket[hi] = NULL;
bitfield_clear(&t->buckets, hi);
}
else
b = NULL;
out:
write_unlock_irqrestore(&t->target_lock, flags);
if (!g)
return -ENOENT;
if (b)
kfree(b);
target_push(g);
@ -1247,6 +1345,7 @@ error:
static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_srtp *s) {
c->cipher = &mp_ciphers[s->cipher];
c->hmac = &mp_hmacs[s->hmac];
@ -1255,7 +1354,7 @@ static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_s
static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target_info *i, int update) {
unsigned char hi, lo;
struct mediaproxy_target *g;
struct mediaproxy_target **gp;
struct mp_bucket *b, *ba = NULL;
struct mediaproxy_target *og = NULL;
int err;
unsigned long flags;
@ -1302,31 +1401,37 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
if (err)
goto fail2;
err = -ENOMEM;
if (update)
gp = NULL;
else {
gp = kmalloc(sizeof(void *) * 256, GFP_KERNEL);
if (!gp)
goto fail2;
memset(gp, 0, sizeof(void *) * 256);
}
hi = (i->target_port & 0xff00) >> 8;
lo = i->target_port & 0xff;
write_lock_irqsave(&t->target_lock, flags);
if (!t->target[hi]) {
if (!(b = t->bucket[hi])) {
err = -ENOENT;
if (update)
goto fail4;
t->target[hi] = gp;
gp = NULL;
t->buckets++;
write_unlock_irqrestore(&t->target_lock, flags);
b = kmalloc(sizeof(*b), GFP_KERNEL);
err = -ENOMEM;
if (!b)
goto fail2;
memset(b, 0, sizeof(*b));
write_lock_irqsave(&t->target_lock, flags);
if (!t->bucket[hi]) {
t->bucket[hi] = b;
bitfield_set(&t->buckets, hi);
}
else {
ba = b;
b = t->bucket[hi];
}
}
if (update) {
err = -ENOENT;
og = t->target[hi][lo];
og = b->target[lo];
if (!og)
goto fail4;
@ -1336,18 +1441,18 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
}
else {
err = -EEXIST;
if (t->target[hi][lo])
if (b->target[lo])
goto fail4;
bitfield_set(&b->targets, lo);
t->targets++;
}
t->target[hi][lo] = g;
b->target[lo] = g;
g = NULL;
if (!update)
t->targets++;
write_unlock_irqrestore(&t->target_lock, flags);
if (gp)
kfree(gp);
if (ba)
kfree(ba);
if (og)
target_push(og);
@ -1355,8 +1460,8 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
fail4:
write_unlock_irqrestore(&t->target_lock, flags);
if (gp)
kfree(gp);
if (ba)
kfree(ba);
fail2:
kfree(g);
fail1:
@ -1381,7 +1486,7 @@ static struct mediaproxy_target *get_target(struct mediaproxy_table *t, u_int16_
lo = port & 0xff;
read_lock_irqsave(&t->target_lock, flags);
r = t->target[hi] ? t->target[hi][lo] : NULL;
r = t->bucket[hi] ? t->bucket[hi]->target[lo] : NULL;
if (r)
target_hold(r);
read_unlock_irqrestore(&t->target_lock, flags);


Loading…
Cancel
Save