7b2d1b3027
to be instances where the kernel doesn't properly save and/or restore it. Use noupcall and nocompleted flags in the KSE mailbox. These require kernel changes to work which will be committed sometime later. Things still work without the changes. Remove the general kse entry function and use two different functions -- one for scope system threads and one for scope process threads. The scope system function is not yet enabled and we use the same function for all threads at the moment. Keep a copy of the KSE stack for the case that a KSE runs a scope system thread and uses the same stack as the thread (no upcalls are generated, so a separate stack isn't needed). This isn't enabled yet. Use a separate field for the KSE waiting flag. It isn't correct to use the mailbox flags field. The following fixes were provided by David Xu: o Initialize condition variable locks with thread versions of the low-level locking functions instead of the kse versions. o Enable threading before creating the first thread instead of after. o Don't enter critical regions when trying to malloc/free or call functions that malloc/free. o Take the scheduling lock when inheriting thread attributes. o Check the attribute's stack pointer instead of the attributes stack size for null when allocating a thread's stack. o Add a kseg reinit function so we don't have to destroy and then recreate the same lock. o Check the return value of kse_create() and return an appropriate error if it fails. o Don't forget to destroy a thread's locks when freeing it. o Examine the correct flags word for checking to see if a thread is in a synchronization queue. Things should now work on an SMP kernel.
109 lines
3.6 KiB
C
109 lines
3.6 KiB
C
/*
|
|
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by John Birrell.
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include "thr_private.h"
|
|
|
|
static void suspend_common(struct pthread *thread);
|
|
|
|
__weak_reference(_pthread_suspend_np, pthread_suspend_np);
|
|
__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
|
|
|
|
/* Suspend a thread: */
|
|
int
|
|
_pthread_suspend_np(pthread_t thread)
|
|
{
|
|
struct pthread *curthread = _get_curthread();
|
|
int ret;
|
|
|
|
/* Suspending the current thread doesn't make sense. */
|
|
if (thread == _get_curthread())
|
|
ret = EDEADLK;
|
|
|
|
/* Add a reference to the thread: */
|
|
else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
|
|
== 0) {
|
|
/* Lock the threads scheduling queue: */
|
|
THR_SCHED_LOCK(curthread, thread);
|
|
suspend_common(thread);
|
|
/* Unlock the threads scheduling queue: */
|
|
THR_SCHED_UNLOCK(curthread, thread);
|
|
|
|
/* Don't forget to remove the reference: */
|
|
_thr_ref_delete(curthread, thread);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
void
|
|
_pthread_suspend_all_np(void)
|
|
{
|
|
struct pthread *curthread = _get_curthread();
|
|
struct pthread *thread;
|
|
kse_critical_t crit;
|
|
|
|
/* Take the thread list lock: */
|
|
crit = _kse_critical_enter();
|
|
KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
|
|
|
|
TAILQ_FOREACH(thread, &_thread_list, tle) {
|
|
if (thread != curthread) {
|
|
THR_SCHED_LOCK(curthread, thread);
|
|
suspend_common(thread);
|
|
THR_SCHED_UNLOCK(curthread, thread);
|
|
}
|
|
}
|
|
|
|
/* Release the thread list lock: */
|
|
KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
|
|
_kse_critical_leave(crit);
|
|
}
|
|
|
|
void
|
|
suspend_common(struct pthread *thread)
|
|
{
|
|
if ((thread->state != PS_DEAD) &&
|
|
(thread->state != PS_DEADLOCK) &&
|
|
((thread->flags & THR_FLAGS_EXITING) == 0)) {
|
|
thread->flags |= THR_FLAGS_SUSPENDED;
|
|
if ((thread->flags & THR_FLAGS_IN_RUNQ) != 0)
|
|
THR_RUNQ_REMOVE(thread);
|
|
THR_SET_STATE(thread, PS_SUSPENDED);
|
|
#ifdef NOT_YET
|
|
if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0)
|
|
/* ??? */
|
|
#endif
|
|
}
|
|
}
|