# This is a patch for Event-0.58 to update it to Event-0.59
# 
# To apply this patch:
# STEP 1: Chdir to the source directory.
# STEP 2: Run the 'applypatch' program with this patch file as input.
#
# If you do not have 'applypatch', it is part of the 'makepatch' package
# that you can fetch from the Comprehensive Perl Archive Network:
# http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz
# In the above URL, 'x' should be 2 or higher.
#
# To apply this patch without the use of 'applypatch':
# STEP 1: Chdir to the source directory.
# If you have a decent Bourne-type shell:
# STEP 2: Run the shell with this file as input.
# If you don't have such a shell, you may need to manually create
# the files as shown below.
# STEP 3: Run the 'patch' program with this file as input.
#
# These are the commands needed to create/delete files/directories:
#
touch 'demo/variable_repeater.t'
chmod 0444 'demo/variable_repeater.t'
touch 't/leak2.t'
chmod 0444 't/leak2.t'
#
# This command terminates the shell and need not be executed manually.
exit
#
#### End of Preamble ####

#### Patch data follows ####
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/ChangeLog' 
'/usr/tmp/mp4882.d/new/Event-0.59/ChangeLog'
Index: ./ChangeLog
--- ./ChangeLog Mon Nov 22 17:04:29 1999
+++ ./ChangeLog Thu Jan 20 10:30:41 2000
@@ -1,3 +1,19 @@
+2000-01-20  Joshua Pritikin  <[EMAIL PROTECTED]>
+
+       * Release 0.59.
+
+       * Fixed serious memory leak (isolated by
+       [EMAIL PROTECTED]). Added t/leak2.t.
+
+2000-01-19  Joshua Pritikin  <[EMAIL PROTECTED]>
+
+       * Doc for timeout_cb (demanded by [EMAIL PROTECTED] :-).
+
+1999-12-15  Joshua Pritikin  <[EMAIL PROTECTED]>
+
+       * Added demo/variable_timer.t along with minor doc
+       update. ([EMAIL PROTECTED])
+
 1999-11-22  Joshua Pritikin  <[EMAIL PROTECTED]>
 
        * Release 0.58.
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/Event.xs' 
'/usr/tmp/mp4882.d/new/Event-0.59/Event.xs'
Index: ./Event.xs
--- ./Event.xs  Mon Nov 22 16:35:49 1999
+++ ./Event.xs  Wed Jan 19 11:45:47 2000
@@ -94,10 +94,12 @@ static void dbg_count_memory(int id, int
     MemoryCount[id] += cnt;
 }
 
-#if DEBUGGING
+#if EVENT_MEMORY_DEBUG
 #  define EvNew(id, ptr, size, type) dbg_count_memory(id,1); New(0,ptr,size,type)
+#  define EvFree(id, ptr) STMT_START { dbg_count_memory(id,-1); safefree(ptr); } 
+STMT_END
 #else
 #  define EvNew(x, ptr, size, type) New(0,ptr,size,type)
+#  define EvFree(id, ptr) safefree(ptr)
 #endif
 
 static int ActiveWatchers=0; /* includes WaACTIVE + queued events */
