summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/c/urweb.c18
-rw-r--r--tests/goodbye.ur26
-rw-r--r--tests/goodbye.urp6
-rw-r--r--tests/goodbye.urs1
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