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
  
  
  

Reply via email to