Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/nathanw_sa]: src/lib/libpthread Cancellation support.



details:   https://anonhg.NetBSD.org/src/rev/9d331ddacc61
branches:  nathanw_sa
changeset: 505563:9d331ddacc61
user:      nathanw <nathanw%NetBSD.org@localhost>
date:      Mon Jan 28 19:05:48 2002 +0000

description:
Cancellation support.
This includes implementing pthread_cancel() and pthread_testcancel(),
making pthread_join() and pthread_cond_wait() cancellation points,
introducing new states to distinguish waiting on a sleep queue
from waiting in the kernel, and introducing a locking protocol around
changing a thread's run state.

diffstat:

 lib/libpthread/pthread.c       |  90 ++++++++++++++++++++++++++++++++++++-----
 lib/libpthread/pthread.h       |   6 +-
 lib/libpthread/pthread_int.h   |  27 +++++++++--
 lib/libpthread/pthread_mutex.c |  16 ++++++-
 4 files changed, 116 insertions(+), 23 deletions(-)

diffs (truncated from 316 to 300 lines):

diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread.c
--- a/lib/libpthread/pthread.c  Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread.c  Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread.c,v 1.1.2.13 2001/12/30 02:18:17 nathanw Exp $ */
+/*     $NetBSD: pthread.c,v 1.1.2.14 2002/01/28 19:05:48 nathanw Exp $ */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -39,6 +39,7 @@
 #include <assert.h>
 #include <err.h>
 #include <errno.h>
+#include <lwp.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -82,8 +83,10 @@
 void pthread_init(void)
 {
        pthread_t first;
+       int retval;
        extern int __isthreaded;
-
+       extern timer_t pthread_alarmtimer;
+       struct sigevent ev;
 #ifdef PTHREAD__DEBUG
        pthread__debug_init();
 #endif
@@ -95,7 +98,13 @@
        PTQ_INIT(&reidlequeue);
        PTQ_INIT(&runqueue);
        PTQ_INIT(&idlequeue);
-
+       
+       ev.sigev_notify = SIGEV_SA;
+       ev.sigev_signo = 0;
+       ev.sigev_value.sival_int = 0;
+       retval = timer_create(CLOCK_REALTIME, &ev, &pthread_alarmtimer);
+       if (retval)
+               err(1, "timer_create");
        /* Create the thread structure corresponding to main() */
        pthread__initmain(&first);
        pthread__initthread(first);
@@ -137,6 +146,7 @@
        t->pt_magic = PT_MAGIC;
        t->pt_type = PT_THREAD_NORMAL;
        t->pt_state = PT_STATE_RUNNABLE;
+       pthread_lockinit(&t->pt_statelock);
        t->pt_spinlocks = 0;
        t->pt_next = NULL;
        t->pt_exitval = NULL;
@@ -149,7 +159,9 @@
        t->pt_sleepuc = NULL;
        sigemptyset(&t->pt_siglist);
        sigemptyset(&t->pt_sigmask);
+       pthread_lockinit(&t->pt_siglock);
        PTQ_INIT(&t->pt_joiners);
+       pthread_lockinit(&t->pt_join_lock);
        PTQ_INIT(&t->pt_cleanup_stack);
        memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
 #ifdef PTHREAD__DEBUG
@@ -274,6 +286,9 @@
 
        self = pthread__self();
 
+       /* Disable cancellability. */
+       self->pt_flags |= PT_FLAG_CS_DISABLED;
+
        /* Call any cancellation cleanup handlers */
        while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
                cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
@@ -340,6 +355,10 @@
                return EINVAL;
        
        self = pthread__self();
+
+       if (thread == self)
+               return EDEADLK;
+               
        pthread_spinlock(self, &thread->pt_join_lock);
 
        if (thread->pt_flags & PT_FLAG_DETACHED) {
@@ -353,11 +372,17 @@
                 * "I'm not dead yet!"
                 * "You will be soon enough."
                 */
-               PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
+               pthread_spinlock(self, &self->pt_statelock);
+               if (self->pt_cancel) {
+                       pthread_spinunlock(self, &self->pt_statelock);
+                       pthread_spinunlock(self, &thread->pt_join_lock);
+                       pthread_exit(PTHREAD_CANCELED);
+               }
+               self->pt_state = PT_STATE_BLOCKED_QUEUE;
+               pthread_spinunlock(self, &self->pt_statelock);
 
-               self->pt_state = PT_STATE_BLOCKED;
+               PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
                pthread__block(self, &thread->pt_join_lock);
-
                pthread_spinlock(self, &thread->pt_join_lock);
        }
        
@@ -387,7 +412,6 @@
        return 0;
 }
 