@@ -309,7 +311,7 @@ void
 _memory_counters()
      PPCODE:
 {
-#ifdef DEBUGGING
+#ifdef EVENT_MEMORY_DEBUG
     int xx;
     for (xx=0; xx < MAX_MEMORYCOUNT; xx++)
        XPUSHs(sv_2mortal(newSViv(MemoryCount[xx])));
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/MANIFEST' 
'/usr/tmp/mp4882.d/new/Event-0.59/MANIFEST'
Index: ./MANIFEST
--- ./MANIFEST  Mon Nov 22 17:12:49 1999
+++ ./MANIFEST  Thu Jan 20 09:32:27 2000
@@ -26,6 +26,7 @@ demo/inactivity.t
 demo/process.pm
 demo/readline.t
 demo/spin_io.t
+demo/variable_repeater.t
 lib/Event.pm
 lib/Event.pod
 lib/Event/EventAPI.h
@@ -51,6 +52,7 @@ t/idle.t
 t/idle2.t
 t/io.t
 t/leak.t
+t/leak2.t
 t/loop.t
 t/now.t
 t/reenter.t
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/TODO' 
'/usr/tmp/mp4882.d/new/Event-0.59/TODO'
Index: ./TODO
--- ./TODO      Mon Nov 22 17:07:03 1999
+++ ./TODO      Thu Jan 20 10:05:56 2000
@@ -14,6 +14,14 @@ optimization
     queue events from both sides?
   try to hoist system calls from the inner loop
 
[EMAIL PROTECTED] signal discussion:
+  The API rsignal overrides the current signal handler.  If the signal
+  watcher is cancelled (or otherwise disabled) then rsignal is reset to
+  SIG_DFL.  You bring up a good point here.  Maybe the original handler
+  should be restored.  On the other hand, assignment to %SIG will mess
+  up Event watchers so maybe Event should refuse to watch a signal if a
+  handler is already installed.
+
 loop
   StarvePrio?
 
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/hook.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/hook.c'
Index: ./c/hook.c
--- ./c/hook.c  Mon Nov 22 13:41:05 1999
+++ ./c/hook.c  Wed Jan 19 10:40:07 2000
@@ -44,7 +44,7 @@ static void pe_cancel_hook(pe_qcallback 
   if (qcb->is_perl)
     SvREFCNT_dec((SV*)qcb->callback);
   PE_RING_DETACH(&qcb->ring);
-  safefree(qcb);
+  EvFree(2, qcb);
 }
 
 static void pe_map_check(pe_ring *List)
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/idle.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/idle.c'
Index: ./c/idle.c
--- ./c/idle.c  Mon Nov 22 13:41:05 1999
+++ ./c/idle.c  Wed Jan 19 10:46:57 2000
@@ -21,6 +21,7 @@ static void pe_idle_dtor(pe_watcher *ev)
     SvREFCNT_dec(ip->max_interval);
     SvREFCNT_dec(ip->min_interval);
     pe_watcher_dtor(ev);
+    EvFree(3, ev);
 }
 
 static void pe_idle_start(pe_watcher *ev, int repeating) {
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/io.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/io.c'
Index: ./c/io.c
--- ./c/io.c    Mon Nov 22 16:51:30 1999
+++ ./c/io.c    Wed Jan 19 10:47:21 2000
@@ -29,6 +29,7 @@ static void pe_io_dtor(pe_watcher *_ev) 
     PE_RING_DETACH(&ev->ioring);
     SvREFCNT_dec(ev->handle);
     pe_watcher_dtor(_ev);
+    EvFree(4, _ev);
 }
 
 static void pe_io_start(pe_watcher *_ev, int repeat) {
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/queue.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/queue.c'
Index: ./c/queue.c
--- ./c/queue.c Mon Nov 22 15:50:39 1999
+++ ./c/queue.c Wed Jan 19 16:54:06 2000
@@ -149,6 +149,9 @@ static void pe_queue_pending() {
 }
 
 static int one_event(double tm) {  /**INVOKE**/
+    /*if (SvIVX(DebugLevel) >= 4)
+      warn("Event: ActiveWatchers=%d\n", ActiveWatchers);*/
+
     pe_signal_asynccheck();
     if (!PE_RING_EMPTY(&AsyncCheck)) pe_map_check(&AsyncCheck);
 
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/signal.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/signal.c'
Index: ./c/signal.c
--- ./c/signal.c        Mon Nov 22 13:41:06 1999
+++ ./c/signal.c        Wed Jan 19 10:48:05 2000
@@ -41,6 +41,11 @@ static pe_watcher *pe_signal_allocate(HV
     return (pe_watcher*) ev;
 }
 
+static void pe_signal_dtor(pe_watcher *ev) {
+    pe_watcher_dtor(ev);
+    EvFree(5, ev);
+}
+
 static void pe_signal_start(pe_watcher *_ev, int repeat) {
     pe_signal *ev = (pe_signal*) _ev;
     int sig = ev->signal;
@@ -138,6 +143,7 @@ static void boot_signal() {
        ++sigp;
     }
     memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
+    vt->dtor = pe_signal_dtor;
     vt->start = pe_signal_start;
     vt->stop = pe_signal_stop;
     pe_register_vtbl(vt, gv_stashpv("Event::signal",1), &event_vtbl);
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/tied.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/tied.c'
Index: ./c/tied.c
--- ./c/tied.c  Mon Nov 22 13:41:06 1999
+++ ./c/tied.c  Wed Jan 19 10:46:25 2000
@@ -10,6 +10,11 @@ static pe_watcher *pe_tied_allocate(HV *
     return (pe_watcher*) ev;
 }
 
+static void pe_tied_dtor(pe_watcher *ev) {
+    pe_watcher_dtor(ev);
+    EvFree(6, ev);
+}
+
 static void pe_tied_start(pe_watcher *ev, int repeat) {
     HV *stash = SvSTASH(SvRV(ev->mysv));
     GV *gv;
@@ -92,6 +97,7 @@ static void boot_tied() {
     pe_watcher_vtbl *vt = &pe_tied_vtbl;
     memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
     vt->did_require = 1; /* otherwise tries to autoload Event::Event! */
+    vt->dtor = pe_tied_dtor;
     vt->start = pe_tied_start;
     vt->stop = pe_tied_stop;
     vt->alarm = pe_tied_alarm;
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/timer.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/timer.c'
Index: ./c/timer.c
--- ./c/timer.c Mon Nov 22 13:44:02 1999
+++ ./c/timer.c Wed Jan 19 10:48:25 2000
@@ -16,6 +16,7 @@ static void pe_timer_dtor(pe_watcher *ev
     pe_timer *tm = (pe_timer*) ev;
     SvREFCNT_dec(tm->interval);
     pe_watcher_dtor(ev);
+    EvFree(7, ev);
 }
 
 static void pe_timer_start(pe_watcher *ev, int repeat) {
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/typemap.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/typemap.c'
Index: ./c/typemap.c
--- ./c/typemap.c       Mon Nov 22 13:41:07 1999
+++ ./c/typemap.c       Wed Jan 19 11:01:14 2000
@@ -22,7 +22,7 @@ static SV *wrap_watcher(void *ptr, HV *s
     while ((mg = *mgp))
        mgp = &mg->mg_moremagic;
 
-    EvNew(8, mg, 1, MAGIC);
+    New(0, mg, 1, MAGIC);
     Zero(mg, 1, MAGIC);
     mg->mg_type = '~';
     mg->mg_obj = (SV*) ptr;  /* NOT refcnt'd */
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/unix_io.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/unix_io.c'
Index: ./c/unix_io.c
--- ./c/unix_io.c       Mon Nov 22 13:41:07 1999
+++ ./c/unix_io.c       Wed Jan 19 10:40:29 2000
@@ -75,7 +75,7 @@ static void pe_sys_multiplex(double time
     int ret;
     if (pollMax < IOWatchCount) {
        if (Pollfd)
-           safefree(Pollfd);
+           EvFree(9, Pollfd);
        pollMax = IOWatchCount+5;
        EvNew(9, Pollfd, pollMax, struct pollfd);
        IOWatch_OK = 0;
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/var.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/var.c'
Index: ./c/var.c
--- ./c/var.c   Mon Nov 22 13:41:07 1999
+++ ./c/var.c   Wed Jan 19 11:01:30 2000
@@ -16,6 +16,7 @@ static void pe_var_dtor(pe_watcher *ev) 
     pe_var *wv = (pe_var *)ev;
     SvREFCNT_dec(wv->variable);
     pe_watcher_dtor(ev);
+    EvFree(10, ev);
 }
 
 static void pe_tracevar(pe_watcher *wa, SV *sv, int got) {
@@ -81,7 +82,7 @@ static void pe_var_start(pe_watcher *_ev
     mg->mg_virtual = &PL_vtbl_uvar;
     *mgp = mg;
     
-    EvNew(12, ufp, 1, struct ufuncs);
+    EvNew(8, ufp, 1, struct ufuncs);
     ufp->uf_val = ev->events & PE_R? tracevar_r : 0;
     ufp->uf_set = ev->events & PE_W? tracevar_w : 0;
     ufp->uf_index = (IV) ev;
@@ -119,8 +120,8 @@ static void pe_var_stop(pe_watcher *_ev)
 
     *mgp = mg->mg_moremagic;
 
-    safefree(mg->mg_ptr);
-    safefree(mg);
+    EvFree(8, mg->mg_ptr);
+    EvFree(11, mg);
 }
 
 static void _var_restart(pe_watcher *ev) {
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/c/watcher.c' 
'/usr/tmp/mp4882.d/new/Event-0.59/c/watcher.c'
Index: ./c/watcher.c
--- ./c/watcher.c       Mon Nov 22 15:32:56 1999
+++ ./c/watcher.c       Wed Jan 19 16:51:41 2000
@@ -49,8 +49,8 @@ static void pe_watcher_cancel_events(pe_
     pe_event *ev;
     while (!PE_RING_EMPTY(&wa->events)) {
        pe_ring *lk = wa->events.prev;
-       PE_RING_DETACH(lk);
        ev = (pe_event*) lk->self;
+       dequeEvent(ev);
        pe_event_release(ev);
     }
 }
@@ -74,7 +74,7 @@ static void pe_watcher_dtor(pe_watcher *
        SvREFCNT_dec(wa->desc);
     if (wa->stats)
        Estat.dtor(wa->stats);
-    safefree(wa);
+    /* safefree(wa); do it yourself */
 }
 
 /********************************** *******************************/
@@ -243,7 +243,7 @@ static void boot_pe_watcher() {
     vt = &pe_watcher_base_vtbl;
     vt->stash = 0;
     vt->did_require = 0;
-    vt->dtor = pe_watcher_dtor;
+    vt->dtor = 0;
     vt->start = pe_watcher_nostart;
     vt->stop = pe_watcher_nostop;
     vt->alarm = pe_watcher_alarm;
gdiff -up /dev/null '/usr/tmp/mp4882.d/new/Event-0.59/demo/variable_repeater.t'
Index: ./demo/variable_repeater.t
--- ./demo/variable_repeater.t  Wed Dec 31 19:00:00 1969
+++ ./demo/variable_repeater.t  Wed Dec 22 17:00:07 1999
@@ -0,0 +1,14 @@
+#!./perl -w
+# contributed by [EMAIL PROTECTED]
+
+use Event qw(loop);
+
+$w = Event->timer(interval => 1);
+$w->cb(sub {
+          my $next = rand(10);
+          print(scalar localtime(Event::time()), ": waiting ",
+                $next, " sec\n");
+          $w->interval($next);
+       });
+
+loop();
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/lib/Event.pm' 
'/usr/tmp/mp4882.d/new/Event-0.59/lib/Event.pm'
Index: ./lib/Event.pm
--- ./lib/Event.pm      Mon Nov 22 17:04:52 1999
+++ ./lib/Event.pm      Thu Jan 20 10:29:07 2000
@@ -13,7 +13,7 @@ use Carp;
 eval { require Carp::Heavy; };  # work around perl_call_pv bug XXX
 use vars qw($VERSION @EXPORT_OK
            $API $DebugLevel $Eval $DIED $Now);
-$VERSION = '0.58';
+$VERSION = '0.59';
 
 # If we inherit DynaLoader then we inherit AutoLoader; Bletch!
 require DynaLoader;
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/lib/Event.pod' 
'/usr/tmp/mp4882.d/new/Event-0.59/lib/Event.pod'
Index: ./lib/Event.pod
--- ./lib/Event.pod     Mon Nov 22 17:09:36 1999
+++ ./lib/Event.pod     Wed Jan 19 10:24:02 2000
@@ -168,9 +168,9 @@ Reports whether the C<$watcher> is suspe
 
 Extra attributes: min => $seconds, max => $seconds
 
-The callback is invoked only when no events are pending.  In the
-callback is not triggered by idling, an event will be generated at
-least every C<max> seconds and not more often than C<min> seconds.
+The callback is invoked only when no events are pending.  If there is
+never a chance to idle, an event will be generated at least every
+C<max> seconds and not more often than C<min> seconds.
 
 =item inactivity
 
@@ -204,7 +204,7 @@ calculated relative to the current time 
 =item io
 
 Extra attributes: fd => $fd, poll => 'rwe', got => 'rwet',
-[timeout => $seconds, hard => $bool]
+[timeout => $seconds, hard => $bool, timeout_cb => \&code]
 
 The callback is invoked when the file descriptor, C<fd>, has data to
 be read, written, or pending exceptions.  C<fd> can be a GLOB, an
@@ -213,6 +213,9 @@ IO::Handle object, or a file number (fil
 Note that it is your option whether to have multiple watchers per file
 handle or to use a single watcher for all event conditions.
 
+If timeout_cb is set then timeouts use this alternate callback instead
+of the main callback.
+
 =item signal
 
 Extra attribute: signal => $str
@@ -298,7 +301,8 @@ Signals in quick succession can be clump
 
 =item interval => $seconds
 
-How long between repeating timeouts.
+How long between repeating timeouts.  The C<at> attribute is
+recalculated using C<interval> upon callback return.
 
 =item level => $priority
 
@@ -398,6 +402,14 @@ actually want to stop a watcher then use
 =item timeout => $seconds
 
 The number of seconds before a watcher times out.
+
+=item timeout_cb => \&code
+
+=item timeout_cb => [$class_or_object, $method_name]
+
+This is an optional attribute for use when it is desired that timeouts
+be serviced in a separate code path than normal events.  When this
+attribute is unset, timeouts are serviced by C<cb>.
 
 =item var => $ref
 
gdiff -up '/usr/tmp/mp4882.d/old/Event-0.58/lib/Event/EventAPI.h' 
'/usr/tmp/mp4882.d/new/Event-0.59/lib/Event/EventAPI.h'
Index: ./lib/Event/EventAPI.h
--- ./lib/Event/EventAPI.h      Mon Nov 22 16:18:48 1999
+++ ./lib/Event/EventAPI.h      Wed Jan 19 16:47:42 2000
@@ -25,8 +25,8 @@ struct pe_watcher {
     IV running; /* SAVEINT */
     U32 flags;
     SV *desc;
-    pe_ring all;
-    pe_ring events;  /* queued events */
+    pe_ring all;       /* all watchers */
+    pe_ring events;    /* this watcher's queued events */
     HV *FALLBACK;
     I16 event_counter; /* refcnt? XXX */
     I16 prio;
gdiff -up /dev/null '/usr/tmp/mp4882.d/new/Event-0.59/t/leak2.t'
Index: ./t/leak2.t
--- ./t/leak2.t Wed Dec 31 19:00:00 1969
+++ ./t/leak2.t Thu Jan 20 10:14:59 2000
@@ -0,0 +1,47 @@
+#!./perl -w
+#
+# Test script to check the memory consumption
+# of an Event loop which installs, handles and
+# cancels a number of IO watchers (recursively).
+#
+# For extra diagnostics, Event.pm can be built with
+# -DEVENT_MEMORY_DEBUG.
+#
+# If the script succeeds, the final memory check
+# replies something like this:
+# "1-29509-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0"
+# (all slots except of the first two ones should
+# be 0 - the second number may differ).
+#
+# J. Stenzel ([EMAIL PROTECTED])
+#
+
+use Test; plan test => 2;
+
+use Event;
+# $Event::DebugLevel = 3;
+
+sub check {warn "[DBG] ", join('-', Event::_memory_counters), "\n";}
+
+sub iosub {
+    for (my $l=0; $l<=5; $l++) {
+       Event->io(
+                 fh => \*STDIO, timeout => "0.5$l",
+                 repeat => 1, cb => \&iosub,
+                 prio => 5);
+    }
+    $_[0]->w->cancel;
+}
+
+Event->io(fh => \*STDIO, timeout => 0.5, repeat => 1,
+         cb => \&iosub, prio => 5);
+
+Event->timer(prio => 1, after => 3,
+            cb => sub {
+                $_->cancel foreach Event::all_watchers;
+                ok !defined Event::all_watchers;
+            }
+           );
+
+Event::loop();
+ok 1;
#### End of Patch data ####

#### ApplyPatch data follows ####
# Data version        : 1.0
# Date generated      : Thu Jan 20 10:43:54 2000
# Generated by        : makepatch 2.00 (2.0BETA)
# Recurse directories : Yes
# p 'ChangeLog' 19702 948382241 0100444
# p 'Event.xs' 17098 948300347 0100444
# p 'MANIFEST' 775 948378747 0100444
# p 'TODO' 750 948380756 0100444
# p 'c/hook.c' 1614 948296407 0100444
# p 'c/idle.c' 3488 948296817 0100444
# p 'c/io.c' 5078 948296841 0100444
# p 'c/queue.c' 5118 948318846 0100444
# p 'c/signal.c' 3665 948296885 0100444
# p 'c/tied.c' 2593 948296785 0100444
# p 'c/timer.c' 2111 948296905 0100444
# p 'c/typemap.c' 3653 948297674 0100444
# p 'c/unix_io.c' 6438 948296429 0100444
# p 'c/var.c' 4082 948297690 0100444
# p 'c/watcher.c' 8585 948318701 0100444
# c 'demo/variable_repeater.t' 0 945900007 0100444
# p 'lib/Event.pm' 4159 948382147 0100444
# p 'lib/Event.pod' 18595 948295442 0100444
# p 'lib/Event/EventAPI.h' 5346 948318462 0100444
# c 't/leak2.t' 0 948381299 0100444
#### End of ApplyPatch data ####

#### End of Patch kit [created: Thu Jan 20 10:43:54 2000] ####
#### Checksum: 513 17072 2998 ####

-- 
"Does `competition' have an abstract purpose?"
       via, but not speaking for Deutsche Bank

Reply via email to