diff options
-rw-r--r-- | src/c/urweb.c | 18 | ||||
-rw-r--r-- | tests/goodbye.ur | 26 | ||||
-rw-r--r-- | tests/goodbye.urp | 6 | ||||
-rw-r--r-- | tests/goodbye.urs | 1 |
4 files changed, 41 insertions, 10 deletions
diff --git a/src/c/urweb.c b/src/c/urweb.c index b105d5ff..9f318c95 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -159,13 +159,7 @@ typedef struct client { static client **clients, *clients_free, *clients_used; static unsigned n_clients; -static pthread_mutex_t clients_mutex = - #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER - PTHREAD_RECURSIVE_MUTEX_INITIALIZER - #else - PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP - #endif - ; +static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; size_t uw_messages_max = SIZE_MAX; size_t uw_clients_max = SIZE_MAX; @@ -230,20 +224,22 @@ static void release_client(client *c) { } static const char begin_msgs[] = "Content-type: text/plain\r\n\r\n"; +static pthread_t pruning_thread; +static int pruning_thread_initialized = 0; static client *find_client(unsigned id) { client *c; - pthread_mutex_lock(&clients_mutex); + if (!pruning_thread_initialized || !pthread_equal(pruning_thread, pthread_self())) pthread_mutex_lock(&clients_mutex); if (id >= n_clients) { - pthread_mutex_unlock(&clients_mutex); + if (!pruning_thread_initialized || !pthread_equal(pruning_thread, pthread_self())) pthread_mutex_unlock(&clients_mutex); return NULL; } c = clients[id]; - pthread_mutex_unlock(&clients_mutex); + if (!pruning_thread_initialized || !pthread_equal(pruning_thread, pthread_self())) pthread_mutex_unlock(&clients_mutex); return c; } @@ -3291,6 +3287,8 @@ void uw_prune_clients(uw_context ctx) { cutoff = time(NULL) - ctx->app->timeout; pthread_mutex_lock(&clients_mutex); + pruning_thread = pthread_self(); + pruning_thread_initialized = 1; for (c = clients_used; c; c = next) { next = c->next; diff --git a/tests/goodbye.ur b/tests/goodbye.ur new file mode 100644 index 00000000..1a466581 --- /dev/null +++ b/tests/goodbye.ur @@ -0,0 +1,26 @@ +table boo : { Client : client, Channel : channel unit } + +fun doIt () = + me <- self; + ch <- channel; + dml (INSERT INTO boo (Client, Channel) VALUES ({[me]}, {[ch]})); + return <xml><body onload={let + fun loop () = + v <- recv ch; + alert "Someone left"; + loop () + in + loop () + end}/></xml> + +task clientLeaves = fn cl => + debug "Client left"; + dml (DELETE FROM boo WHERE Client = {[cl]}); + queryI (SELECT (boo.Channel) + FROM boo) + (fn r => send r.1 ()); + debug "Done processing" + +fun main () = return <xml><body> + <form> <submit action={doIt}/> </form> +</body></xml> diff --git a/tests/goodbye.urp b/tests/goodbye.urp new file mode 100644 index 00000000..2a469815 --- /dev/null +++ b/tests/goodbye.urp @@ -0,0 +1,6 @@ +database dbname=goodbye +sql goodbye.sql +rewrite all Goodbye/* +timeout 5 + +goodbye
\ No newline at end of file diff --git a/tests/goodbye.urs b/tests/goodbye.urs new file mode 100644 index 00000000..901d6bf2 --- /dev/null +++ b/tests/goodbye.urs @@ -0,0 +1 @@ +val main : {} -> transaction page |