/*! * Change scheduling parameters * \param thread User level thread descriptor * \param policy Thread scheduling policy * \param param Additional scheduling parameters (when policy != SCHED_FIFO) * \return 0 */ int sys__pthread_setschedparam ( void *p ) { pthread_t *thread; int policy; sched_param_t *param; kthread_t *kthread; thread = *( (pthread_t **) p ); p += sizeof (pthread_t *); policy = *( (int *) p ); p += sizeof (int); param = *( (sched_param_t **) p ); kthread = thread->ptr; ASSERT_ERRNO_AND_EXIT ( kthread, EINVAL ); ASSERT_ERRNO_AND_EXIT ( kthread_get_id (kthread) == thread->id, ESRCH ); ASSERT_ERRNO_AND_EXIT ( kthread_is_alive (kthread), ESRCH ); ASSERT_ERRNO_AND_EXIT ( policy >= 0 && policy < SCHED_NUM, EINVAL ); if ( param ) { ASSERT_ERRNO_AND_EXIT ( param->sched_priority >= THREAD_MIN_PRIO && param->sched_priority <= THREAD_MAX_PRIO, EINVAL ); } return kthread_setschedparam ( kthread, policy, param ); }
/*! Change thread scheduling parameters ------------------------------------- */ int kthread_setschedparam (kthread_t *kthread, int policy, sched_param_t *param) { int sched_priority; ASSERT_ERRNO_AND_EXIT ( kthread, EINVAL ); ASSERT_ERRNO_AND_EXIT ( kthread_is_alive (kthread), ESRCH ); ASSERT_ERRNO_AND_EXIT ( policy >= 0 && policy < SCHED_NUM, EINVAL ); if ( param ) { ASSERT_ERRNO_AND_EXIT ( param->sched_priority >= THREAD_MIN_PRIO && param->sched_priority <= THREAD_MAX_PRIO, EINVAL ); if ( param->sched_priority ) sched_priority = param->sched_priority; else sched_priority = kthread->sched_priority; } else { sched_priority = kthread->sched_priority; } /* change in priority? */ if ( kthread->sched_priority != sched_priority ) kthread_set_prio ( kthread, sched_priority ); return EXIT_SUCCESS; }
/*! * Change scheduling parameters * \param thread User level thread descriptor * \param policy Thread scheduling policy * \param param Additional scheduling parameters (when policy != SCHED_FIFO) * \return 0 */ int sys__pthread_setschedparam ( pthread_t *thread, int policy, sched_param_t *param ) { kthread_t *kthread; int retval; SYS_ENTRY(); kthread = thread->ptr; ASSERT_ERRNO_AND_EXIT ( kthread, EINVAL ); ASSERT_ERRNO_AND_EXIT ( kthread_get_id (kthread) == thread->id, ESRCH ); ASSERT_ERRNO_AND_EXIT ( kthread_is_alive (kthread), ESRCH ); ASSERT_ERRNO_AND_EXIT ( policy == SCHED_FIFO, ENOTSUP ); if ( param ) { ASSERT_ERRNO_AND_EXIT ( param->sched_priority >= THREAD_MIN_PRIO && param->sched_priority <= THREAD_MAX_PRIO, EINVAL ); } retval = kthread_setschedparam ( kthread, policy, param ); if ( retval == EXIT_SUCCESS ) SYS_EXIT ( EXIT_SUCCESS, retval ); else SYS_EXIT ( retval, EXIT_FAILURE ); }
/*! * Deactivate thread because: * 1. higher priority thread becomes active * 2. this thread blocks on some queue (not in edf_ready) */ static int edf_thread_deactivate ( ksched_t *ksched, kthread_t *kthread ) { if ( kthread_is_alive (kthread) && !kthread_is_ready (kthread) && kthread_get_queue (kthread) != &ksched->params.edf.ready && kthread_get_queue (kthread) != &ksched->params.edf.wait ) { /* if kthread is blocked, but not in edf.ready */ ksched->params.edf.active = NULL; edf_schedule ( ksched ); } return 0; }
/*! Change thread scheduling parameters ------------------------------------- */ int kthread_setschedparam (kthread_t *kthread, int policy, sched_param_t *param) { int sched_priority; sched_supp_t *supp; ASSERT_AND_RETURN_ERRNO ( kthread, EINVAL ); ASSERT_AND_RETURN_ERRNO ( kthread_is_alive (kthread), ESRCH ); ASSERT_AND_RETURN_ERRNO ( policy >= 0 && policy < SCHED_NUM, EINVAL ); if ( param ) { ASSERT_AND_RETURN_ERRNO ( param->sched_priority >= THREAD_MIN_PRIO && param->sched_priority <= THREAD_MAX_PRIO, EINVAL ); if ( param->sched_priority ) sched_priority = param->sched_priority; else sched_priority = kthread->sched_priority; supp = ¶m->supp; } else { sched_priority = kthread->sched_priority; supp = NULL; } /* change in priority? */ if ( kthread->sched_priority != sched_priority ) kthread_set_prio ( kthread, sched_priority ); /* change in scheduling policy? */ if ( kthread->sched_policy != policy ) { ksched2_thread_remove ( kthread ); ksched2_schedule ( kthread->sched_policy ); kthread->sched_policy = policy; ksched2_thread_add ( kthread, policy, sched_priority, supp ); ksched2_schedule ( kthread->sched_policy ); } else if ( supp ) /* if policy changed, parameters are already given */ { ksched2_setsched_param ( kthread, supp ); } return EXIT_SUCCESS; }
/*! * Wait for thread termination * \param thread Thread descriptor (user level descriptor) * \param retval Where to store exit status of joined thread * \return 0 if thread already gone; -1 if not finished and 'wait' not set; * 'thread exit status' otherwise */ int sys__pthread_join ( void *p ) { pthread_t *thread; void **retval; kthread_t *kthread; int ret_value = 0; thread = *( (pthread_t **) p ); p += sizeof (pthread_t *); retval = *( (void ***) p ); ASSERT_ERRNO_AND_EXIT ( thread, ESRCH ); kthread = thread->ptr; if ( kthread_get_id (kthread) != thread->id ) { /* at 'kthread' is now something else */ ret_value = EXIT_FAILURE; SET_ERRNO ( ESRCH ); } else if ( kthread_is_alive (kthread) ) { ret_value = EXIT_SUCCESS; SET_ERRNO ( EXIT_SUCCESS ); kthread_set_private_param ( kthread_get_active(), retval ); kthread_wait_thread ( NULL, kthread ); kthreads_schedule (); } else { /* target thread is passive, collect status and free descr. */ ret_value = EXIT_SUCCESS; SET_ERRNO ( EXIT_SUCCESS ); kthread_collect_status ( kthread, retval ); } return ret_value; }
/*! * Wait for thread termination * \param thread Thread descriptor (user level descriptor) * \param retval Where to store exit status of joined thread * \return 0 if thread already gone; -1 if not finished and 'wait' not set; * 'thread exit status' otherwise */ int sys__pthread_join ( pthread_t *thread, void **retval ) { kthread_t *kthread; SYS_ENTRY(); ASSERT_ERRNO_AND_EXIT ( thread, ESRCH ); kthread = thread->ptr; if ( kthread_get_id (kthread) != thread->id ) { /* at 'kthread' is now something else */ SYS_EXIT ( ESRCH, EXIT_FAILURE ); } else if ( kthread_is_alive (kthread) ) { kthread_set_errno ( NULL, EXIT_SUCCESS ); kthread_set_syscall_retval ( NULL, EXIT_SUCCESS ); kthread_set_private_param ( kthread_get_active(), retval ); kthread_wait_thread ( NULL, kthread ); kthreads_schedule (); SYS_EXIT ( kthread_get_errno(NULL), kthread_get_syscall_retval(NULL) ); } else { /* target thread is passive, collect status and free descr. */ kthread_collect_status ( kthread, retval ); SYS_EXIT ( EXIT_SUCCESS, EXIT_SUCCESS ); } }
/*! Send signal to target thread */ int ksignal_queue ( kthread_t *kthread, siginfo_t *sig ) { int enqueue = FALSE; int retval = EXIT_SUCCESS; int schedule = FALSE; ksignal_handling_t *sh; sigaction_t *act; void (*func) (kthread_t *, void *), *param; kprocess_t *proc; siginfo_t *us; param_t param1, param2, param3; ASSERT ( kthread ); ASSERT ( kthread_check_kthread ( kthread ) ); ASSERT ( sig->si_signo > 0 && sig->si_signo <= SIGMAX ); if ( !kthread_is_alive ( kthread ) ) return ESRCH; sh = kthread_get_sigparams ( kthread ); /* is thread suspended and waits for this signal? */ if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) && ((void *) func) == ((void *) ksignal_received_signal) ) { /* thread is waiting for signal */ if ( !ksignal_received_signal ( kthread, sig ) ) { /* waited for this signal */ /* do not process this signal further */ return EXIT_SUCCESS; } } /* * If thread is in interruptable state and signal is not masked: * - process signal * - otherwise queue it */ if ( kthread_get_interruptable ( kthread ) && !sigtestset ( sh->mask, sig->si_signo ) ) { act = &sh->act[sig->si_signo]; if ( act->sa_flags != SA_SIGINFO ) return ENOTSUP; /* not supported without SA_SIGINFO! */ if ( act->sa_sigaction == SIG_ERR || act->sa_sigaction == SIG_DFL || act->sa_sigaction == SIG_IGN || act->sa_sigaction == SIG_HOLD ) { return ENOTSUP; /* not yet supported */ } if ( !kthread_is_ready ( kthread ) ) { /* * thread is suspended/blocked on something else * * 1. handle interruption: * a) we break suspend/wait state * (call cancel function) * b) set errno = EINTR * c) set return value = FAILURE * 2. create new thread state * a) process signal in this state */ void (*func) (kthread_t *, void *), *param; kthread_is_suspended (kthread, (void **) &func, ¶m); if ( func ) func ( kthread, param ); kthread_move_to_ready ( kthread, LAST ); kthread_set_errno ( kthread, EINTR ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); /* thread is unsuspended, but signal * handler will be added first */ schedule = TRUE; } /* copy sig to user space */ proc = kthread_get_process ( kthread ); us = kprocess_stack_alloc ( proc ); ASSERT (us); /*if ( !us ) return ENOMEM;*/ *us = *sig; kthread_create_new_state ( kthread, act->sa_sigaction, K2U_GET_ADR ( us, proc ), NULL, HANDLER_STACK_SIZE, TRUE ); param1.p_ptr = proc; param2.p_ptr = us; param3.p_ptr = NULL; kthread_add_cleanup ( kthread, kprocess_stack_free, param1, param2, param3 ); /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* mask additional signals in thread mask */ sigaddsets ( sh->mask, &act->sa_mask ); } else { enqueue = TRUE; } if ( enqueue ) { ksignal_add_to_pending ( sh, sig ); retval = EAGAIN; } if ( schedule ) kthreads_schedule (); return retval; }
/*! Process event defined with sigevent_t */ int ksignal_process_event ( sigevent_t *evp, kthread_t *kthread, int code ) { int retval = EXIT_SUCCESS; kthread_t *target = kthread; siginfo_t sig; pid_t pid; void (*func) ( sigval_t ); ASSERT ( evp && kthread ); switch ( evp->sigev_notify ) { case SIGEV_WAKE_THREAD: func = evp->sigev_notify_function; func ( evp->sigev_value ); break; case SIGEV_NONE: break; case SIGEV_THREAD_ID: pid = evp->sigev_notify_thread_id; target = pid.ptr; if ( !target || !kthread_is_alive (target) || pid.id != kthread_get_id (target) ) return ESRCH; case SIGEV_SIGNAL: sig.si_signo = evp->sigev_signo; sig.si_value = evp->sigev_value; sig.si_code = code; sig.si_errno = 0; sig.si_pid.id = kthread_get_id ( kthread ); sig.si_pid.ptr = kthread; retval = ksignal_queue ( target, &sig ); break; case SIGEV_THREAD: if ( evp->sigev_notify_function ) { if ( !kthread_create ( evp->sigev_notify_function, evp->sigev_value.sival_ptr, 0, SCHED_FIFO, THREAD_DEF_PRIO, NULL, 0, kthread_get_process(kthread) ) ) retval = EINVAL; } else { retval = EINVAL; } break; default: retval = EINVAL; break; } return retval; }
/*! Send signal to target thread */ int ksignal_queue ( kthread_t *kthread, siginfo_t *sig ) { int enqueue = FALSE; int retval = EXIT_SUCCESS; int schedule = FALSE; ksignal_handling_t *sh; sigaction_t *act; void (*func) (kthread_t *, void *), *param; kprocess_t *proc; siginfo_t *us; param_t param1, param2, param3; ksiginfo_t *ksig; ASSERT ( kthread ); ASSERT ( kthread_check_kthread ( kthread ) ); ASSERT ( sig->si_signo > 0 && sig->si_signo <= SIGMAX ); if ( !kthread_is_alive ( kthread ) ) return ESRCH; sh = kthread_get_sigparams ( kthread ); /* is thread suspended and waits for this signal? */ if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) ) { if ( ((void *) func) == ((void *) ksignal_received_signal) ) { /* thread is waiting for signal */ if ( !ksignal_received_signal ( kthread, sig ) ) { /* waited for this signal */ /* should continue with signal handler also? */ /* do not process this signal further */ return EXIT_SUCCESS; } } /* else { * thread is waiting for something else; * deal with this later (in next "if") * } */ } /* if signal is not masked in thread signal mask, deliver signal */ if ( !sigtestset ( sh->mask, sig->si_signo ) ) { act = &sh->act[sig->si_signo]; if ( act->sa_flags != SA_SIGINFO ) return ENOTSUP; /* not supported without SA_SIGINFO! */ if ( act->sa_sigaction == SIG_ERR || act->sa_sigaction == SIG_DFL || act->sa_sigaction == SIG_IGN || act->sa_sigaction == SIG_HOLD ) { return ENOTSUP; /* not yet supported */ } /* current implementation * - if thread is active or ready * -- save old context in list * -- create new context * - else * -- enqueue signal or cancel wait state (todo) * * on sys__exit check if its handler or thread!!! */ if ( !kthread_is_ready ( kthread ) ) { void (*func) (kthread_t *, void *), *param; if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) ) { /* * thread is suspended on something * else; interrupt it or not? * * -handle interruption (kernel part) * -interrupt it (resume) * -process signal * * to do above just move thread to * ready, set errno & retval */ if ( func ) func ( kthread, param ); kthread_move_to_ready ( kthread, LAST ); kthread_set_errno ( kthread, EINTR ); kthread_set_syscall_retval(kthread,EXIT_FAILURE); /* thread is unsuspended, but signal * handler will be added first */ schedule = TRUE; } else { /* what else? this is error */ ASSERT ( FALSE ); } } /* copy sig to user space */ proc = kthread_get_process ( kthread ); us = ffs_alloc(proc->stack_pool, sizeof (siginfo_t)); ASSERT (us); /*if ( !us ) return ENOMEM;*/ *us = *sig; kthread_create_new_state ( kthread, act->sa_sigaction, K2U_GET_ADR ( us, proc ), NULL, HANDLER_STACK_SIZE, TRUE ); param1.p_ptr = proc->stack_pool; param2.p_ptr = us; param3.p_ptr = NULL; kthread_add_cleanup ( kthread, kthread_param_free, param1, param2, param3 ); /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* mask additional signals in thread mask */ sigaddsets ( sh->mask, &act->sa_mask ); } else { enqueue = TRUE; } if ( enqueue ) { /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* add signal to list of pending signals */ ksig = kmalloc ( sizeof (ksiginfo_t) ); ksig->siginfo = *sig; list_append ( &sh->pending_signals, ksig, &ksig->list ); /* list_sort_add ( &sh->pending_signals, ksig, &ksig->list, ksignal_compare ); */ retval = EAGAIN; } if ( schedule ) kthreads_schedule (); return retval; }