Mercurial > urweb
comparison src/c/urweb.c @ 685:c73c5fe72388
Stop holding client locks throughout request processing
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Thu, 02 Apr 2009 10:55:00 -0400 |
parents | f0224c7f12bb |
children | a3ddf05fb3e3 |
comparison
equal
deleted
inserted
replaced
684:f0224c7f12bb | 685:c73c5fe72388 |
---|---|
97 pthread_mutex_t lock; | 97 pthread_mutex_t lock; |
98 buf msgs; | 98 buf msgs; |
99 int sock; | 99 int sock; |
100 time_t last_contact; | 100 time_t last_contact; |
101 unsigned n_channels; | 101 unsigned n_channels; |
102 unsigned refcount; | |
102 } client; | 103 } client; |
103 | 104 |
104 | 105 |
105 // Persistent client state | 106 // Persistent client state |
106 | 107 |
133 c->pass = rand(); | 134 c->pass = rand(); |
134 c->sock = -1; | 135 c->sock = -1; |
135 c->last_contact = time(NULL); | 136 c->last_contact = time(NULL); |
136 buf_reset(&c->msgs); | 137 buf_reset(&c->msgs); |
137 c->n_channels = 0; | 138 c->n_channels = 0; |
139 c->refcount = 0; | |
138 pthread_mutex_unlock(&c->lock); | 140 pthread_mutex_unlock(&c->lock); |
139 | 141 |
140 c->next = clients_used; | 142 c->next = clients_used; |
141 clients_used = c; | 143 clients_used = c; |
142 | 144 |
143 pthread_mutex_unlock(&clients_mutex); | 145 pthread_mutex_unlock(&clients_mutex); |
144 | 146 |
145 return c; | 147 return c; |
148 } | |
149 | |
150 static void use_client(client *c) { | |
151 pthread_mutex_lock(&c->lock); | |
152 ++c->refcount; | |
153 pthread_mutex_unlock(&c->lock); | |
154 } | |
155 | |
156 static void release_client(client *c) { | |
157 pthread_mutex_lock(&c->lock); | |
158 --c->refcount; | |
159 pthread_mutex_unlock(&c->lock); | |
146 } | 160 } |
147 | 161 |
148 static const char begin_msgs[] = "HTTP/1.1 200 OK\r\nContent-type: text/plain\r\n\r\n"; | 162 static const char begin_msgs[] = "HTTP/1.1 200 OK\r\nContent-type: text/plain\r\n\r\n"; |
149 | 163 |
150 static client *find_client(unsigned id) { | 164 static client *find_client(unsigned id) { |
220 static uw_Basis_channel new_channel(client *c) { | 234 static uw_Basis_channel new_channel(client *c) { |
221 uw_Basis_channel ch = {c->id, c->n_channels++}; | 235 uw_Basis_channel ch = {c->id, c->n_channels++}; |
222 return ch; | 236 return ch; |
223 } | 237 } |
224 | 238 |
225 static void client_send(int already_locked, client *c, buf *msg) { | 239 static void client_send(client *c, buf *msg) { |
226 if (!already_locked) | 240 pthread_mutex_lock(&c->lock); |
227 pthread_mutex_lock(&c->lock); | |
228 | 241 |
229 if (c->sock != -1) { | 242 if (c->sock != -1) { |
230 uw_really_send(c->sock, begin_msgs, sizeof(begin_msgs) - 1); | 243 uw_really_send(c->sock, begin_msgs, sizeof(begin_msgs) - 1); |
231 uw_really_send(c->sock, msg->start, buf_used(msg)); | 244 uw_really_send(c->sock, msg->start, buf_used(msg)); |
232 close(c->sock); | 245 close(c->sock); |
233 c->sock = -1; | 246 c->sock = -1; |
234 } else | 247 } else |
235 buf_append(&c->msgs, msg->start, buf_used(msg)); | 248 buf_append(&c->msgs, msg->start, buf_used(msg)); |
236 | 249 |
237 if (!already_locked) | 250 pthread_mutex_unlock(&c->lock); |
238 pthread_mutex_unlock(&c->lock); | |
239 } | 251 } |
240 | 252 |
241 | 253 |
242 // Global entry points | 254 // Global entry points |
243 | 255 |
470 client *c = find_client(id); | 482 client *c = find_client(id); |
471 | 483 |
472 if (c == NULL) | 484 if (c == NULL) |
473 uw_error(ctx, FATAL, "Unknown client ID in HTTP headers (%s, %s)", id_s, pass_s); | 485 uw_error(ctx, FATAL, "Unknown client ID in HTTP headers (%s, %s)", id_s, pass_s); |
474 else { | 486 else { |
475 pthread_mutex_lock(&c->lock); | 487 use_client(c); |
476 ctx->client = c; | 488 ctx->client = c; |
477 | 489 |
478 if (c->mode != USED) | 490 if (c->mode != USED) |
479 uw_error(ctx, FATAL, "Stale client ID (%u) in subscription request", id); | 491 uw_error(ctx, FATAL, "Stale client ID (%u) in subscription request", id); |
480 if (c->pass != pass) | 492 if (c->pass != pass) |
481 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass); | 493 uw_error(ctx, FATAL, "Wrong client password (%u, %d) in subscription request", id, pass); |
482 } | 494 } |
483 } else { | 495 } else { |
484 client *c = new_client(); | 496 client *c = new_client(); |
485 pthread_mutex_lock(&c->lock); | 497 use_client(c); |
486 ctx->client = c; | 498 ctx->client = c; |
487 } | 499 } |
488 } | 500 } |
489 } | 501 } |
490 | 502 |
1845 delta *d = &ctx->deltas[i]; | 1857 delta *d = &ctx->deltas[i]; |
1846 client *c = find_client(d->client); | 1858 client *c = find_client(d->client); |
1847 | 1859 |
1848 assert (c != NULL && c->mode == USED); | 1860 assert (c != NULL && c->mode == USED); |
1849 | 1861 |
1850 client_send(c == ctx->client, c, &d->msgs); | 1862 client_send(c, &d->msgs); |
1851 } | 1863 } |
1852 | 1864 |
1853 if (ctx->client) | 1865 if (ctx->client) |
1854 pthread_mutex_unlock(&ctx->client->lock); | 1866 release_client(ctx->client); |
1855 } | 1867 } |
1856 | 1868 |
1857 int uw_rollback(uw_context ctx) { | 1869 int uw_rollback(uw_context ctx) { |
1858 if (ctx->client) | 1870 if (ctx->client) |
1859 pthread_mutex_unlock(&ctx->client->lock); | 1871 release_client(ctx->client); |
1860 | 1872 |
1861 return uw_db_rollback(ctx); | 1873 return uw_db_rollback(ctx); |
1862 } | 1874 } |
1863 | 1875 |
1864 | 1876 |
1889 pthread_mutex_lock(&clients_mutex); | 1901 pthread_mutex_lock(&clients_mutex); |
1890 | 1902 |
1891 for (c = clients_used; c; c = next) { | 1903 for (c = clients_used; c; c = next) { |
1892 next = c->next; | 1904 next = c->next; |
1893 pthread_mutex_lock(&c->lock); | 1905 pthread_mutex_lock(&c->lock); |
1894 if (c->last_contact < cutoff) { | 1906 if (c->last_contact < cutoff && c->refcount == 0) { |
1895 failure_kind fk = UNLIMITED_RETRY; | 1907 failure_kind fk = UNLIMITED_RETRY; |
1896 if (prev) | 1908 if (prev) |
1897 prev->next = next; | 1909 prev->next = next; |
1898 else | 1910 else |
1899 clients_used = next; | 1911 clients_used = next; |