-
 int
 pthread_equal(pthread_t t1, pthread_t t2)
 {
@@ -532,7 +556,48 @@
 int
 pthread_cancel(pthread_t thread)
 {
-       /* XXX finish */
+       pthread_t self;
+       int flags;
+
+       if (!(thread->pt_state == PT_STATE_RUNNABLE || 
+           thread->pt_state == PT_STATE_BLOCKED_QUEUE ||
+           thread->pt_state == PT_STATE_BLOCKED_SYS))
+               return ESRCH;
+
+       self = pthread__self();
+       flags = thread->pt_flags;
+
+       flags |= PT_FLAG_CS_PENDING;
+       if ((flags & PT_FLAG_CS_DISABLED) == 0) {
+               thread->pt_cancel = 1;
+               pthread_spinlock(self, &thread->pt_statelock);
+               if (thread->pt_state == PT_STATE_BLOCKED_SYS) {
+                       /* It's sleeping in the kernel. If we can
+                        * wake it up, it will notice the cancellation
+                        * when it returns. If we can't wake it up...
+                        * there's not much to be done about it.
+                        */
+                       _lwp_wakeup(thread->pt_blockedlwp);
+               } else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
+                       /* We're blocked somewhere (pthread__block()
+                        * was called. Cause it to wakeup and the
+                        * caller will check for the cancellation.
+                        */
+                       pthread_spinlock(self, thread->pt_sleeplock);
+                       PTQ_REMOVE(thread->pt_sleepq, thread, 
+                           pt_sleep);
+                       pthread_spinunlock(self, thread->pt_sleeplock);
+                       pthread__sched(self, thread);
+               } else {
+                       /* Nothing. The target thread is running and will
+                        * notice at the next deferred cancellation point.
+                        */
+               }
+               pthread_spinunlock(self, &thread->pt_statelock);
+       }
+
+       thread->pt_flags = flags;
+
        return 0;
 }
 
@@ -567,7 +632,7 @@
                        self->pt_cancel = 1;
                        /* This is not a deferred cancellation point. */
                        if (flags & PT_FLAG_CS_ASYNC)
-                               pthread_exit(PTHREAD_CANCELLED);
+                               pthread_exit(PTHREAD_CANCELED);
                }
        } else
                return EINVAL;
@@ -597,7 +662,7 @@
        if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
                flags |= PT_FLAG_CS_ASYNC;
                if (self->pt_cancel)
-                       pthread_exit(PTHREAD_CANCELLED);
+                       pthread_exit(PTHREAD_CANCELED);
        } else if (type == PTHREAD_CANCEL_DEFERRED)
                flags &= ~PT_FLAG_CS_ASYNC;
        else
@@ -615,7 +680,8 @@
        pthread_t self;
        
        self = pthread__self();
-       pthread__testcancel(self);
+       if (self->pt_cancel)
+               pthread_exit(PTHREAD_CANCELED);
 }
 
 
@@ -624,7 +690,7 @@
 {
 
        if (self->pt_cancel)
-               pthread_exit(PTHREAD_CANCELLED);
+               pthread_exit(PTHREAD_CANCELED);
 }
 
 void
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread.h
--- a/lib/libpthread/pthread.h  Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread.h  Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread.h,v 1.1.2.7 2001/12/30 02:14:41 nathanw Exp $  */
+/*     $NetBSD: pthread.h,v 1.1.2.8 2002/01/28 19:05:49 nathanw Exp $  */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -136,11 +136,11 @@
 #define PTHREAD_CANCEL_DISABLE         1
 
 /* POSIX 1003.1-2001, section 2.5.9.3: "The symbolic constant
- * PTHREAD_CANCELLED expands to a constant expression of type (void *)
+ * PTHREAD_CANCELED expands to a constant expression of type (void *)
  * whose value matches no pointer to an object in memory nor the value
  * NULL."
  */
