/*! * Send signal to thread (from thread) * \param pid Thread descriptor (user level descriptor) * \param signo Signal number * \param sigval Parameter to send with signal * \return 0 if successful, -1 otherwise and appropriate error number is set */ int sys__sigqueue ( void *p ) { pid_t pid; int signo; sigval_t sigval; pthread_t thread, sender; kthread_t *kthread; siginfo_t sig; pid = *( (pid_t *) p ); p += sizeof (pid_t); signo = *( (int *) p ); p += sizeof (int); sigval = *( (sigval_t *) p ); ASSERT_ERRNO_AND_EXIT ( signo > 0 && signo <= SIGMAX, EINVAL ); thread = (pthread_t) pid; /* pid_t should be pthread_t */ ASSERT_ERRNO_AND_EXIT ( thread.ptr, EINVAL ); kthread = thread.ptr; ASSERT_ERRNO_AND_EXIT ( kthread_get_id (kthread) == thread.id, EINVAL ); ASSERT_ERRNO_AND_EXIT ( kthread_check_kthread ( kthread ), EINVAL ); sender.id = kthread_get_id (NULL); sender.ptr = kthread_get_active (); sig.si_signo = signo; sig.si_value = sigval; sig.si_pid = sender; sig.si_code = SI_USER; sig.si_errno = 0; EXIT ( ksignal_queue ( kthread, &sig ) ); }
/*! * 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 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 ); }
/*! * Create new thread (params on user stack!) * \param thread User level thread descriptor * \param attr Thread attributes * \param start_routine Starting function for new thread * \param arg Parameter sent to starting function * (parameters are on calling thread stack) */ int sys__pthread_create ( void *p ) { pthread_t *thread; pthread_attr_t *attr; void *(*start_routine) (void *); void *arg; kthread_t *kthread; uint flags = 0; int sched_policy = SCHED_FIFO; int sched_priority = THREAD_DEF_PRIO; void *stackaddr = NULL; size_t stacksize = 0; thread = *( (pthread_t **) p ); p += sizeof (pthread_t *); attr = *( (pthread_attr_t **) p ); p += sizeof (pthread_attr_t *); start_routine = *( (void **) p ); p += sizeof (void *); arg = *( (void **) p ); if ( attr ) { flags = attr->flags; sched_policy = attr->sched_policy; sched_priority = attr->sched_params.sched_priority; stackaddr = attr->stackaddr; stacksize = attr->stacksize; ASSERT_ERRNO_AND_EXIT ( sched_policy >= 0 && sched_policy < SCHED_NUM, ENOTSUP ); ASSERT_ERRNO_AND_EXIT ( sched_priority >= THREAD_MIN_PRIO && sched_priority <= THREAD_MAX_PRIO, ENOMEM ); /* if ( flags & SOMETHING ) change attributes ... */ } kthread = kthread_create ( start_routine, arg, flags, sched_policy, sched_priority, stackaddr, stacksize ); ASSERT_ERRNO_AND_EXIT ( kthread, ENOMEM ); if ( thread ) { thread->ptr = kthread; thread->id = kthread_get_id (kthread); } SET_ERRNO ( EXIT_SUCCESS ); kthreads_schedule (); return EXIT_SUCCESS; }
/*! Return calling thread descriptor * \param thread Thread descriptor (user level descriptor) * \return 0 */ int sys__pthread_self ( pthread_t *thread ) { SYS_ENTRY(); ASSERT_ERRNO_AND_EXIT ( thread, ESRCH ); thread->ptr = kthread_get_active (); thread->id = kthread_get_id (NULL); SYS_EXIT ( EXIT_SUCCESS, EXIT_SUCCESS ); }
/*! Return calling thread descriptor * \param thread Thread descriptor (user level descriptor) * \return 0 */ int sys__pthread_self ( void *p ) { pthread_t *thread; thread = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( thread, ESRCH ); thread->ptr = kthread_get_active (); thread->id = kthread_get_id (NULL); EXIT ( EXIT_SUCCESS ); }
/*! * Create new thread (params on user stack!) * \param thread User level thread descriptor * \param attr Thread attributes * \param start_routine Starting function for new thread * \param arg Parameter sent to starting function * (parameters are on calling thread stack) */ int sys__pthread_create ( pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void *), void *arg ) { kthread_t *kthread; uint flags = 0; int sched_policy = SCHED_FIFO; int sched_priority = THREAD_DEF_PRIO; void *stackaddr = NULL; size_t stacksize = 0; SYS_ENTRY(); if ( attr ) { flags = attr->flags; sched_policy = attr->sched_policy; sched_priority = attr->sched_params.sched_priority; stackaddr = attr->stackaddr; stacksize = attr->stacksize; ASSERT_ERRNO_AND_EXIT ( sched_policy == SCHED_FIFO, ENOTSUP ); ASSERT_ERRNO_AND_EXIT ( sched_priority >= THREAD_MIN_PRIO && sched_priority <= THREAD_MAX_PRIO, ENOMEM ); /* if ( flags & SOMETHING ) change attributes ... */ } kthread = kthread_create ( start_routine, arg, flags, sched_policy, sched_priority, stackaddr, stacksize ); ASSERT_ERRNO_AND_EXIT ( kthread, ENOMEM ); if ( thread ) { thread->ptr = kthread; thread->id = kthread_get_id (kthread); } kthreads_schedule (); SYS_EXIT ( EXIT_SUCCESS, 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 ); } }
/*! 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; }