Пример #1
0
/*
 * sleepq_remove:
 *
 *	Remove an LWP from a sleep queue and wake it up.
 */
void
sleepq_remove(sleepq_t *sq, lwp_t *l)
{
	struct schedstate_percpu *spc;
	struct cpu_info *ci;

	KASSERT(lwp_locked(l, NULL));

	TAILQ_REMOVE(sq, l, l_sleepchain);
	l->l_syncobj = &sched_syncobj;
	l->l_wchan = NULL;
	l->l_sleepq = NULL;
	l->l_flag &= ~LW_SINTR;

	ci = l->l_cpu;
	spc = &ci->ci_schedstate;

	/*
	 * If not sleeping, the LWP must have been suspended.  Let whoever
	 * holds it stopped set it running again.
	 */
	if (l->l_stat != LSSLEEP) {
		KASSERT(l->l_stat == LSSTOP || l->l_stat == LSSUSPENDED);
		lwp_setlock(l, spc->spc_lwplock);
		return;
	}

	/*
	 * If the LWP is still on the CPU, mark it as LSONPROC.  It may be
	 * about to call mi_switch(), in which case it will yield.
	 */
	if ((l->l_pflag & LP_RUNNING) != 0) {
		l->l_stat = LSONPROC;
		l->l_slptime = 0;
		lwp_setlock(l, spc->spc_lwplock);
		return;
	}

	/* Update sleep time delta, call the wake-up handler of scheduler */
	l->l_slpticksum += (hardclock_ticks - l->l_slpticks);
	sched_wakeup(l);

	/* Look for a CPU to wake up */
	l->l_cpu = sched_takecpu(l);
	ci = l->l_cpu;
	spc = &ci->ci_schedstate;

	/*
	 * Set it running.
	 */
	spc_lock(ci);
	lwp_setlock(l, spc->spc_mutex);
	sched_setrunnable(l);
	l->l_stat = LSRUN;
	l->l_slptime = 0;
	sched_enqueue(l, false);
	spc_unlock(ci);
}
Пример #2
0
int
do_lwp_create(lwp_t *l, void *arg, u_long flags, lwpid_t *new_lwp)
{
	struct proc *p = l->l_proc;
	struct lwp *l2;
	struct schedstate_percpu *spc;
	vaddr_t uaddr;
	int error;

	/* XXX check against resource limits */

	uaddr = uvm_uarea_alloc();
	if (__predict_false(uaddr == 0))
		return ENOMEM;

	error = lwp_create(l, p, uaddr, flags & LWP_DETACHED,
	    NULL, 0, p->p_emul->e_startlwp, arg, &l2, l->l_class);
	if (__predict_false(error)) {
		uvm_uarea_free(uaddr);
		return error;
	}

	*new_lwp = l2->l_lid;

	/*
	 * Set the new LWP running, unless the caller has requested that
	 * it be created in suspended state.  If the process is stopping,
	 * then the LWP is created stopped.
	 */
	mutex_enter(p->p_lock);
	lwp_lock(l2);
	spc = &l2->l_cpu->ci_schedstate;
	if ((flags & LWP_SUSPENDED) == 0 &&
	    (l->l_flag & (LW_WREBOOT | LW_WSUSPEND | LW_WEXIT)) == 0) {
	    	if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0) {
			KASSERT(l2->l_wchan == NULL);
	    		l2->l_stat = LSSTOP;
			p->p_nrlwps--;
			lwp_unlock_to(l2, spc->spc_lwplock);
		} else {
			KASSERT(lwp_locked(l2, spc->spc_mutex));
			l2->l_stat = LSRUN;
			sched_enqueue(l2, false);
			lwp_unlock(l2);
		}
	} else {
		l2->l_stat = LSSUSPENDED;
		p->p_nrlwps--;
		lwp_unlock_to(l2, spc->spc_lwplock);
	}
	mutex_exit(p->p_lock);

	return 0;
}
Пример #3
0
void
cpu_signotify(struct lwp *l)
{
	KASSERT(kpreempt_disabled());
#ifdef __HAVE_FAST_SOFTINTS
	KASSERT(lwp_locked(l, NULL));
#endif
	KASSERT(l->l_stat == LSONPROC || l->l_stat == LSRUN || l->l_stat == LSSTOP);

	l->l_md.md_astpending = 1; 		/* force call to ast() */
}
Пример #4
0
/*
 * sleepq_unsleep:
 *
 *	Remove an LWP from its sleep queue and set it runnable again.
 *	sleepq_unsleep() is called with the LWP's mutex held, and will
 *	always release it.
 */