-#define PTHREAD_CANCELLED      ((void *) 1)
+#define PTHREAD_CANCELED       ((void *) 1)
 
 #define        _POSIX_THREADS
 
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread_int.h
--- a/lib/libpthread/pthread_int.h      Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread_int.h      Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_int.h,v 1.1.2.17 2001/12/30 02:13:00 nathanw Exp $     */
+/*     $NetBSD: pthread_int.h,v 1.1.2.18 2002/01/28 19:05:49 nathanw Exp $     */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -62,9 +62,11 @@
 
        int     pt_type;        /* normal, upcall, or idle */
        int     pt_state;       /* running, blocked, etc. */
-       int     pt_flags;       
+       pthread_spin_t pt_statelock;    /* lock on pt_state */
+       int     pt_flags;       /* see PT_FLAG_* below */
        int     pt_cancel;      /* Deferred cancellation */
        int     pt_spinlocks;   /* Number of spinlocks held. */
+       int     pt_blockedlwp;  /* LWP/SA number when blocked */
 
        int     pt_errno;       /* Thread-specific errno. */
 
@@ -74,6 +76,10 @@
        PTQ_ENTRY(pthread_st)   pt_allq;
        /* Entry on the sleep queue (xxx should be same as run queue?) */
        PTQ_ENTRY(pthread_st)   pt_sleep;
+       /* Queue we're sleeping on */
+       struct pthread_queue_t          *pt_sleepq;
+       /* Lock protecting that queue */
+       pthread_spin_t          *pt_sleeplock;
 
        stack_t         pt_stack;       /* Our stack */
        ucontext_t      *pt_uc;         /* Saved context when we're stopped */
@@ -139,10 +145,11 @@
 
 /* Thread states */
 #define PT_STATE_RUNNABLE      1
-#define PT_STATE_BLOCKED       2
-#define PT_STATE_ZOMBIE                3
-#define PT_STATE_DEAD          4
-#define PT_STATE_RECYCLABLE    5
+#define PT_STATE_BLOCKED_SYS   2
+#define PT_STATE_BLOCKED_QUEUE 3
+#define PT_STATE_ZOMBIE                4
+#define PT_STATE_DEAD          5
+#define PT_STATE_RECYCLABLE    6
 
 /* Flag values */
 
@@ -200,6 +207,14 @@
 void   pthread__sa_start(void);
 void   pthread__sa_recycle(pthread_t old, pthread_t new);
 
+/* Alarm code */
+void   *pthread__alarm_add(pthread_t, const struct timespec *,
+    void (*)(void *), void *);
+void   pthread__alarm_del(pthread_t, void *);
+int    pthread__alarm_fired(void *);
+void   pthread__alarm_process(pthread_t self, void *arg);
+
+
 #include "pthread_md.h"
 
 int    _getcontext_u(ucontext_t *);
diff -r 8be8b0af7b62 -r 9d331ddacc61 lib/libpthread/pthread_mutex.c
--- a/lib/libpthread/pthread_mutex.c    Mon Jan 28 19:03:09 2002 +0000
+++ b/lib/libpthread/pthread_mutex.c    Mon Jan 28 19:05:48 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_mutex.c,v 1.1.2.6 2001/08/08 16:36:29 nathanw Exp $    */
+/*     $NetBSD: pthread_mutex.c,v 1.1.2.7 2002/01/28 19:05:49 nathanw Exp $    */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -117,7 +117,19 @@
                 */
                if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) {
                        PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep);
-                       self->pt_state = PT_STATE_BLOCKED;



Home | Main Index | Thread Index | Old Index