Mercurial > urweb
diff src/c/urweb.c @ 672:df6eb58de040
Fix some AJAX annoyances
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 24 Mar 2009 15:05:28 -0400 |
parents | 729e65db2e2f |
children | a8effb6159c2 |
line wrap: on
line diff
--- a/src/c/urweb.c Tue Mar 24 14:44:45 2009 -0400 +++ b/src/c/urweb.c Tue Mar 24 15:05:28 2009 -0400 @@ -77,16 +77,22 @@ } static void buf_append(buf *b, const char *s, size_t len) { - buf_check(b, len); + buf_check(b, len+1); memcpy(b->front, s, len); b->front += len; + *b->front = 0; } -// Persistent client state +// Persistent state types typedef enum { UNUSED, USED } usage; +typedef struct channel_list { + struct channel *data; + struct channel_list *next; +} channel_list; + typedef struct client { size_t id; usage mode; @@ -99,10 +105,32 @@ int sock; time_t last_contact; unsigned refcount; + channel_list *channels; } used; } data; } client; +typedef struct client_list { + client *data; + struct client_list *next; +} client_list; + +typedef struct channel { + size_t id; + usage mode; + union { + struct channel *next; + struct { + pthread_mutex_t lock; + client_list *clients; + unsigned refcount; + } used; + } data; +} channel; + + +// Persistent client state + static client **clients, *clients_free; static size_t n_clients; @@ -130,8 +158,9 @@ c->data.used.pass = rand(); c->data.used.sock = -1; c->data.used.last_contact = time(NULL); + buf_init(&c->data.used.msgs, 0); c->data.used.refcount = 0; - buf_init(&c->data.used.msgs, 0); + c->data.used.channels = NULL; pthread_mutex_unlock(&clients_mutex); @@ -210,17 +239,53 @@ pthread_mutex_unlock(&c->data.used.lock); } + static void uw_free_client(client *c) { + channel_list *chs; + printf("Freeing client %d\n", c->id); - if (c->mode == USED && c->data.used.sock != -1) - close(c->data.used.sock); + if (c->mode == USED) { + pthread_mutex_lock(&c->data.used.lock); - pthread_mutex_destroy(&c->data.used.lock); - buf_free(&c->data.used.msgs); - c->mode = UNUSED; - c->data.next = clients_free; - clients_free = c; + for (chs = c->data.used.channels; chs; ) { + client_list *prev, *cs; + + channel *ch = chs->data; + channel_list *tmp = chs->next; + free(chs); + chs = tmp; + + pthread_mutex_lock(&ch->data.used.lock); + for (prev = NULL, cs = ch->data.used.clients; cs; ) { + if (cs->data == c) { + client_list *tmp = cs->next; + free(cs); + cs = tmp; + if (prev) + prev->next = cs; + else + ch->data.used.clients = cs; + } + else { + prev = cs; + cs = cs->next; + } + } + pthread_mutex_unlock(&ch->data.used.lock); + } + + if (c->data.used.sock != -1) + close(c->data.used.sock); + + pthread_mutex_unlock(&c->data.used.lock); + pthread_mutex_destroy(&c->data.used.lock); + buf_free(&c->data.used.msgs); + c->mode = UNUSED; + + c->data.next = clients_free; + clients_free = c; + } } void uw_prune_clients(time_t timeout) { @@ -243,23 +308,6 @@ // Persistent channel state -typedef struct client_list { - client *data; - struct client_list *next; -} client_list; - -typedef struct channel { - size_t id; - usage mode; - union { - struct channel *next; - struct { - pthread_mutex_t lock; - client_list *clients; - unsigned refcount; - } used; - } data; -} channel; static channel **channels, *channels_free; static size_t n_channels;