u_int
sleepq_unsleep(lwp_t *l, bool cleanup)
{
	sleepq_t *sq = l->l_sleepq;
	kmutex_t *mp = l->l_mutex;
	int swapin;

#ifndef T2EX
	KASSERT(lwp_locked(l, mp));
#endif
	KASSERT(l->l_wchan != NULL);

	swapin = sleepq_remove(sq, l);

	if (cleanup) {
		mutex_spin_exit(mp);
	}

	return swapin;
}
Пример #5
0
/*
 * sleepq_remove:
 *
 *	Remove an LWP from a sleep queue and wake it up.  Return non-zero if
 *	the LWP is swapped out; if so the caller needs to awaken the swapper
 *	to bring the LWP into memory.
 */
int
sleepq_remove(sleepq_t *sq, lwp_t *l)
{

	KASSERT(lwp_locked(l, NULL));

	TAILQ_REMOVE(sq, l, l_sleepchain);

#ifndef T2EX
	l->l_syncobj = NULL;
#endif
	l->l_wchan = NULL;
	l->l_sleepq = NULL;
#ifndef T2EX
	l->l_wmesg = NULL;
	l->l_slptime = 0;
#endif
	l->l_stat &= ~LSSLEEP;

	cv_broadcast(&sq_cv);

	return 0;
}
Пример #6
0
/* ARGSUSED */
int
sys__lwp_create(struct lwp *l, const struct sys__lwp_create_args *uap, register_t *retval)
{
	/* {
		syscallarg(const ucontext_t *) ucp;
		syscallarg(u_long) flags;
		syscallarg(lwpid_t *) new_lwp;
	} */
	struct proc *p = l->l_proc;
	struct lwp *l2;
	vaddr_t uaddr;
	bool inmem;
	ucontext_t *newuc;
	int error, lid;

#ifdef KERN_SA
	mutex_enter(p->p_lock);
	if ((p->p_sflag & (PS_SA | PS_WEXIT)) != 0 || p->p_sa != NULL) {
		mutex_exit(p->p_lock);
		return EINVAL;
	}
	mutex_exit(p->p_lock);
#endif

	newuc = pool_get(&lwp_uc_pool, PR_WAITOK);

	error = copyin(SCARG(uap, ucp), newuc, p->p_emul->e_ucsize);
	if (error) {
		pool_put(&lwp_uc_pool, newuc);
		return error;
	}

	/* XXX check against resource limits */

	inmem = uvm_uarea_alloc(&uaddr);
	if (__predict_false(uaddr == 0)) {
		pool_put(&lwp_uc_pool, newuc);
		return ENOMEM;
	}

	error = lwp_create(l, p, uaddr, inmem, SCARG(uap, flags) & LWP_DETACHED,
	    NULL, 0, p->p_emul->e_startlwp, newuc, &l2, l->l_class);
	if (error) {
		uvm_uarea_free(uaddr, curcpu());
		pool_put(&lwp_uc_pool, newuc);
		return error;
	}

	lid = l2->l_lid;
	error = copyout(&lid, SCARG(uap, new_lwp), sizeof(lid));
	if (error) {
		lwp_exit(l2);
		pool_put(&lwp_uc_pool, newuc);
		return error;
	}

	/*
	 * Set the new LWP running, unless the caller has requested that
	 * it be created in suspended state.  If the process is stopping,
	 * then the LWP is created stopped.
	 */
	mutex_enter(p->p_lock);
	lwp_lock(l2);
	if ((SCARG(uap, flags) & LWP_SUSPENDED) == 0 &&
	    (l->l_flag & (LW_WREBOOT | LW_WSUSPEND | LW_WEXIT)) == 0) {
	    	if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0)
	    		l2->l_stat = LSSTOP;
		else {
			KASSERT(lwp_locked(l2, l2->l_cpu->ci_schedstate.spc_mutex));
			p->p_nrlwps++;
			l2->l_stat = LSRUN;
			sched_enqueue(l2, false);
		}
		lwp_unlock(l2);
	} else {
		l2->l_stat = LSSUSPENDED;
		lwp_unlock_to(l2, l2->l_cpu->ci_schedstate.spc_lwplock);
	}
	mutex_exit(p->p_lock);

	return 0;
}
Пример #7
0
static int
linux_clone_nptl(struct lwp *l, const struct linux_sys_clone_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) flags;
		syscallarg(void *) stack;
		syscallarg(void *) parent_tidptr;
		syscallarg(void *) tls;
		syscallarg(void *) child_tidptr;
	} */
	struct proc *p;
	struct lwp *l2;
	struct linux_emuldata *led;
	void *parent_tidptr, *tls, *child_tidptr;
	struct schedstate_percpu *spc;
	vaddr_t uaddr;
	lwpid_t lid;
	int flags, tnprocs, error;

	p = l->l_proc;
	flags = SCARG(uap, flags);
	parent_tidptr = SCARG(uap, parent_tidptr);
	tls = SCARG(uap, tls);
	child_tidptr = SCARG(uap, child_tidptr);

	tnprocs = atomic_inc_uint_nv(&nprocs);
	if (__predict_false(tnprocs >= maxproc) ||
	    kauth_authorize_process(l->l_cred, KAUTH_PROCESS_FORK, p,
	    KAUTH_ARG(tnprocs), NULL, NULL) != 0) {
		atomic_dec_uint(&nprocs);
		return EAGAIN;
	}

	uaddr = uvm_uarea_alloc();
	if (__predict_false(uaddr == 0)) {
		atomic_dec_uint(&nprocs);
		return ENOMEM;
	}

	error = lwp_create(l, p, uaddr, LWP_DETACHED | LWP_PIDLID,
	    SCARG(uap, stack), 0, child_return, NULL, &l2, l->l_class);
	if (__predict_false(error)) {
		DPRINTF(("%s: lwp_create error=%d\n", __func__, error));
		atomic_dec_uint(&nprocs);
		uvm_uarea_free(uaddr);
		return error;
	}
	lid = l2->l_lid;

	/* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
	if (flags & LINUX_CLONE_CHILD_CLEARTID) {
		led = l2->l_emuldata;
		led->led_clear_tid = child_tidptr;
	}

	/* LINUX_CLONE_PARENT_SETTID: store child's TID in parent's memory */
	if (flags & LINUX_CLONE_PARENT_SETTID) {
		if ((error = copyout(&lid, parent_tidptr, sizeof(lid))) != 0)
			printf("%s: LINUX_CLONE_PARENT_SETTID "
			    "failed (parent_tidptr = %p tid = %d error=%d)\n",
			    __func__, parent_tidptr, lid, error);
	}

	/* LINUX_CLONE_CHILD_SETTID: store child's TID in child's memory  */
	if (flags & LINUX_CLONE_CHILD_SETTID) {
		if ((error = copyout(&lid, child_tidptr, sizeof(lid))) != 0)
			printf("%s: LINUX_CLONE_CHILD_SETTID "
			    "failed (child_tidptr = %p, tid = %d error=%d)\n",
			    __func__, child_tidptr, lid, error);
	}

	if (flags & LINUX_CLONE_SETTLS) {
		error = LINUX_LWP_SETPRIVATE(l2, tls);
		if (error) {
			DPRINTF(("%s: LINUX_LWP_SETPRIVATE %d\n", __func__,
			    error));
			lwp_exit(l2);
			return error;
		}
	}

	/*
	 * Set the new LWP running, unless the process is stopping,
	 * then the LWP is created stopped.
	 */
	mutex_enter(p->p_lock);
	lwp_lock(l2);
	spc = &l2->l_cpu->ci_schedstate;
	if ((l->l_flag & (LW_WREBOOT | LW_WSUSPEND | LW_WEXIT)) == 0) {
	    	if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0) {
			KASSERT(l2->l_wchan == NULL);
	    		l2->l_stat = LSSTOP;
			p->p_nrlwps--;
			lwp_unlock_to(l2, spc->spc_lwplock);
		} else {
			KASSERT(lwp_locked(l2, spc->spc_mutex));
			l2->l_stat = LSRUN;
			sched_enqueue(l2, false);
			lwp_unlock(l2);
		}
	} else {
		l2->l_stat = LSSUSPENDED;
		p->p_nrlwps--;
		lwp_unlock_to(l2, spc->spc_lwplock);
	}
	mutex_exit(p->p_lock);

	retval[0] = lid;
	retval[1] = 0;
	return 0;
}