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;