=== modified file 'execute.c' --- execute.c 2002-08-18 09:47:26 +0000 +++ execute.c 2002-08-29 03:02:41 +0000 @@ -1518,21 +1518,24 @@ { Var time; unsigned id = 0, f_index; + double when; time = POP(); f_index = READ_BYTES(bv, bc.numbytes_fork); if (op == OP_FORK_WITH_ID) id = READ_BYTES(bv, bc.numbytes_var_name); - if (time.type != TYPE_INT) { + if (time.type != TYPE_INT && time.type != TYPE_FLOAT) { free_var(time); RAISE_ERROR(E_TYPE); - } else if (time.v.num < 0) { - free_var(time); + } + when = time.type == TYPE_INT ? time.v.num : *time.v.fnum; + free_var(time); + if(when < 0) { RAISE_ERROR(E_INVARG); } else { enum error e; - e = enqueue_forked_task2(RUN_ACTIV, f_index, time.v.num, + e = enqueue_forked_task2(RUN_ACTIV, f_index, when, op == OP_FORK_WITH_ID ? id : -1); if (e != E_NONE) RAISE_ERROR(e); @@ -2464,19 +2467,24 @@ static package bf_suspend(Var arglist, Byte next, void *vdata, Objid progr) { - static int seconds; + static double seconds, *secondsp = NULL; int nargs = arglist.v.list[0].v.num; - if (nargs >= 1) - seconds = arglist.v.list[1].v.num; - else - seconds = -1; + if (nargs >= 1) { + seconds = arglist.v.list[1].type == TYPE_INT ? + arglist.v.list[1].v.num : + *arglist.v.list[1].v.fnum; + secondsp = &seconds; + } else { + secondsp = NULL; + } free_var(arglist); if (nargs >= 1 && seconds < 0) return make_error_pack(E_INVARG); - else - return make_suspend_pack(enqueue_suspended_task, &seconds); + else { + return make_suspend_pack(enqueue_suspended_task, secondsp); + } } static package @@ -2619,7 +2627,7 @@ bf_call_function_write, TYPE_STR); register_function("raise", 1, 3, bf_raise, TYPE_ANY, TYPE_STR, TYPE_ANY); - register_function("suspend", 0, 1, bf_suspend, TYPE_INT); + register_function("suspend", 0, 1, bf_suspend, TYPE_NUMERIC); register_function("read", 0, 2, bf_read, TYPE_OBJ, TYPE_ANY); register_function("seconds_left", 0, 0, bf_seconds_left); @@ -2874,10 +2882,13 @@ } -char rcsid_execute[] = "$Id: execute.c,v 1.13 2002/08/18 09:47:26 bjj Exp $"; +char rcsid_execute[] = "$Id: execute.c,v 1.13.4.1 2002/08/29 03:02:41 xythian Exp $"; /* * $Log: execute.c,v $ + * Revision 1.13.4.1 2002/08/29 03:02:41 xythian + * Merging Ben's sub-second suspend/fork. bf_suspend now supports both FLOAT and INT arguments. + * * Revision 1.13 2002/08/18 09:47:26 bjj * Finally made free_activation() take a pointer after noticing how !$%^& * much time it was taking in a particular profiling run. === modified file 'net_mp_fake.c' --- net_mp_fake.c 1997-03-03 04:18:21 +0000 +++ net_mp_fake.c 2002-08-29 03:01:37 +0000 @@ -136,10 +136,11 @@ } } } - + + timeout -= 1000000; if (got_one) break; - else if (timeout-- > 0) + else if (timeout > 0) sleep(1); } @@ -158,12 +159,15 @@ return (fd < rw_size) ? writable[fd] : 0; } -char rcsid_net_mp_fake[] = "$Id: net_mp_fake.c,v 1.2 1997/03/03 04:19:03 nop Exp $"; +char rcsid_net_mp_fake[] = "$Id: net_mp_fake.c,v 1.2.6.1 2002/08/29 03:01:54 xythian Exp $"; /* $Log: net_mp_fake.c,v $ - * Revision 1.2 1997/03/03 04:19:03 nop - * GNU Indent normalization + * Revision 1.2.6.1 2002/08/29 03:01:54 xythian + * Merging Ben's sub-second suspend/fork. Network i/o timeouts are now in terms of microseconds. db_flush() call is no longer made. * +/* Revision 1.2 1997/03/03 04:19:03 nop +/* GNU Indent normalization +/* * Revision 1.1.1.1 1997/03/03 03:45:02 nop * LambdaMOO 1.8.0p5 * === modified file 'net_mp_poll.c' --- net_mp_poll.c 1997-03-03 04:18:21 +0000 +++ net_mp_poll.c 2002-08-29 03:01:37 +0000 @@ -80,7 +80,7 @@ int mplex_wait(unsigned timeout) { - int result = poll(ports, max_fd + 1, timeout * 1000); + int result = poll(ports, max_fd + 1, timeout / 1000); if (result < 0) { if (errno != EINTR) @@ -102,12 +102,15 @@ return fd <= max_fd && (ports[fd].revents & POLLOUT) != 0; } -char rcsid_net_mp_poll[] = "$Id: net_mp_poll.c,v 1.2 1997/03/03 04:19:04 nop Exp $"; +char rcsid_net_mp_poll[] = "$Id: net_mp_poll.c,v 1.2.6.1 2002/08/29 03:01:54 xythian Exp $"; /* $Log: net_mp_poll.c,v $ - * Revision 1.2 1997/03/03 04:19:04 nop - * GNU Indent normalization + * Revision 1.2.6.1 2002/08/29 03:01:54 xythian + * Merging Ben's sub-second suspend/fork. Network i/o timeouts are now in terms of microseconds. db_flush() call is no longer made. * +/* Revision 1.2 1997/03/03 04:19:04 nop +/* GNU Indent normalization +/* * Revision 1.1.1.1 1997/03/03 03:45:02 nop * LambdaMOO 1.8.0p5 * === modified file 'net_mp_selct.c' --- net_mp_selct.c 1998-12-14 13:17:26 +0000 +++ net_mp_selct.c 2002-08-29 03:01:37 +0000 @@ -58,8 +58,8 @@ struct timeval tv; int n; - tv.tv_sec = timeout; - tv.tv_usec = 0; + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; n = select(max_descriptor + 1, (void *) &input, (void *) &output, 0, &tv); @@ -83,10 +83,13 @@ return FD_ISSET(fd, &output); } -char rcsid_net_mp_selct[] = "$Id: net_mp_selct.c,v 1.3 1998/12/14 13:18:28 nop Exp $"; +char rcsid_net_mp_selct[] = "$Id: net_mp_selct.c,v 1.3.4.1 2002/08/29 03:01:54 xythian Exp $"; /* * $Log: net_mp_selct.c,v $ + * Revision 1.3.4.1 2002/08/29 03:01:54 xythian + * Merging Ben's sub-second suspend/fork. Network i/o timeouts are now in terms of microseconds. db_flush() call is no longer made. + * * Revision 1.3 1998/12/14 13:18:28 nop * Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims * === modified file 'net_single.c' --- net_single.c 1997-03-03 04:18:21 +0000 +++ net_single.c 2002-08-29 03:01:37 +0000 @@ -198,8 +198,8 @@ sh = server_new_connection(slistener, nh, 0); state = STATE_OPEN; got_some = 1; - } else if (timeout != 0) - sleep(timeout); + } else if (timeout > 0) + sleep(timeout / 1000000); break; case STATE_OPEN: @@ -223,11 +223,11 @@ } } - if (got_some || timeout == 0) + if (got_some || timeout <= 0) goto done; sleep(1); - timeout--; + timeout -= 1000000; } } @@ -235,12 +235,15 @@ return got_some; } -char rcsid_net_single[] = "$Id: net_single.c,v 1.2 1997/03/03 04:19:07 nop Exp $"; +char rcsid_net_single[] = "$Id: net_single.c,v 1.2.6.1 2002/08/29 03:01:54 xythian Exp $"; /* $Log: net_single.c,v $ - * Revision 1.2 1997/03/03 04:19:07 nop - * GNU Indent normalization + * Revision 1.2.6.1 2002/08/29 03:01:54 xythian + * Merging Ben's sub-second suspend/fork. Network i/o timeouts are now in terms of microseconds. db_flush() call is no longer made. * +/* Revision 1.2 1997/03/03 04:19:07 nop +/* GNU Indent normalization +/* * Revision 1.1.1.1 1997/03/03 03:45:02 nop * LambdaMOO 1.8.0p5 * === modified file 'server.c' --- server.c 1998-12-29 06:56:32 +0000 +++ server.c 2002-08-29 03:01:37 +0000 @@ -422,6 +422,7 @@ main_loop(void) { int i; + int res; /* First, notify DB of disconnections for all checkpointed connections */ for (i = 1; i <= checkpointed_connections.v.list[0].v.num; i++) { @@ -443,8 +444,8 @@ * We only care about three cases (== 0, == 1, and > 1), so we can * map a `never' result from the task subsystem into 2. */ - int task_seconds = next_task_start(); - int seconds_left = task_seconds < 0 ? 2 : task_seconds; + int task_useconds = next_task_start(); + int useconds_left = task_useconds < 0 ? 1000000 : task_useconds; shandle *h, *nexth; if (checkpoint_requested != CHKPT_OFF) { @@ -469,10 +470,7 @@ } #endif - if (!network_process_io(seconds_left ? 1 : 0) && seconds_left > 1) - db_flush(FLUSH_ONE_SECOND); - else - db_flush(FLUSH_IF_FULL); + res = network_process_io(useconds_left); run_ready_tasks(); @@ -1735,10 +1733,13 @@ bf_buffered_output_length, TYPE_OBJ); } -char rcsid_server[] = "$Id: server.c,v 1.5 1998/12/29 06:56:32 nop Exp $"; +char rcsid_server[] = "$Id: server.c,v 1.5.4.1 2002/08/29 03:01:37 xythian Exp $"; /* * $Log: server.c,v $ + * Revision 1.5.4.1 2002/08/29 03:01:37 xythian + * Merging Ben's sub-second suspend/fork. Network i/o timeouts are now in terms of microseconds. db_flush() call is no longer made. + * * Revision 1.5 1998/12/29 06:56:32 nop * Fixed leak in onc(). * === modified file 'tasks.c' --- tasks.c 2001-07-31 06:33:22 +0000 +++ tasks.c 2002-08-29 03:00:33 +0000 @@ -43,18 +43,24 @@ #include "verbs.h" #include "version.h" +#include +#include + +#define ROUND(tvp) ((tvp)->tv_sec + ((tvp)->tv_usec > 500000)) + + typedef struct forked_task { int id; Program *program; activation a; Var *rt_env; int f_index; - time_t start_time; + struct timeval start_tv; } forked_task; typedef struct suspended_task { vm the_vm; - time_t start_time; + struct timeval start_tv; Var value; } suspended_task; @@ -136,8 +142,21 @@ #define GET_START_TIME(ttt) \ (ttt->kind == TASK_FORKED \ - ? ttt->t.forked.start_time \ - : ttt->t.suspended.start_time) + ? &ttt->t.forked.start_tv \ + : &ttt->t.suspended.start_tv) + + +static inline struct timeval +double_to_start_tv(double after_seconds) +{ + struct timeval now, delta, when; + + gettimeofday(&now, NULL); + delta.tv_sec = floor(after_seconds); + delta.tv_usec = 1000000. * (after_seconds - delta.tv_sec); + timeradd(&now, &delta, &when); + return when; +} static void @@ -763,21 +782,21 @@ enqueue_waiting(task * t) { /* either FORKED or SUSPENDED */ - time_t start_time = GET_START_TIME(t); + struct timeval *start_tvp = GET_START_TIME(t); Objid progr = (t->kind == TASK_FORKED ? t->t.forked.a.progr : progr_of_cur_verb(t->t.suspended.the_vm)); tqueue *tq = find_tqueue(progr, 1); tq->num_bg_tasks++; - if (!waiting_tasks || start_time < GET_START_TIME(waiting_tasks)) { + if (!waiting_tasks || timercmp(start_tvp, GET_START_TIME(waiting_tasks), <)) { t->next = waiting_tasks; waiting_tasks = t; } else { task *tt; for (tt = waiting_tasks; tt->next; tt = tt->next) - if (start_time < GET_START_TIME(tt->next)) + if (timercmp(start_tvp, GET_START_TIME(tt->next), <)) break; t->next = tt->next; tt->next = t; @@ -786,7 +805,7 @@ static void enqueue_ft(Program * program, activation a, Var * rt_env, - int f_index, time_t start_time, int id) + int f_index, struct timeval start_tv, int id) { task *t = (task *) mymalloc(sizeof(task), M_TASK); @@ -805,7 +824,7 @@ t->t.forked.a = a; t->t.forked.rt_env = rt_env; t->t.forked.f_index = f_index; - t->t.forked.start_time = start_time; + t->t.forked.start_tv = start_tv; t->t.forked.id = id; enqueue_waiting(t); @@ -835,8 +854,9 @@ } enum error -enqueue_forked_task2(activation a, int f_index, unsigned after_seconds, int vid) +enqueue_forked_task2(activation a, int f_index, double after_seconds, int vid) { + struct timeval when; int id; Var *rt_env; @@ -853,7 +873,8 @@ a.rt_env[vid].v.num = id; } rt_env = copy_rt_env(a.rt_env, a.prog->num_var_names); - enqueue_ft(a.prog, a, rt_env, f_index, time(0) + after_seconds, id); + when = double_to_start_tv(after_seconds); + enqueue_ft(a.prog, a, rt_env, f_index, when, id); return E_NONE; } @@ -861,21 +882,23 @@ enum error enqueue_suspended_task(vm the_vm, void *data) { - int after_seconds = *((int *) data); - int now = time(0); - int when; + struct timeval when; task *t; + if (data) { + double after_seconds = *((double *) data); + + when = double_to_start_tv(after_seconds); + } else { + when.tv_sec = INT32_MAX; + when.tv_usec = 0; + } + if (check_user_task_limit(progr_of_cur_verb(the_vm))) { t = mymalloc(sizeof(task), M_TASK); t->kind = TASK_SUSPENDED; t->t.suspended.the_vm = the_vm; - if (now + after_seconds < now) - /* overflow or suspend `forever' code */ - when = INT32_MAX; - else - when = now + after_seconds; - t->t.suspended.start_time = when; + t->t.suspended.start_tv = when; t->t.suspended.value = zero; enqueue_waiting(t); @@ -893,7 +916,8 @@ t->kind = TASK_SUSPENDED; t->t.suspended.the_vm = the_vm; - t->t.suspended.start_time = 0; /* ready now */ + t->t.suspended.start_tv.tv_sec = 0; /* ready now */ + t->t.suspended.start_tv.tv_usec = 0; t->t.suspended.value = value; enqueue_bg_task(tq, t); @@ -957,22 +981,29 @@ return 0; if (waiting_tasks != 0) { - int wait = (waiting_tasks->kind == TASK_FORKED - ? waiting_tasks->t.forked.start_time - : waiting_tasks->t.suspended.start_time) - time(0); - return (wait >= 0) ? wait : 0; + struct timeval *tvp, now, delta; + + gettimeofday(&now, NULL); + tvp = GET_START_TIME(waiting_tasks); + timersub(tvp, &now, &delta); + if (delta.tv_sec < 0 || delta.tv_usec < 0) + return 0; + if (delta.tv_sec > 9) + delta.tv_sec = 9; + return delta.tv_usec + delta.tv_sec * 1000000; } - return -1; + return -1; /* never */ } void run_ready_tasks(void) { task *t, *next_t; - time_t now = time(0); + struct timeval now; tqueue *tq, *next_tq; - for (t = waiting_tasks; t && GET_START_TIME(t) <= now; t = next_t) { + gettimeofday(&now, NULL); + for (t = waiting_tasks; t && timercmp(GET_START_TIME(t), &now, <=); t = next_t) { Objid progr = (t->kind == TASK_FORKED ? t->t.forked.a.progr : progr_of_cur_verb(t->t.suspended.the_vm)); @@ -1144,7 +1175,8 @@ { int lineno = find_line_number(ft.program, ft.f_index, 0); - dbio_printf("0 %d %d %d\n", lineno, ft.start_time, ft.id); + /* saving rounds to the nearest second. restart is slow anyway */ + dbio_printf("0 %d %d %d\n", lineno, ROUND(&ft.start_tv), ft.id); write_activ_as_pi(ft.a); write_rt_env(ft.program->var_names, ft.rt_env, ft.program->num_var_names); dbio_write_forked_program(ft.program, ft.f_index); @@ -1153,7 +1185,8 @@ static void write_suspended_task(suspended_task st) { - dbio_printf("%d %d ", st.start_time, st.the_vm->task_id); + /* saving rounds down to the nearest second. restart is slow anyway */ + dbio_printf("%d %d ", ROUND(&st.start_tv), st.the_vm->task_id); dbio_write_var(st.value); write_vm(st.the_vm); } @@ -1233,7 +1266,7 @@ for (; count > 0; count--) { int first_lineno, id, old_size, st; char c; - time_t start_time; + struct timeval start_tv; Program *program; Var *rt_env, *old_rt_env; const char **old_names; @@ -1245,7 +1278,8 @@ errlog("READ_TASK_QUEUE: Bad numbers, count = %d.\n", count); return 0; } - start_time = st; + start_tv.tv_sec = st; + start_tv.tv_usec = 0; if (!read_activ_as_pi(&a)) { errlog("READ_TASK_QUEUE: Bad activation, count = %d.\n", count); return 0; @@ -1262,7 +1296,7 @@ rt_env = reorder_rt_env(old_rt_env, old_names, old_size, program); program->first_lineno = first_lineno; - enqueue_ft(program, a, rt_env, MAIN_VECTOR, start_time, id); + enqueue_ft(program, a, rt_env, MAIN_VECTOR, start_tv, id); } suspended_task_header = dbio_scanf("%d suspended tasks\n", @@ -1276,16 +1310,17 @@ } for (; suspended_count > 0; suspended_count--) { task *t = (task *) mymalloc(sizeof(task), M_TASK); - int task_id, start_time; + int task_id, st; char c; t->kind = TASK_SUSPENDED; - if (dbio_scanf("%d %d%c", &start_time, &task_id, &c) != 3) { + if (dbio_scanf("%d %d%c", &st, &task_id, &c) != 3) { errlog("READ_TASK_QUEUE: Bad suspended task header, count = %d\n", suspended_count); return 0; } - t->t.suspended.start_time = start_time; + t->t.suspended.start_tv.tv_sec = st; + t->t.suspended.start_tv.tv_usec = 0; if (c == ' ') t->t.suspended.value = dbio_read_var(); else if (c == '\n') @@ -1468,7 +1503,7 @@ list.v.list[1].type = TYPE_INT; list.v.list[1].v.num = ft.id; list.v.list[2].type = TYPE_INT; - list.v.list[2].v.num = ft.start_time; + list.v.list[2].v.num = ROUND(&ft.start_tv); list.v.list[3].type = TYPE_INT; list.v.list[3].v.num = 0; /* OBSOLETE: was clock ID */ list.v.list[4].type = TYPE_INT; @@ -1538,7 +1573,7 @@ list = list_for_vm(st.the_vm); list.v.list[2].type = TYPE_INT; - list.v.list[2].v.num = st.start_time; + list.v.list[2].v.num = ROUND(&st.start_tv); return list; } @@ -1876,7 +1911,7 @@ if (!is_wizard(progr) && progr != owner) return E_PERM; - t->t.suspended.start_time = time(0); /* runnable now */ + gettimeofday(&t->t.suspended.start_tv, NULL); /* runnable now */ free_var(t->t.suspended.value); t->t.suspended.value = value; tq = find_tqueue(owner, 1); @@ -2009,10 +2044,16 @@ register_function("flush_input", 1, 2, bf_flush_input, TYPE_OBJ, TYPE_ANY); } -char rcsid_tasks[] = "$Id: tasks.c,v 1.9 2001/07/31 06:33:22 bjj Exp $"; +char rcsid_tasks[] = "$Id: tasks.c,v 1.9.4.1 2002/08/29 03:00:33 xythian Exp $"; /* * $Log: tasks.c,v $ + * Revision 1.9.4.1 2002/08/29 03:00:33 xythian + * Merging Ben's sub-second suspend and fork. + * + * enqueue_* now take float number of seconds. Task structs now contain + * timevals. + * * Revision 1.9 2001/07/31 06:33:22 bjj * Fixed some bugs in the reporting of forked task sizes. *