Date: Wed, 01 Mar 2000 09:30:43 -0500
From: "Daniel M. Eischen" <eischen@vigrid.com>
To: John Polstra <jdp@polstra.com>
Cc: current@freebsd.org, jasone@freebsd.org
Subject: Re: pthread_{suspend,resume}_np broken?
Message-ID: <38BD2993.A122EDAE@vigrid.com>
References: <Pine.SUN.3.91.1000301064035.7639A-100000@pcnet1.pcnet.com>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------D3633965D555A5BBF600678E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Daniel Eischen wrote:
>
> On Tue, 29 Feb 2000, John Polstra wrote:
>
> > In article <Pine.SUN.3.91.1000229224700.20669A@pcnet1.pcnet.com>,
> > Daniel Eischen <eischen@vigrid.com> wrote:
> > > On Tue, 29 Feb 2000, John Polstra wrote:
> > >
> > > > Shouldn't the test against PS_SUSPENDED be "==" instead of "!="?
> > >
> > > Yes, it should be "==" instead of "!=".
> > >
> > > Go ahead and fix it if you want :-)
> >
> > Thanks. I'll ask Jordan if I may commit the fix.
> >
> > What about the other part of my question? I still don't understand
> > why in my test program pthread_suspend_np() isn't suspending the
> > thread. I think it's a separate bug from the pthread_resume_np() bug.
>
> Sorry, it was very late here and I missed that part.
>
> I see the problem. pthread_suspend_np is broke in that it only will
> work if the thread is running (PS_RUNNING). Your program is always
> trying to suspend a thread that is sleeping (PS_SLEEP_WAIT) so changing
> the state with PTHREAD_NEW_STATE fails.
>
> The fix isn't as easy as just correctly setting the threads state.
> Potentially, the suspended thread could be waiting on a mutex or
> condition variable and be in another queue. The correct fix is
> probably to save the threads old state and then set the threads state
> to PS_SUSPENDED. Resuming should restore the saved thread state.
>
> I'll see if I can come up with a correct fix for this.
Here's a quick fix. It also includes a simple fix for pthread_kill that
src/libc_r/uthread/test/sigwait/sigwait.c will expose.
I haven't run any other regression tests. I'll do that when I get
some more time. Jason, can you also take a look at these changes and
run some tests on them?
Thanks,
Dan Eischen
eischen@vigrid.com
--------------D3633965D555A5BBF600678E
Content-Type: text/plain; charset=us-ascii;
name="diffs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="diffs"
Index: pthread_private.h
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/pthread_private.h,v
retrieving revision 1.36
diff -c -r1.36 pthread_private.h
*** pthread_private.h 2000/01/20 21:53:58 1.36
--- pthread_private.h 2000/03/01 12:49:27
***************
*** 576,581 ****
--- 576,583 ----
#define PTHREAD_CANCEL_NEEDED 0x0010
int cancelflags;
+ int suspended;
+
thread_continuation_t continuation;
/*
Index: uthread_cancel.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_cancel.c,v
retrieving revision 1.3
diff -c -r1.3 uthread_cancel.c
*** uthread_cancel.c 2000/01/19 07:04:45 1.3
--- uthread_cancel.c 2000/03/01 13:44:57
***************
*** 37,42 ****
--- 37,51 ----
pthread->cancelflags |= PTHREAD_CANCELLING;
break;
+ case PS_SUSPENDED:
+ /*
+ * This thread isn't in any scheduling
+ * queues; just change it's state:
+ */
+ pthread->cancelflags |= PTHREAD_CANCELLING;
+ PTHREAD_SET_STATE(pthread, PS_RUNNING);
+ break;
+
case PS_SPINBLOCK:
case PS_FDR_WAIT:
case PS_FDW_WAIT:
***************
*** 52,58 ****
case PS_WAIT_WAIT:
case PS_SIGSUSPEND:
case PS_SIGWAIT:
- case PS_SUSPENDED:
/* Interrupt and resume: */
pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCELLING;
--- 61,66 ----
Index: uthread_cond.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_cond.c,v
retrieving revision 1.22
diff -c -r1.22 uthread_cond.c
*** uthread_cond.c 2000/01/27 23:06:59 1.22
--- uthread_cond.c 2000/03/01 13:03:46
***************
*** 282,289 ****
break;
}
! if (interrupted != 0 && _thread_run->continuation != NULL)
! _thread_run->continuation((void *) _thread_run);
_thread_leave_cancellation_point();
}
--- 282,292 ----
break;
}
! if (interrupted != 0) {
! if (_thread_run->continuation != NULL)
! _thread_run->continuation((void *) _thread_run);
! rval = EINTR;
! }
_thread_leave_cancellation_point();
}
***************
*** 449,456 ****
break;
}
! if (interrupted != 0 && _thread_run->continuation != NULL)
! _thread_run->continuation((void *) _thread_run);
_thread_leave_cancellation_point();
}
--- 452,462 ----
break;
}
! if (interrupted != 0) {
! if (_thread_run->continuation != NULL)
! _thread_run->continuation((void *) _thread_run);
! rval = EINTR;
! }
_thread_leave_cancellation_point();
}
Index: uthread_create.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_create.c,v
retrieving revision 1.24
diff -c -r1.24 uthread_create.c
*** uthread_create.c 2000/01/19 07:04:46 1.24
--- uthread_create.c 2000/03/01 13:19:53
***************
*** 299,308 ****
/* Add the thread to the linked list of all threads: */
TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
! if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
new_thread->state = PS_SUSPENDED;
! PTHREAD_WAITQ_INSERT(new_thread);
! } else {
new_thread->state = PS_RUNNING;
PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
}
--- 299,307 ----
/* Add the thread to the linked list of all threads: */
TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
! if (pattr->suspend == PTHREAD_CREATE_SUSPENDED)
new_thread->state = PS_SUSPENDED;
! else {
new_thread->state = PS_RUNNING;
PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
}
Index: uthread_kern.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_kern.c,v
retrieving revision 1.28
diff -c -r1.28 uthread_kern.c
*** uthread_kern.c 2000/01/20 04:46:51 1.28
--- uthread_kern.c 2000/03/01 13:18:35
***************
*** 184,191 ****
switch (_thread_run->state) {
case PS_DEAD:
case PS_STATE_MAX: /* to silence -Wall */
/*
! * Dead threads are not placed in any queue:
*/
break;
--- 184,193 ----
switch (_thread_run->state) {
case PS_DEAD:
case PS_STATE_MAX: /* to silence -Wall */
+ case PS_SUSPENDED:
/*
! * Dead and suspended threads are not placed
! * in any queue:
*/
break;
***************
*** 227,233 ****
case PS_SIGSUSPEND:
case PS_SIGTHREAD:
case PS_SIGWAIT:
- case PS_SUSPENDED:
case PS_WAIT_WAIT:
/* No timeouts for these states: */
_thread_run->wakeup_time.tv_sec = -1;
--- 229,234 ----
Index: uthread_mutex.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_mutex.c,v
retrieving revision 1.20
diff -c -r1.20 uthread_mutex.c
*** uthread_mutex.c 2000/01/19 07:04:49 1.20
--- uthread_mutex.c 2000/03/01 13:00:56
***************
*** 610,617 ****
* Check to see if this thread was interrupted and
* is still in the mutex queue of waiting threads:
*/
! if (_thread_run->interrupted != 0)
mutex_queue_remove(*mutex, _thread_run);
/* Unlock the mutex structure: */
_SPINUNLOCK(&(*mutex)->lock);
--- 610,619 ----
* Check to see if this thread was interrupted and
* is still in the mutex queue of waiting threads:
*/
! if (_thread_run->interrupted != 0) {
mutex_queue_remove(*mutex, _thread_run);
+ ret = EINTR;
+ }
/* Unlock the mutex structure: */
_SPINUNLOCK(&(*mutex)->lock);
Index: uthread_resume_np.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_resume_np.c,v
retrieving revision 1.7
diff -c -r1.7 uthread_resume_np.c
*** uthread_resume_np.c 1999/08/28 00:03:44 1.7
--- uthread_resume_np.c 2000/03/01 13:46:54
***************
*** 44,51 ****
/* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) {
! /* The thread exists. Is it suspended? */
! if (thread->state != PS_SUSPENDED) {
/*
* Defer signals to protect the scheduling queues
* from access by the signal handler:
--- 44,54 ----
/* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) {
! /* Cancel any pending suspensions: */
! thread->suspended = 0;
!
! /* Is it currently suspended? */
! if (thread->state == PS_SUSPENDED) {
/*
* Defer signals to protect the scheduling queues
* from access by the signal handler:
***************
*** 53,59 ****
_thread_kern_sig_defer();
/* Allow the thread to run. */
! PTHREAD_NEW_STATE(thread,PS_RUNNING);
/*
* Undefer and handle pending signals, yielding if
--- 56,63 ----
_thread_kern_sig_defer();
/* Allow the thread to run. */
! PTHREAD_SET_STATE(thread,PS_RUNNING);
! PTHREAD_PRIOQ_INSERT_TAIL(thread);
/*
* Undefer and handle pending signals, yielding if
Index: uthread_sig.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_sig.c,v
retrieving revision 1.25
diff -c -r1.25 uthread_sig.c
*** uthread_sig.c 2000/01/20 04:46:52 1.25
--- uthread_sig.c 2000/03/01 14:11:30
***************
*** 149,155 ****
signal_lock.access_lock = 0;
else {
sigaddset(&pthread->sigmask, sig);
!
/*
* Make sure not to deliver the same signal to
* the thread twice. sigpend is potentially
--- 149,155 ----
signal_lock.access_lock = 0;
else {
sigaddset(&pthread->sigmask, sig);
!
/*
* Make sure not to deliver the same signal to
* the thread twice. sigpend is potentially
***************
*** 160,166 ****
*/
if (sigismember(&pthread->sigpend, sig))
sigdelset(&pthread->sigpend, sig);
!
signal_lock.access_lock = 0;
_thread_sig_deliver(pthread, sig);
sigdelset(&pthread->sigmask, sig);
--- 160,166 ----
*/
if (sigismember(&pthread->sigpend, sig))
sigdelset(&pthread->sigpend, sig);
!
signal_lock.access_lock = 0;
_thread_sig_deliver(pthread, sig);
sigdelset(&pthread->sigmask, sig);
***************
*** 461,466 ****
--- 461,467 ----
case PS_RUNNING:
case PS_SIGTHREAD:
case PS_STATE_MAX:
+ case PS_SUSPENDED:
break;
/*
***************
*** 492,498 ****
case PS_SIGWAIT:
case PS_SLEEP_WAIT:
case PS_SPINBLOCK:
- case PS_SUSPENDED:
case PS_WAIT_WAIT:
if ((pthread->flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
PTHREAD_WAITQ_REMOVE(pthread);
--- 493,498 ----
***************
*** 628,637 ****
!sigismember(&pthread->sigmask, sig)) {
/* Perform any state changes due to signal arrival: */
thread_sig_check_state(pthread, sig);
}
-
- /* Increment the pending signal count. */
- sigaddset(&pthread->sigpend,sig);
}
}
--- 628,637 ----
!sigismember(&pthread->sigmask, sig)) {
/* Perform any state changes due to signal arrival: */
thread_sig_check_state(pthread, sig);
+ } else {
+ /* Increment the pending signal count. */
+ sigaddset(&pthread->sigpend,sig);
}
}
}
Index: uthread_suspend_np.c
===================================================================
RCS file: /opt/b/CVS/src/lib/libc_r/uthread/uthread_suspend_np.c,v
retrieving revision 1.7
diff -c -r1.7 uthread_suspend_np.c
*** uthread_suspend_np.c 1999/08/28 00:03:53 1.7
--- uthread_suspend_np.c 2000/03/01 13:36:11
***************
*** 36,41 ****
--- 36,43 ----
#include <pthread.h>
#include "pthread_private.h"
+ static void finish_suspension(void *arg);
+
/* Suspend a thread: */
int
pthread_suspend_np(pthread_t thread)
***************
*** 44,66 ****
/* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) {
- /* The thread exists. Is it running? */
- if (thread->state != PS_RUNNING &&
- thread->state != PS_SUSPENDED) {
- /* The thread operation has been interrupted */
- _thread_seterrno(thread,EINTR);
- thread->interrupted = 1;
- }
-
/*
* Defer signals to protect the scheduling queues from
* access by the signal handler:
*/
_thread_kern_sig_defer();
! /* Suspend the thread. */
! PTHREAD_NEW_STATE(thread,PS_SUSPENDED);
/*
* Undefer and handle pending signals, yielding if
* necessary:
--- 46,127 ----
/* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) {
/*
* Defer signals to protect the scheduling queues from
* access by the signal handler:
*/
_thread_kern_sig_defer();
+
+ switch (thread->state) {
+ case PS_RUNNING:
+ /*
+ * Remove the thread from the priority queue and
+ * set the state to suspended:
+ */
+ PTHREAD_PRIOQ_REMOVE(thread);
+ PTHREAD_SET_STATE(thread, PS_SUSPENDED);
+ break;
+
+ case PS_SPINBLOCK:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ case PS_POLL_WAIT:
+ case PS_SELECT_WAIT:
+ /*
+ * Remove these threads from the work queue
+ * and mark the operation as interrupted:
+ */
+ if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
+ PTHREAD_WORKQ_REMOVE(thread);
+ _thread_seterrno(thread,EINTR);
+ thread->interrupted = 1;
+
+ /* FALLTHROUGH */
+ case PS_SIGTHREAD:
+ case PS_SLEEP_WAIT:
+ case PS_WAIT_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
+ /*
+ * Remove these threads from the waiting queue and
+ * set their state to suspended:
+ */
+ PTHREAD_WAITQ_REMOVE(thread);
+ PTHREAD_SET_STATE(thread, PS_SUSPENDED);
+ break;
! case PS_MUTEX_WAIT:
! case PS_COND_WAIT:
! case PS_FDLR_WAIT:
! case PS_FDLW_WAIT:
! case PS_FILE_WAIT:
! case PS_JOIN:
! /* Mark the thread as suspended: */
! thread->suspended = 1;
+ /*
+ * Threads in these states may be in queues.
+ * In order to preserve queue integrity, the
+ * cancelled thread must remove itself from the
+ * queue. Mark the thread as interrupted and
+ * set the state to running. When the thread
+ * resumes, it will remove itself from the queue
+ * and call the suspension completion routine.
+ */
+ thread->interrupted = 1;
+ _thread_seterrno(thread, EINTR);
+ PTHREAD_NEW_STATE(thread, PS_RUNNING);
+ thread->continuation = finish_suspension;
+ break;
+
+ case PS_DEAD:
+ case PS_DEADLOCK:
+ case PS_STATE_MAX:
+ case PS_SUSPENDED:
+ /* Nothing needs to be done: */
+ break;
+ }
+
/*
* Undefer and handle pending signals, yielding if
* necessary:
***************
*** 69,72 ****
--- 130,142 ----
}
return(ret);
}
+
+ static void
+ finish_suspension(void *arg)
+ {
+ if (_thread_run->suspended != 0)
+ _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__);
+ }
+
+
#endif
--------------D3633965D555A5BBF600678E--
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?38BD2993.A122EDAE>
