From 7d66aadb65a25a97e2a28de797e1328f88498513 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Tue, 24 Mar 2009 15:35:46 -0400 Subject: Variable timeouts and client keep-alive --- lib/js/urweb.js | 24 +++++++++++++++++++----- src/c/urweb.c | 27 ++++++++++++++++++--------- src/cjr_print.sig | 2 ++ src/cjr_print.sml | 6 ++++++ src/compiler.sig | 3 ++- src/compiler.sml | 42 +++++++++++++++++++++++++++--------------- src/demo.sml | 1 + tests/channel.urp | 1 + 8 files changed, 76 insertions(+), 30 deletions(-) diff --git a/lib/js/urweb.js b/lib/js/urweb.js index be1aea08..6d405347 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -141,6 +141,7 @@ function cr(n) { var client_id = 0; var client_pass = 0; var url_prefix = "/"; +var timeout = 60; function getXHR(uri) { @@ -234,8 +235,18 @@ function newChannel() { function listener() { var uri = path_join(url_prefix, ".msgs"); var xhr = getXHR(); - var orsc = function() { + var tid, orsc, onTimeout; + + var connect = function () { + xhr.onreadystatechange = orsc; + tid = window.setTimeout(onTimeout, timeout * 500); + requestUri(xhr, uri); + } + + orsc = function() { if (xhr.readyState == 4) { + window.clearTimeout(tid); + var isok = false; try { @@ -271,8 +282,7 @@ function listener() { } } - xhr.onreadystatechange = orsc; - requestUri(xhr, uri); + connect(); } else { try { @@ -282,8 +292,12 @@ function listener() { } }; - xhr.onreadystatechange = orsc; - requestUri(xhr, uri); + onTimeout = function() { + xhr.abort(); + connect(); + }; + + connect(); } function rv(chn, parse, k) { diff --git a/src/c/urweb.c b/src/c/urweb.c index 6cc786ef..5fa2af42 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -220,10 +220,8 @@ void uw_client_connect(size_t id, int pass, int sock) { } if (c->data.used.sock != -1) { - pthread_mutex_unlock(&c->data.used.lock); - close(sock); - fprintf(stderr, "Duplicate client connection (%d)\n", (int)id); - return; + close(c->data.used.sock); + c->data.used.sock = -1; } c->data.used.last_contact = time(NULL); @@ -288,11 +286,13 @@ static void uw_free_client(client *c) { } } -void uw_prune_clients(time_t timeout) { +extern int uw_timeout; + +void uw_prune_clients() { size_t i; time_t cutoff; - cutoff = time(NULL) - timeout; + cutoff = time(NULL) - uw_timeout; pthread_mutex_lock(&clients_mutex); @@ -507,6 +507,8 @@ struct uw_context { size_t n_deltas; channel_delta *deltas; + int timeout; + char error_message[ERROR_BUF_LEN]; }; @@ -541,6 +543,8 @@ uw_context uw_init(size_t outHeaders_len, size_t script_len, size_t page_len, si ctx->n_deltas = 0; ctx->deltas = malloc(0); + ctx->timeout = uw_timeout; + return ctx; } @@ -834,10 +838,15 @@ const char *uw_Basis_get_script(uw_context ctx, uw_unit u) { int pass; client *c = uw_new_client(&pass); - char *r = uw_malloc(ctx, strlen(ctx->script_header) + 56 + 2 * INTS_MAX + buf_used(&ctx->script) + char *r = uw_malloc(ctx, strlen(ctx->script_header) + 65 + 3 * INTS_MAX + buf_used(&ctx->script) + strlen(ctx->url_prefix)); - sprintf(r, "%s", - ctx->script_header, (int)c->id, c->data.used.pass, ctx->url_prefix, ctx->script.start); + sprintf(r, "%s", + ctx->script_header, + (int)c->id, + c->data.used.pass, + ctx->url_prefix, + ctx->timeout, + ctx->script.start); return r; } } diff --git a/src/cjr_print.sig b/src/cjr_print.sig index baef005e..d7fb21a0 100644 --- a/src/cjr_print.sig +++ b/src/cjr_print.sig @@ -36,4 +36,6 @@ signature CJR_PRINT = sig val p_sql : CjrEnv.env -> Cjr.file Print.printer val debug : bool ref + + val timeout : int ref end diff --git a/src/cjr_print.sml b/src/cjr_print.sml index c5931616..79a43d19 100644 --- a/src/cjr_print.sml +++ b/src/cjr_print.sml @@ -1124,6 +1124,8 @@ fun urlify env t = urlify' IS.empty 0 t end +val timeout = ref 0 + fun p_exp' par env (e, loc) = case e of EPrim p => Prim.p_t_GCC p @@ -2688,6 +2690,10 @@ fun p_file env (ds, ps) = string (Int.toString (SM.foldl Int.max 0 fnums + 1)), string ";", newline, + string "int uw_timeout = ", + string (Int.toString (!timeout)), + string ";", + newline, newline, string "int uw_input_num(char *name) {", newline, diff --git a/src/compiler.sig b/src/compiler.sig index 8ef41a58..025a6bcd 100644 --- a/src/compiler.sig +++ b/src/compiler.sig @@ -36,7 +36,8 @@ signature COMPILER = sig exe : string, sql : string option, debug : bool, - profile : bool + profile : bool, + timeout : int } val compile : string -> unit val compileC : {cname : string, oname : string, ename : string, libs : string, profile : bool} -> unit diff --git a/src/compiler.sml b/src/compiler.sml index b433a7b6..f9200731 100644 --- a/src/compiler.sml +++ b/src/compiler.sml @@ -42,7 +42,8 @@ type job = { exe : string, sql : string option, debug : bool, - profile : bool + profile : bool, + timeout : int } type ('src, 'dst) phase = { @@ -200,7 +201,7 @@ val parseUr = { handle LrParser.ParseError => [], print = SourcePrint.p_file} -fun p_job {prefix, database, exe, sql, sources, debug, profile} = +fun p_job {prefix, database, exe, sql, sources, debug, profile, timeout} = let open Print.PD open Print @@ -223,6 +224,10 @@ fun p_job {prefix, database, exe, sql, sources, debug, profile} = case sql of NONE => string "No SQL file." | SOME sql => string ("SQL fle: " ^ sql), + newline, + string "Timeout: ", + string (Int.toString timeout), + newline, string "Sources:", p_list string sources, newline] @@ -265,7 +270,7 @@ val parseUrp = { readSources acc end - fun finish (prefix, database, exe, sql, debug, profile, sources) = + fun finish (prefix, database, exe, sql, debug, profile, timeout, sources) = {prefix = Option.getOpt (prefix, "/"), database = database, exe = Option.getOpt (exe, OS.Path.joinBaseExt {base = OS.Path.base filename, @@ -273,12 +278,13 @@ val parseUrp = { sql = sql, debug = debug, profile = profile, + timeout = Option.getOpt (timeout, 60), sources = sources} - fun read (prefix, database, exe, sql, debug, profile) = + fun read (prefix, database, exe, sql, debug, profile, timeout) = case TextIO.inputLine inf of - NONE => finish (prefix, database, exe, sql, debug, profile, []) - | SOME "\n" => finish (prefix, database, exe, sql, debug, profile, readSources []) + NONE => finish (prefix, database, exe, sql, debug, profile, timeout, []) + | SOME "\n" => finish (prefix, database, exe, sql, debug, profile, timeout, readSources []) | SOME line => let val (cmd, arg) = Substring.splitl (fn x => not (Char.isSpace x)) (Substring.full line) @@ -290,32 +296,38 @@ val parseUrp = { (case prefix of NONE => () | SOME _ => ErrorMsg.error "Duplicate 'prefix' directive"; - read (SOME arg, database, exe, sql, debug, profile)) + read (SOME arg, database, exe, sql, debug, profile, timeout)) | "database" => (case database of NONE => () | SOME _ => ErrorMsg.error "Duplicate 'database' directive"; - read (prefix, SOME arg, exe, sql, debug, profile)) + read (prefix, SOME arg, exe, sql, debug, profile, timeout)) | "exe" => (case exe of NONE => () | SOME _ => ErrorMsg.error "Duplicate 'exe' directive"; - read (prefix, database, SOME (relify arg), sql, debug, profile)) + read (prefix, database, SOME (relify arg), sql, debug, profile, timeout)) | "sql" => (case sql of NONE => () | SOME _ => ErrorMsg.error "Duplicate 'sql' directive"; - read (prefix, database, exe, SOME (relify arg), debug, profile)) - | "debug" => read (prefix, database, exe, sql, true, profile) - | "profile" => read (prefix, database, exe, sql, debug, true) + read (prefix, database, exe, SOME (relify arg), debug, profile, timeout)) + | "debug" => read (prefix, database, exe, sql, true, profile, timeout) + | "profile" => read (prefix, database, exe, sql, debug, true, timeout) + | "timeout" => + (case timeout of + NONE => () + | SOME _ => ErrorMsg.error "Duplicate 'timeout' directive"; + read (prefix, database, exe, sql, debug, profile, SOME (valOf (Int.fromString arg)))) | _ => (ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'"); - read (prefix, database, exe, sql, debug, profile)) + read (prefix, database, exe, sql, debug, profile, timeout)) end - val job = read (NONE, NONE, NONE, NONE, false, false) + val job = read (NONE, NONE, NONE, NONE, false, false, NONE) in TextIO.closeIn inf; Monoize.urlPrefix := #prefix job; + CjrPrint.timeout := #timeout job; job end, print = p_job @@ -598,7 +610,7 @@ fun compileC {cname, oname, ename, libs, profile} = else if not (OS.Process.isSuccess (OS.Process.system link)) then print "C linking failed\n" else - print "Success\n" + () end fun compile job = diff --git a/src/demo.sml b/src/demo.sml index 4f0cb52e..43fa5ef0 100644 --- a/src/demo.sml +++ b/src/demo.sml @@ -93,6 +93,7 @@ fun make {prefix, dirname, guided} = sql = SOME (OS.Path.joinDirFile {dir = dirname, file = "demo.sql"}), debug = false, + timeout = Int.max (#timeout combined, #timeout urp), profile = false } diff --git a/tests/channel.urp b/tests/channel.urp index d49aa728..167899c4 100644 --- a/tests/channel.urp +++ b/tests/channel.urp @@ -1,3 +1,4 @@ debug +timeout 10 channel -- cgit v1.2.3