cvsuser 03/07/16 23:53:15
Modified: . MANIFEST
classes timer.pmc
config/auto signal.pl
config/auto/signal test_1.in test_2.in
config/gen/feature_h feature_h.in
config/gen parrot_include.pl
config/gen/platform generic.c platform_interface.h
Added: t/pmc timer.t
Log:
timer class functions
Revision Changes Path
1.380 +1 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.379
retrieving revision 1.380
diff -u -w -r1.379 -r1.380
--- MANIFEST 16 Jul 2003 15:00:12 -0000 1.379
+++ MANIFEST 17 Jul 2003 06:53:06 -0000 1.380
@@ -1870,6 +1870,7 @@
t/pmc/sarray.t []
t/pmc/scratchpad.t []
t/pmc/sub.t []
+t/pmc/timer.t []
t/src/basic.t []
t/src/exit.t []
t/src/intlist.t []
1.2 +343 -3 parrot/classes/timer.pmc
Index: timer.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/timer.pmc,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- timer.pmc 15 Jul 2003 12:32:27 -0000 1.1
+++ timer.pmc 17 Jul 2003 06:53:07 -0000 1.2
@@ -1,7 +1,7 @@
/* timer.pmc
* Copyright: 2002-2003 Yet Another Society
* CVS Info
- * $Id: timer.pmc,v 1.1 2003/07/15 12:32:27 leo Exp $
+ * $Id: timer.pmc,v 1.2 2003/07/17 06:53:07 leo Exp $
* Overview:
* This is the Timer base class
* Data Structure and Algorithms:
@@ -11,6 +11,7 @@
* invoked via Parrots event handling code.
* History:
* Initial proposal by leo 2003.07.15
+ * Initial revision 2003.07.17
* Synopsis:
* new P0, .Timer
* set P0[.TIMER_SEC], I_seconds # whole seconds
@@ -22,6 +23,8 @@
* invoke P0 # start timer
* set P0[.TIMER_RUNNING], 1 # same
*
+ * new P0, .Timer, P1 # set everything
+ *
* set I0, P0[.TIMER_SEC] # query current timer status
* set N0, P0[.TIMER_NSEC]
* ...
@@ -33,8 +36,13 @@
* programmed interval.
* The Timer stops after (repeat+1) times invoking the handler.
* If a Timer should run forever, set "repeat" to -1.
- * Turning the Timer off sets all values to zero, the Timer is
- * not destroyed, it can be reprogrammed and started again.
+ * Turning the Timer off preserves set values, the Timer is
+ * not destroyed.
+ * When setting both TIMER_SEC and TIMER_USEC it must be done in
+ * that sequence, whole seconds first.
+ * If a timer is constructed with an initializer and it should
+ * be run immediately, the TIMER_RUNNING value has to be in the
+ * last key of the initializer.
*
* References:
*/
@@ -42,9 +50,341 @@
#include "parrot/parrot.h"
#include "parrot/method_util.h"
+/*
+ * for now we keep all stuff inside the pmc
+ */
+
+/* interface constants */
+/* &gen_from_enum(timer.pasm) */
+typedef enum {
+ TIMER_SEC,
+ TIMER_USEC,
+ TIMER_NSEC,
+ TIMER_REPEAT,
+ TIMER_RUNNING,
+ TIMER_HANDLER,
+ TIMER_MAX
+} parrot_timer_enum_t;
+/* &end_gen */
+
+/* internal run state */
+typedef enum {
+ TIMER_STATE_STOPPED,
+ TIMER_STATE_NEW,
+ TIMER_STATE_RUNNING,
+ TIMER_STATE_FIRE
+} parrot_timer_state_t;
+
+typedef struct timer_t {
+ int flags;
+ int ticks;
+ int value;
+ int repeat;
+ int state;
+ union {
+ INTVAL pasm_code;
+ void *c_code;
+ } handler;
+ PMC *self;
+ struct timer_t *next;
+ struct timer_t *prev;
+} timer_t;
+
+/* XXX next 2 should probably go into interpreter */
+/* linked list of running timers */
+static timer_t *rtimer = 0;
+/* handle of system timer */
+static void *handle = (void *) -1;
+
+/* add timer to running */
+static void
+add_timer(timer_t *t)
+{
+ timer_t *next = rtimer;
+ rtimer = t;
+ t->next = next;
+ if (next) {
+ next->prev = t;
+ }
+ t->state = TIMER_STATE_RUNNING;
+ PObj_needs_early_DOD_SET(t->self);
+}
+
+static int
+timer_is_running(timer_t *tp)
+{
+ timer_t *t;
+ /* be paranoid, check run lis too */
+ for (t = rtimer; t; t = t->next)
+ if (t == tp)
+ return 1;
+ return 0;
+}
+
+/* del timer from running */
+static void
+del_timer(timer_t *t)
+{
+ timer_t *next = t->next;
+ timer_t *prev = t->prev;
+
+ if (!timer_is_running(t))
+ return;
+ if (prev)
+ prev->next = next;
+ else
+ rtimer = next;
+ if (next)
+ next->prev = prev;
+ t->ticks = 0;
+ t->state = TIMER_STATE_STOPPED;
+ PObj_needs_early_DOD_CLEAR(t->self);
+}
+
+/* TODO move this to misc.c (or util.c?), s. also math.ops */
+static UINTVAL
+gcd(UINTVAL a, UINTVAL b)
+{
+
+ UINTVAL q = 0;
+ UINTVAL c = 0;
+ while (b != 0) {
+ q = (UINTVAL)floor( (FLOATVAL)a/b );
+ c = a - b*q;
+ a = b;
+ b = c;
+ }
+ return a;
+}
+
+static void
+recalc_ticks(void)
+{
+ UINTVAL ms, oms;
+ timer_t *t;
+
+ oms = get_sys_timer_ms(handle);
+ t = rtimer;
+ if (t) {
+ if (t->state == TIMER_STATE_NEW)
+ t->state = TIMER_STATE_STOPPED;
+ if (oms && t->ticks)
+ ms = oms*t->ticks; /* time left */
+ else
+ ms = t->value;
+ if (t->next) {
+ for (t = t->next; t; t = t->next) {
+ if (t->state == TIMER_STATE_NEW)
+ t->state = TIMER_STATE_STOPPED;
+ if (oms && t->ticks) {
+ ms = gcd(oms*t->ticks, ms);
+ }
+ else
+ ms = gcd(t->value, ms);
+ }
+ }
+ for (t = rtimer; t; t = t->next) {
+ int ot = t->ticks;
+ if (oms && ot)
+ t->ticks = t->ticks * ((double)oms / (double)ms);
+ else
+ t->ticks = t->value / ms;
+ if (!t->ticks) {
+ internal_exception(1, "Timer ticks are zero\n");
+ }
+ }
+ }
+ else
+ ms = 0;
+
+ if (ms)
+ start_sys_timer_ms(handle, ms);
+ else
+ stop_sys_timer_ms(handle);
+}
+
+static void
+do_alarm_handler(void)
+{
+ timer_t *t;
+ UINTVAL ms;
+ int recalc = 0;
+
+ ms = get_sys_timer_ms(handle);
+ for (t = rtimer; t; t = t->next) {
+ if (!--t->ticks) {
+ t->state = TIMER_STATE_FIRE;
+ if (t->repeat) {
+ t->ticks = t->value/ms;
+ if (t->repeat != -1)
+ t->repeat--;
+ }
+ }
+ }
+ /* do this in a separate loop, and always start over:
+ * the timer handler function might add/stop timers
+ */
+again:
+ for (t = rtimer; t; t= t->next) {
+ if (t->state == TIMER_STATE_FIRE) {
+ t->state = TIMER_STATE_RUNNING;
+ /* TODO setup event */
+ goto again;
+ }
+ if (!t->ticks && !t->repeat) {
+ del_timer(t);
+ recalc = 1;
+ goto again;
+ }
+ }
+ if (recalc)
+ recalc_ticks();
+}
+
pmclass Timer {
+ void class_init() {
+ if (handle == (void *) -1)
+ handle = new_sys_timer_ms();
+ }
+
+ void init() {
+ timer_t *t = mem_sys_allocate_zeroed(sizeof(timer_t));
+ t->state = TIMER_STATE_NEW;
+ t->self = SELF;
+ SELF->cache.struct_val = t;
+ PObj_active_destroy_SET(SELF);
+ interpreter->has_early_DOD_PMCs = 1;
+ }
+
+ void init_pmc(PMC *init) {
+ /*
+ * s. pdd02_vtables for intializers
+ */
+ INTVAL n = VTABLE_get_integer(interpreter, init);
+ INTVAL i;
+ INTVAL val;
+ FLOATVAL nval;
+
+ SELF.init();
+ for (i = 0; i < n; i += 2) {
+ INTVAL key = VTABLE_get_integer_keyed_int(interpreter, init, i);
+ switch (key) {
+ case TIMER_SEC:
+ case TIMER_USEC:
+ case TIMER_REPEAT:
+ case TIMER_RUNNING:
+ case TIMER_HANDLER:
+ val =
+ VTABLE_get_integer_keyed_int(interpreter, init, i+1);
+ SELF.set_integer_keyed_int(key, val);
+ break;
+ case TIMER_NSEC:
+ nval =
+ VTABLE_get_number_keyed_int(interpreter, init, i+1);
+ SELF.set_number_keyed_int(key, nval);
+ break;
+ }
+ }
+ }
+
+ void destroy() {
+ timer_t *t = SELF->cache.struct_val;
+ del_timer(t);
+ mem_sys_free(t);
+ }
STRING* name() {
return whoami;
+ }
+
+ INTVAL get_integer_keyed_int(INTVAL key) {
+ timer_t *t = SELF->cache.struct_val;
+
+ switch(key) {
+ case TIMER_SEC:
+ return t->value/1000;
+ break;
+ case TIMER_USEC:
+ return (t->value % 1000) * 1000;
+ break;
+ case TIMER_REPEAT:
+ return t->repeat;
+ break;
+ case TIMER_RUNNING:
+ return timer_is_running(t);
+ break;
+ case TIMER_HANDLER:
+ return t->handler.pasm_code;
+ break;
+ }
+ return -1;
+ }
+
+ FLOATVAL get_number_keyed_int(INTVAL key) {
+ timer_t *t = SELF->cache.struct_val;
+
+ switch(key) {
+ case TIMER_NSEC:
+ return (FLOATVAL)t->value/1000.0;
+ break;
+ }
+ return -1.0;
+ }
+
+ void set_integer_native(INTVAL value) {
+ timer_t *t = SELF->cache.struct_val;
+ t->handler.pasm_code = value;
+ }
+
+ void set_integer_keyed_int(INTVAL key, INTVAL value) {
+ timer_t *t = SELF->cache.struct_val;
+
+ switch(key) {
+ case TIMER_SEC:
+ t->value = value * 1000;
+ break;
+ case TIMER_USEC:
+ t->value += value / 1000;
+ break;
+ case TIMER_REPEAT:
+ t->repeat = value;
+ break;
+ case TIMER_RUNNING:
+ if (value) {
+ if (!timer_is_running(t)) {
+ add_timer(t);
+ recalc_ticks();
+ }
+ }
+ else {
+ if (timer_is_running(t)) {
+ del_timer(t);
+ recalc_ticks();
+ }
+ }
+ break;
+ case TIMER_HANDLER:
+ t->handler.pasm_code = value;
+ break;
+ }
+ }
+
+ void* invoke(void *next) {
+ timer_t *t = SELF->cache.struct_val;
+ if (!timer_is_running(t)) {
+ add_timer(t);
+ recalc_ticks();
+ }
+ return next;
+ }
+
+ void set_number_keyed_int(INTVAL key, FLOATVAL value) {
+ timer_t *t = SELF->cache.struct_val;
+
+ switch(key) {
+ case TIMER_NSEC:
+ t->value = (INTVAL) (value * 1000.0);
+ break;
+ }
}
}
1.5 +4 -10 parrot/config/auto/signal.pl
Index: signal.pl
===================================================================
RCS file: /cvs/public/parrot/config/auto/signal.pl,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -w -r1.4 -r1.5
--- signal.pl 14 Jul 2003 08:38:23 -0000 1.4
+++ signal.pl 17 Jul 2003 06:53:09 -0000 1.5
@@ -13,6 +13,7 @@
my ($miniparrot) = @_;
Configure::Data->set(
has___sighandler_t => undef,
+ has_sigatomic_t => undef,
has_sigaction => undef,
has_setitimer => undef
);
@@ -20,13 +21,6 @@
return;
}
- if (Configure::Data->get('i_malloc')) {
- Configure::Data->set('malloc_header', 'malloc.h');
- }
- else {
- Configure::Data->set('malloc_header', 'stdlib.h');
- }
-
cc_gen('config/auto/signal/test_1.in');
eval { cc_build(); };
unless ($@ || cc_run() !~ /ok/) {
@@ -47,17 +41,17 @@
}
cc_clean();
- Configure::Data->set('malloc_header', undef);
-
cc_gen('config/auto/signal/test_itimer.in');
eval { cc_build(); };
unless ($@ || cc_run() !~ /ok/) {
Configure::Data->set(
- has_setitimer => 'define'
+ has_setitimer => 'define',
+ has_sig_atomic_t => 'define'
);
print " (setitimer) ";
}
cc_clean();
+
# now generate signal constants
open O, ">runtime/parrot/include/signal.pasm" or die
"Cant write runtime/parrot/include/signal.pasm";
1.4 +1 -1 parrot/config/auto/signal/test_1.in
Index: test_1.in
===================================================================
RCS file: /cvs/public/parrot/config/auto/signal/test_1.in,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -w -r1.3 -r1.4
--- test_1.in 13 Jul 2003 18:52:38 -0000 1.3
+++ test_1.in 17 Jul 2003 06:53:10 -0000 1.4
@@ -4,7 +4,7 @@
* This file is automatically generated by Configure
* from test_1.in.
*/
-#include <${malloc_header}>
+
#include <stdio.h>
#include <signal.h>
1.3 +1 -1 parrot/config/auto/signal/test_2.in
Index: test_2.in
===================================================================
RCS file: /cvs/public/parrot/config/auto/signal/test_2.in,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- test_2.in 13 Jul 2003 18:52:39 -0000 1.2
+++ test_2.in 17 Jul 2003 06:53:10 -0000 1.3
@@ -4,7 +4,7 @@
* This file is automatically generated by Configure
* from test_2.in.
*/
-#include <${malloc_header}>
+
#include <stdio.h>
#include <signal.h>
1.11 +1 -0 parrot/config/gen/feature_h/feature_h.in
Index: feature_h.in
===================================================================
RCS file: /cvs/public/parrot/config/gen/feature_h/feature_h.in,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -w -r1.10 -r1.11
--- feature_h.in 14 Jul 2003 08:38:24 -0000 1.10
+++ feature_h.in 17 Jul 2003 06:53:11 -0000 1.11
@@ -74,6 +74,7 @@
if (${has_setitimer}) {
print OUT <<'END';
#define HAS_SETITIMER 1
+#define HAS_SOME_SYS_TIMER 1
END
}
1.2 +1 -0 parrot/config/gen/parrot_include.pl
Index: parrot_include.pl
===================================================================
RCS file: /cvs/public/parrot/config/gen/parrot_include.pl,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- parrot_include.pl 3 Jul 2003 10:03:37 -0000 1.1
+++ parrot_include.pl 17 Jul 2003 06:53:12 -0000 1.2
@@ -18,6 +18,7 @@
include/parrot/resources.h
include/parrot/string.h
include/parrot/warnings.h
+ classes/timer.pmc
);
my $destdir = 'runtime/parrot/include';
1.17 +60 -2 parrot/config/gen/platform/generic.c
Index: generic.c
===================================================================
RCS file: /cvs/public/parrot/config/gen/platform/generic.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -w -r1.16 -r1.17
--- generic.c 14 Jul 2003 07:58:20 -0000 1.16
+++ generic.c 17 Jul 2003 06:53:14 -0000 1.17
@@ -220,6 +220,64 @@
}
#endif
+/*
+ * itimer stuff
+ */
+
+#ifdef HAS_SETITIMER
+
+/*
+ * Start a system timer with the passed value in milli seconds.
+ *
+ * The handle is that, what new_sys_timer_ms() returned.
+ * We could pass ITIMER_REAL in handle, but for now we ignore it
+ * as we are just having one timer.
+ */
+
+void
+start_sys_timer_ms(void *handle, int ms)
+{
+ struct itimerval its;
+ memset(&its, 0, sizeof(its));
+ if (ms) {
+ its.it_interval.tv_sec = its.it_value.tv_sec = ms/1000;
+ its.it_interval.tv_usec = its.it_value.tv_usec = 1000 *(ms%1000);
+ }
+ setitimer(ITIMER_REAL, &its, NULL);
+}
+
+/* Stop the given timer. */
+void
+stop_sys_timer_ms(void *handle)
+{
+ start_sys_timer_ms(handle, 0);
+}
+
+/*
+ * Return the programmed timer interval or 0 if none for the
+ * given timer handle.
+ */
+
+int
+get_sys_timer_ms(void *handle)
+{
+ struct itimerval ots;
+ getitimer(ITIMER_REAL, &ots);
+ return ots.it_interval.tv_sec * 1000 + ots.it_interval.tv_usec/1000;
+}
+
+/*
+ * Create a new system timer with ~ms resolution.
+ * The returned handle is passed to the other timer functions.
+ */
+void *
+new_sys_timer_ms()
+{
+ return 0;
+}
+
+#else
+#endif
/*
* Local variables:
* c-indentation-style: bsd
1.5 +18 -0 parrot/config/gen/platform/platform_interface.h
Index: platform_interface.h
===================================================================
RCS file: /cvs/public/parrot/config/gen/platform/platform_interface.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -w -r1.4 -r1.5
--- platform_interface.h 11 Jul 2003 17:49:46 -0000 1.4
+++ platform_interface.h 17 Jul 2003 06:53:14 -0000 1.5
@@ -49,6 +49,24 @@
#endif
/*
+ * system timer
+ */
+
+#ifdef HAS_SOME_SYS_TIMER
+
+void * new_sys_timer_ms(void);
+void start_sys_timer_ms(void *handle, int ms);
+void stop_sys_timer_ms(void *handle);
+int get_sys_timer_ms(void *handle);
+#else
+#define new_sys_timer NULL
+#define start_sys_timer(h, m)
+#define stop_sys_timer(h)
+#define get_sys_timer(h) 0
+#endif
+
+
+/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
1.1 parrot/t/pmc/timer.t
Index: timer.t
===================================================================
#! perl -w
use Parrot::Test tests => 3;
use Test::More;
output_is(<<'CODE', <<'OUT', "Timer setup");
.include "timer.pasm"
new P0, .Timer
set P0[.TIMER_SEC], 7
set I0, P0[.TIMER_SEC]
eq I0, 7, ok1
print "not "
ok1:
print "ok 1\n"
set I0, P0[.TIMER_USEC]
eq I0, 0, ok2
print "not "
ok2:
print "ok 2\n"
set I0, P0[.TIMER_RUNNING]
eq I0, 0, ok3
print "not "
ok3:
print "ok 3\n"
end
CODE
ok 1
ok 2
ok 3
OUT
output_is(<<'CODE', <<'OUT', "Timer setup - initializer");
.include "timer.pasm"
new P1, .SArray
set P1, 4
set P1[0], .TIMER_SEC
set P1[1], 8
set P1[2], .TIMER_USEC
set P1[3], 400000
new P0, .Timer, P1
set I0, P0[.TIMER_SEC]
eq I0, 8, ok1
print "not "
ok1:
print "ok 1\n"
set I0, P0[.TIMER_USEC]
eq I0, 400000, ok2
print "not "
ok2:
print "ok 2\n"
set I0, P0[.TIMER_RUNNING]
eq I0, 0, ok3
print "not "
ok3:
print "ok 3\n"
end
CODE
ok 1
ok 2
ok 3
OUT
output_is(<<'CODE', <<'OUT', "Timer setup - initializer/start");
.include "timer.pasm"
new P1, .SArray
set P1, 6
set P1[0], .TIMER_SEC
set P1[1], 8
set P1[2], .TIMER_USEC
set P1[3], 400000
set P1[4], .TIMER_RUNNING
set P1[5], 1
new P0, .Timer, P1
set I0, P0[.TIMER_SEC]
eq I0, 8, ok1
print "not "
ok1:
print "ok 1\n"
set I0, P0[.TIMER_USEC]
eq I0, 400000, ok2
print "not "
ok2:
print "ok 2\n"
set I0, P0[.TIMER_RUNNING]
eq I0, 1, ok3
print "not "
ok3:
print "ok 3\n"
end
CODE
ok 1
ok 2
ok 3
OUT