/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
#include <sys/sysmacros.h>
#include <sys/schedctl.h>
{
return (NULL);
}
/*
* Same as idtot(), but acquire and return
* the tid hash table entry lock on success.
* This allows lwp_unpark() to do its job without acquiring
* p->p_lock (and thereby causing congestion problems when
* the application calls lwp_unpark() too often).
*/
static kthread_t *
{
kthread_t *t;
mutex_exit(*mpp);
return (t);
}
return (NULL);
}
/*
* Stop an lwp of the current process
*/
int
{
kthread_t *t;
int error;
mutex_enter(&p->p_lock);
else
error = lwp_suspend(t);
mutex_exit(&p->p_lock);
if (error)
return (0);
}
int
{
kthread_t *t;
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
}
lwp_continue(t);
mutex_exit(&p->p_lock);
return (0);
}
int
{
kthread_t *t;
if (sig != 0)
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
if (sig != 0)
}
if (sig == 0) {
mutex_exit(&p->p_lock);
return (0);
}
mutex_exit(&p->p_lock);
return (0);
}
/*
* This is the specification of lwp_wait() from the _lwp_wait(2) manual page:
*
* The lwp_wait() function blocks the current lwp until the lwp specified
* by 'lwpid' terminates. If the specified lwp terminated prior to the call
* to lwp_wait(), then lwp_wait() returns immediately. If 'lwpid' is zero,
* then lwp_wait() waits for any undetached lwp in the current process.
* If 'lwpid' is not zero, then it must specify an undetached lwp in the
* current process. If 'departed' is not NULL, then it points to a location
* where the id of the exited lwp is stored.
*
* When an lwp exits and there are one or more lwps in the process waiting
* for this specific lwp to exit, then one of the waiting lwps is unblocked
* and it returns from lwp_wait() successfully. Any other lwps waiting for
* this same lwp to exit are also unblocked, however, they return from
* lwp_wait() with the error ESRCH. If there are no lwps in the process
* waiting for this specific lwp to exit but there are one or more lwps
* waiting for any lwp to exit, then one of the waiting lwps is unblocked
* and it returns from lwp_wait() successfully.
*
* If an lwp is waiting for any lwp to exit, it blocks until an undetached
* lwp for which no other lwp is waiting terminates, at which time it returns
* successfully, or until all other lwps in the process are either daemon
* lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK.
*/
int
{
int error = 0;
/*
* lwp_wait() is not supported for the /proc agent lwp.
*/
mutex_enter(&p->p_lock);
prbarrier(p);
p->p_lwpwait++;
p->p_lwpdwait += daemon;
if (lwpid != 0) {
target_lep = NULL;
else {
target_lep->le_waiters++;
}
}
while (error == 0) {
kthread_t *t;
int i;
if (lwpid != 0) {
/*
* Look for a specific zombie lwp.
*/
if (target_lep == NULL)
if (!(t->t_proc_flag & TP_TWAIT))
} else {
/*
* We found the zombie we are waiting for.
*/
p->p_zombcnt--;
p->p_lwpwait--;
p->p_lwpdwait -= daemon;
lwp_hash_out(p, lwpid);
mutex_exit(&p->p_lock);
return (0);
}
} else {
/*
* Look for any zombie lwp.
*/
int some_non_daemon_will_return = 0;
/* for each entry in the lwp directory... */
for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
continue;
/*
* We found a zombie lwp. If there is some
* other thread waiting specifically for the
* zombie we just found, then defer to the other
* waiting thread and continue searching for
* another zombie. Also check to see if there
* is some non-daemon thread sleeping here in
* lwp_wait() that will succeed and return when
* we drop p->p_lock. This is tested below.
*/
if (lep->le_waiters != 0) {
continue;
}
/*
* We found a zombie that no one else
* is specifically waiting for.
*/
p->p_zombcnt--;
p->p_lwpwait--;
p->p_lwpdwait -= daemon;
lwp_hash_out(p, tid);
mutex_exit(&p->p_lock);
return (0);
}
/*
* We are waiting for anyone. If all non-daemon lwps
* are waiting here, and if we determined above that
* no non-daemon lwp will return, we have deadlock.
*/
if (!some_non_daemon_will_return &&
p->p_lwpcnt == p->p_lwpdaemon +
(p->p_lwpwait - p->p_lwpdwait))
}
/*
* We are waiting for a specific non-zombie lwp.
* Fail if there is a deadlock loop.
*/
for (;;) {
if (t == curthread) {
break;
}
/* who is he waiting for? */
break;
if (tid == 0) {
/*
* The lwp we are waiting for is
* waiting for anyone (transitively).
* If there are no zombies right now
* and if we would have deadlock due
* to all non-daemon lwps waiting here,
* wake up the lwp that is waiting for
* anyone so it can return EDEADLK.
*/
if (p->p_zombcnt == 0 &&
p->p_lwpcnt == p->p_lwpdaemon +
p->p_lwpwait - p->p_lwpdwait)
cv_broadcast(&p->p_lwpexit);
break;
}
break;
}
}
if (error)
break;
/*
* Wait for some lwp to terminate.
*/
prbarrier(p);
if (lwpid != 0) {
target_lep = NULL;
else
}
}
target_lep->le_waiters--;
}
p->p_lwpwait--;
p->p_lwpdwait -= daemon;
mutex_exit(&p->p_lock);
}
int
{
kthread_t *t;
int error = 0;
mutex_enter(&p->p_lock);
prbarrier(p);
if (!(t->t_proc_flag & TP_TWAIT))
else {
t->t_proc_flag &= ~TP_TWAIT;
cv_broadcast(&p->p_lwpexit);
}
} else {
p->p_zombcnt--;
lwp_hash_out(p, lwpid);
}
mutex_exit(&p->p_lock);
if (error)
return (0);
}
/*
* Unpark the specified lwp.
*/
static int
{
kthread_t *t;
int error = 0;
} else {
mutex_enter(&t->t_delay_lock);
t->t_unpark = 1;
cv_signal(&t->t_delay_cv);
mutex_exit(&t->t_delay_lock);
mutex_exit(mp);
}
return (error);
}
/*
* Cancel a previous unpark for the specified lwp.
*
* This interface exists ONLY to support older versions of libthread, which
* called lwp_unpark(self) to force calls to lwp_park(self) to return
* immediately. These older libthreads required a mechanism to cancel the
* lwp_unpark(self).
*
* libc does not call this interface. Instead, the sc_park flag in the
* schedctl page is cleared to force calls to lwp_park() to return
* immediately.
*/
static int
{
kthread_t *t;
int error = 0;
} else {
mutex_enter(&t->t_delay_lock);
t->t_unpark = 0;
mutex_exit(&t->t_delay_lock);
mutex_exit(mp);
}
return (error);
}
/*
* Sleep until we are set running by lwp_unpark() or until we are
* interrupted by a signal or until we exhaust our timeout.
* time until timeout. On exit, we copyout the residual time left to it.
*/
static int
{
int timecheck = 0;
int error = 0;
if (lwpid != 0) /* unpark the other lwp, if any */
(void) lwp_unpark(lwpid);
if (timeoutp) {
gethrestime(&now);
if (datamodel == DATAMODEL_NATIVE) {
goto out;
}
} else {
goto out;
}
}
if (itimerspecfix(&rqtime)) {
goto out;
}
/*
* Convert the timespec value into absolute time.
*/
}
(void) new_mstate(t, LMS_USER_LOCK);
mutex_enter(&t->t_delay_lock);
if (!schedctl_is_park())
switch (cv_waituntil_sig(&t->t_delay_cv,
case 0:
break;
case -1:
break;
}
}
t->t_unpark = 0;
mutex_exit(&t->t_delay_lock);
gethrestime(&now);
}
}
if (datamodel == DATAMODEL_NATIVE) {
} else {
}
}
out:
if (t->t_mstate == LMS_USER_LOCK)
(void) new_mstate(t, LMS_SYSTEM);
return (error);
}
/*
* Unpark all of the specified lwps.
* Do it in chunks of MAXLWPIDS to avoid allocating too much memory.
*/
static int
{
kthread_t *t;
int error = 0;
int n;
int i;
if (nids <= 0)
return (EINVAL);
while (nids > 0) {
break;
}
for (i = 0; i < n; i++) {
} else {
mutex_enter(&t->t_delay_lock);
t->t_unpark = 1;
cv_signal(&t->t_delay_cv);
mutex_exit(&t->t_delay_lock);
mutex_exit(mp);
}
}
lwpidp += n;
nids -= n;
}
return (error);
}
/*
* SYS_lwp_park() system call.
*/
int
{
int error;
switch (which) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
/*
* This subcode is not used by libc. It exists ONLY to
* support older versions of libthread which do not use
* the sc_park flag in the schedctl page.
*
* These versions of libthread need to be modifed or emulated
* to change calls to syslwp_park(1, tid, 0) to
* syslwp_park(3, tid).
*/
break;
case 4:
/*
* This subcode is not used by libc. It exists ONLY to
* support older versions of libthread which do not use
* the sc_park flag in the schedctl page.
*
* These versions of libthread need to be modified or emulated
* to change calls to syslwp_park(0, ts, tid) to
* syslwp_park(4, ts, tid).
*/
break;
default:
break;
}
if (error)
return (0);
}