Do not deliver event signal if waiter has gone away.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 18 Feb 2007 19:55:08 +0000 (19:55 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 18 Feb 2007 19:55:08 +0000 (19:55 +0000)
lib/silcutil/silcfsm.c

index c05efdece42752635caabae556186e4b7191d7bd..aff9a77edf5e1cf8d7c053083289e06fcf706475 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2005 - 2006 Pekka Riikonen
+  Copyright (C) 2005 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -632,6 +632,9 @@ SILC_TASK_CALLBACK(silc_fsm_signal)
 {
   SilcFSMEventSignal p = context;
   SilcMutex lock = p->event->fsm->u.m.lock;
+  SilcFSM fsm;
+
+  /* We have to check couple of things before delivering the signal. */
 
   /* If the event value has went to zero while we've been waiting this
      callback, the event has been been signalled already.  It can happen
@@ -644,6 +647,18 @@ SILC_TASK_CALLBACK(silc_fsm_signal)
     silc_free(p);
     return;
   }
+
+  /* If the waiter is not waiting anymore, don't deliver the signal */
+  silc_list_start(p->event->waiters);
+  while ((fsm = silc_list_get(p->event->waiters)))
+    if (fsm == p->fsm)
+      break;
+  if (!fsm) {
+    silc_mutex_unlock(lock);
+    silc_fsm_event_unref(p->event);
+    silc_free(p);
+    return;
+  }
   silc_mutex_unlock(lock);
 
   SILC_LOG_DEBUG(("Signalled %s %p", p->fsm->thread ? "thread" : "FSM",
@@ -706,7 +721,7 @@ static void silc_fsm_thread_termination_signal(SilcFSMEvent event)
   silc_mutex_lock(lock);
 
   silc_list_start(event->waiters);
-  while ((fsm = silc_list_get(event->waiters)) != SILC_LIST_END) {
+  while ((fsm = silc_list_get(event->waiters))) {
     /* Signal on thread termination.  Wake up destination scheduler in case
        caller is a real thread. */
     silc_list_del(event->waiters, fsm);