/*! * Wait for signal * \param set Signals thread is waiting for * \param info Where to save caught signal * \return signal number if signal is caught, * -1 otherwise and appropriate error number is set */ int sys__sigwaitinfo ( void *p ) { sigset_t *set; siginfo_t *info; kthread_t *kthread; ksignal_handling_t *sh; ksiginfo_t *ksig, *next; int retval; set = *( (sigset_t **) p ); p += sizeof (sigset_t *); info = *( (siginfo_t **) p ); ASSERT_ERRNO_AND_EXIT ( set, EINVAL ); set = U2K_GET_ADR ( set, kthread_get_process (NULL) ); ASSERT_ERRNO_AND_EXIT ( set, EINVAL ); if ( info ) info = U2K_GET_ADR ( info, kthread_get_process (NULL) ); kthread = kthread_get_active (); sh = kthread_get_sigparams ( kthread ); /* first, search for such signal in pending signals */ ksig = list_get ( &sh->pending_signals, FIRST ); while ( ksig ) { next = list_get_next ( &ksig->list ); if ( sigtestset ( set, ksig->siginfo.si_signo ) ) { retval = ksig->siginfo.si_signo; if ( info ) *info = ksig->siginfo; list_remove ( &sh->pending_signals, 0, &ksig->list ); kfree ( ksig ); EXIT2 ( EXIT_SUCCESS, retval ); } ksig = next; } /* * if no pending signal found that matches given mask * suspend thread until signal is received */ kthread_suspend ( kthread, ksignal_received_signal, NULL ); kthreads_schedule (); EXIT ( EINTR ); /* if other events wake thread */ }
int sys__device_open ( void *p ) { char *dev_name; void **dev; dev_name = U2K_GET_ADR ( *( (char **) p ), kthread_get_process (NULL) ); p += sizeof (char *); dev = U2K_GET_ADR ( *( (void **) p ), kthread_get_process (NULL) ); *dev = k_device_open ( dev_name ); return *dev == NULL; }
/*! * Modify thread signal mask * \param how How to modify current must * \param set Mask to use in modification * \param oset Where to store old mask * \return 0 if successful, -1 otherwise and appropriate error number is set */ int sys__pthread_sigmask ( void *p ) { int how; sigset_t *set; sigset_t *oset; ksignal_handling_t *sh; int retval = EXIT_SUCCESS; how = *( (int *) p ); p += sizeof (int); set = *( (sigset_t **) p ); p += sizeof (sigset_t *); oset = *( (sigset_t **) p ); ASSERT_ERRNO_AND_EXIT ( set, EINVAL ); set = U2K_GET_ADR ( set, kthread_get_process (NULL) ); ASSERT_ERRNO_AND_EXIT ( set, EINVAL ); sh = kthread_get_sigparams ( NULL ); if (oset) oset = U2K_GET_ADR ( oset, kthread_get_process (NULL) ); if (oset) *oset = *sh->mask; switch ( how ) { case SIG_BLOCK: sigaddsets ( sh->mask, set ); break; case SIG_UNBLOCK: sigaddsets ( sh->mask, set ); break; case SIG_SETMASK: *sh->mask = *set; break; default: retval = EINVAL; } /* reevaluate pending signals with new mask */ if ( retval == EXIT_SUCCESS ) retval = ksignal_process_pending ( kthread_get_active () ); EXIT ( retval ); }
/*! * Delete global message queue */ int sys__delete_msg_queue ( void *p ) { /* parameter on thread stack */ msg_q *msgq; /* local variables */ kgmsg_q *gmsgq; msgq = *( (msg_q **) p ); ASSERT_ERRNO_AND_EXIT ( msgq, E_INVALID_HANDLE ); msgq = U2K_GET_ADR ( msgq, k_get_active_process () ); gmsgq = msgq->handle; ASSERT_ERRNO_AND_EXIT ( gmsgq->id == msgq->id, E_INVALID_HANDLE ); k_msgq_clean ( &gmsgq->mq ); k_release_all_threads ( &gmsgq->mq.thrq ); k_free_unique_id ( gmsgq->id ); kfree ( gmsgq ); msgq->id = 0; msgq->handle = NULL; EXIT ( SUCCESS ); }
/*! * Create new thread (params on user stack!) * \param func Starting function * \param param Parameter for starting function * \param prio Priority for new thread * \param thr_desc User level thread descriptor * (parameters are on calling thread stack) */ int sys__create_thread ( void *p ) { void *func; void *param; int prio; thread_t *thr_desc; kthread_t *kthr; func = *( (void **) p ); p += sizeof (void *); param = *( (void **) p ); p += sizeof (void *); prio = *( (int *) p ); p += sizeof (int); kthr = k_create_thread (func, param, active_thread->proc->pi->exit, prio, NULL, 0, 1, active_thread->proc ); ASSERT_ERRNO_AND_EXIT ( kthr, E_NO_MEMORY ); thr_desc = *( (void **) p ); if ( thr_desc ) { thr_desc = U2K_GET_ADR ( thr_desc, active_thread->proc ); thr_desc->thread = kthr; thr_desc->thr_id = kthr->id; } SET_ERRNO ( SUCCESS ); k_schedule_threads (); RETURN ( SUCCESS ); }
/*! * Create global message queue */ int sys__create_msg_queue ( void *p ) { /* parameters on thread stack */ msg_q *msgq; uint min_prio; /* local variables */ kgmsg_q *gmsgq; msgq = *( (msg_q **) p ); p += sizeof (msg_q *); min_prio = *( (uint *) p ); ASSERT_ERRNO_AND_EXIT ( msgq, E_INVALID_HANDLE ); msgq = U2K_GET_ADR ( msgq, k_get_active_process () ); gmsgq = kmalloc ( sizeof ( kgmsg_q ) ); ASSERT_ERRNO_AND_EXIT ( gmsgq, E_NO_MEMORY ); list_init ( &gmsgq->mq.msgs ); /* list for messages */ k_threadq_init ( &gmsgq->mq.thrq ); /* list for blocked threads */ gmsgq->mq.min_prio = min_prio; msgq->id = gmsgq->id = k_new_unique_id (); msgq->handle = gmsgq; list_append ( &kmsg_qs, gmsgq, &gmsgq->all ); /* all msg.q. list */ EXIT ( SUCCESS ); }
/*! * Modify thread signal mask * \param sig Signal number * \param act Signal handling behavior * \param oact Where to save old signal behavior * \return 0 if successful, -1 otherwise and appropriate error number is set */ int sys__sigaction ( void *p ) { int sig; sigaction_t *act; sigaction_t *oact; ksignal_handling_t *sh; sig = *( (int *) p ); p += sizeof (int); act = *( (sigaction_t **) p ); p += sizeof (sigaction_t *); oact = *( (sigaction_t **) p ); ASSERT_ERRNO_AND_EXIT ( sig > 0 && sig <= SIGMAX, EINVAL ); if ( act ) act = U2K_GET_ADR ( act, kthread_get_process (NULL) ); if ( oact ) oact = U2K_GET_ADR ( oact, kthread_get_process (NULL) ); sh = kthread_get_sigparams ( NULL ); if ( oact ) *oact = sh->act[sig]; if ( act ) { if ( !( act->sa_flags & SA_SIGINFO ) ) EXIT ( ENOTSUP ); if ( act->sa_sigaction == SIG_ERR || act->sa_sigaction == SIG_DFL || act->sa_sigaction == SIG_IGN || act->sa_sigaction == SIG_HOLD ) { EXIT ( ENOTSUP ); } sh->act[sig] = *act; sigdelset ( sh->mask, sig ); /* accept sig */ /* reevaluate pending signals with changed behavior */ ksignal_process_pending ( kthread_get_active () ); } EXIT ( EXIT_SUCCESS ); }
//int sys__alarm_new ( alarm_t *alarm ) int sys__alarm_new ( void *p ) { void **id; alarm_t *alarm; id = *( (void **) p ); p += sizeof ( void *); alarm = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE ); id = U2K_GET_ADR ( id, k_get_active_process() ); alarm = U2K_GET_ADR ( alarm, k_get_active_process() ); ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE ); return k_alarm_new ( id, alarm ); }
/*! Return calling thread descriptor * \param thread Thread descriptor (user level descriptor) * \return 0 */ int sys__thread_self ( void *p ) { thread_t *thread; thread = U2K_GET_ADR ( *( (void **) p ), active_thread->proc ); ASSERT_ERRNO_AND_EXIT ( thread, E_INVALID_HANDLE ); thread->thread = active_thread; thread->thr_id = active_thread->id; EXIT ( SUCCESS ); }
/*! * Wait for thread termination * \param thread Thread descriptor (user level descriptor) * \param wait Wait if thread not finished (!=0) or not (0)? * \return 0 if thread already gone; -1 if not finished and 'wait' not set; * 'thread exit status' otherwise */ int sys__wait_for_thread ( void *p ) { thread_t *thread; int wait; kthread_t *kthr; int ret_value = 0; thread = U2K_GET_ADR ( *( (void **) p ), active_thread->proc ); p += sizeof (void *); wait = *( (int *) p ); ASSERT_ERRNO_AND_EXIT ( thread && thread->thread, E_INVALID_HANDLE ); kthr = thread->thread; if ( kthr->id != thread->thr_id ) /* at 'kthr' is now something else */ { ret_value = -SUCCESS; SET_ERRNO ( SUCCESS ); } else if ( kthr->state != THR_STATE_PASSIVE && !wait ) { ret_value = -E_NOT_FINISHED; SET_ERRNO ( E_NOT_FINISHED ); } else if ( kthr->state != THR_STATE_PASSIVE ) { kthr->ref_cnt++; ret_value = -E_RETRY; /* retry (collect thread status) */ SET_ERRNO ( E_RETRY ); k_enqueue_thread ( NULL, &kthr->join_queue ); k_schedule_threads (); } else { /* kthr->state == THR_STATE_PASSIVE, but thread descriptor still not freed - some thread still must collect its status */ SET_ERRNO ( SUCCESS ); ret_value = kthr->exit_status; kthr->ref_cnt--; if ( !kthr->ref_cnt ) k_remove_thread_descriptor ( kthr ); } return ret_value; }
//int sys__get_time ( time_t *time ) int sys__get_time ( void *p ) { time_t *time; time = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( time, E_INVALID_HANDLE ); time = U2K_GET_ADR ( time, k_get_active_process() ); k_get_time ( time ); EXIT ( SUCCESS ); }
/*! * Cancel some other thread * \param thread Thread descriptor (user) */ int sys__cancel_thread ( void *p ) { thread_t *thread; kthread_t *kthr; int ret_value = -1; thread = U2K_GET_ADR ( *( (void **) p ), active_thread->proc ); ASSERT_ERRNO_AND_EXIT ( thread && thread->thread, E_INVALID_HANDLE ); kthr = thread->thread; if ( kthr->id != thread->thr_id ) EXIT ( SUCCESS ); /* thread is already finished */ /* remove thread from queue where its descriptor is */ switch ( kthr->state ) { case THR_STATE_PASSIVE: EXIT ( SUCCESS ); /* thread is already finished */ case THR_STATE_READY: case THR_STATE_WAIT: SET_ERRNO ( SUCCESS ); /* temporary move calling thread (active) to ready */ move_to_ready ( active_thread ); /* remove target 'thread' from its queue */ k_threadq_remove ( kthr->queue, kthr ); if ( kthr->state == THR_STATE_READY && k_threadq_get( &ready_q[kthr->sched.prio] ) == NULL ) clear_got_ready ( kthr->sched.prio ); /* mark it as active and 'end' it normally */ active_thread = kthr; active_thread->state = THR_STATE_ACTIVE; active_thread->queue = NULL; return sys__thread_exit ( &ret_value ); case THR_STATE_ACTIVE: default: EXIT ( E_INVALID_HANDLE ); /* thread descriptor corrupted ! */ } }
int sys__device_recv ( void *p ) { void *data; size_t size; int flags; kdevice_t *dev; data = U2K_GET_ADR ( *( (void **) p ), kthread_get_process (NULL) ); p += sizeof (void *); size = *( (size_t *) p ); p += sizeof (size_t); flags = *( (int *) p ); p += sizeof (int); dev = *( (void **) p ); return k_device_recv ( data, size, flags, dev ); }
/*! * Retrieve parameters for existing alarm (get its values) * \param alarm Pointer where alarm parameters will be stored * \returns status (0 for success) */ int sys__alarm_get ( void *p ) { void *id; alarm_t *alarm; kalarm_t *kalarm; id = *( (void **) p ); p += sizeof ( void *); alarm = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE ); alarm = U2K_GET_ADR ( alarm, k_get_active_process() ); kalarm = id; ASSERT_ERRNO_AND_EXIT ( kalarm && kalarm->magic == ALARM_MAGIC, E_INVALID_HANDLE ); *alarm = kalarm->alarm; EXIT ( SUCCESS ); }
/*! initialize thread structures and create idle thread */ void kthreads_init () { extern kprog_t prog; int prio; list_init ( &all_threads ); active_thread = NULL; ksched_init (); /* initially create 'idle thread' */ kernel_proc.prog = NULL; kernel_proc.stack_pool = NULL; /* use kernel pool */ kernel_proc.m.start = NULL; kernel_proc.m.size = (size_t) 0xffffffff; (void) kthread_create ( idle_thread, NULL, 0, SCHED_FIFO, 0, NULL, NULL, 0, &kernel_proc ); /* user_proc */ user_proc.prog = &prog; user_proc.m.size = prog.m->size; user_proc.m.start = user_proc.pi = prog.pi; /* initialize memory pool for threads stacks */ user_proc.stack_pool = ffs_init ( U2K_GET_ADR ( user_proc.pi->stack, &user_proc ), (size_t) prog.pi->end_adr - (size_t) prog.pi->stack + 1 ); prio = prog.pi->prio; if ( !prio ) prio = THREAD_DEF_PRIO; kthread_create ( user_proc.pi->init, NULL, 0, SCHED_FIFO, prio, NULL, NULL, 0, &user_proc ); kthreads_schedule (); }
/*! * Start program defined by 'prog' (loaded as module) as new process: * - initialize environment (stack area for threads, stdin, stdout) and start * it's first thread * \param prog_name Program name (as given with module) * \param param Command line arguments for starting thread (if not NULL) * \param prio Priority for starting thread * \return Pointer to descriptor of created process */ kthread_t *k_proc_start ( char *prog_name, void *param, int prio ) { extern kdevice_t *u_stdin, *u_stdout; extern list_t progs; kprog_t *prog; kprocess_t *proc; kthread_t *kthr; char **args = NULL, *arg, *karg, **kargs; size_t argsize; int i; prog = list_get ( &progs, FIRST ); while ( prog && strcmp ( prog->prog_name, prog_name ) ) prog = list_get_next ( &prog->all ); if ( !prog ) return NULL; if ( prog->started ) return NULL; /* create new process */ proc = kmalloc ( sizeof ( kprocess_t) ); ASSERT ( proc ); proc->prog = prog; proc->m.size = prog->m.size; proc->m.start = proc->pi = prog->pi; proc->pi->stdin = u_stdin; proc->pi->stdout = u_stdout; /* initialize memory pool for threads stacks */ proc->stack_pool = ffs_init ( U2K_GET_ADR ( proc->pi->stack, proc ), prog->pi->stack_size ); proc->thr_count = 0; if ( !prio ) prio = proc->pi->prio; if ( !prio ) prio = THR_DEFAULT_PRIO; if ( param ) /* have arguments? */ { /* copy command line arguments from kernel space to process; (use process stack space for arguments) */ kargs = param; for ( i = 0; kargs[i]; i++ ) ; argsize = ( (size_t) kargs[i-1] + strlen( kargs[i-1] ) + 1 ) - (size_t) param; if ( argsize > 0 ) { args = ffs_alloc ( proc->stack_pool, argsize ); arg = (void *) args + (i + 1) * sizeof (void *); kargs = param; i = 0; do { karg = kargs[i]; strcpy ( arg, karg ); args[i++] = K2U_GET_ADR ( arg, proc ); arg += strlen ( arg ) + 1; } while ( kargs[i] ); args[i] = NULL; args = K2U_GET_ADR ( args, proc ); } kfree ( param ); } kthr = k_create_thread ( proc->pi->init, args, NULL, prio, NULL, 0, 1, proc ); list_append ( &procs, proc, &proc->all ); prog->started = 1; k_schedule_threads (); return kthr; }
/*! * Start new process * \param prog_name Program name (as given with module) * \param thr_desc Pointer to thread descriptor (user) for starting thread * \param param Command line arguments for starting thread (if not NULL) * \param prio Priority for starting thread */ int sys__start_program ( void *p ) { char *prog_name; void *param; int prio; thread_t *thr_desc; kthread_t *kthr, *cur = active_thread; char *arg, *karg, **args, **kargs = NULL; int argnum, argsize; prog_name = *( (void **) p ); p += sizeof (void *); ASSERT_ERRNO_AND_EXIT ( prog_name, E_INVALID_HANDLE ); prog_name = U2K_GET_ADR ( prog_name, cur->proc ); thr_desc = *( (void **) p ); p += sizeof (void *); param = *( (void **) p ); p += sizeof (void *); prio = *( (int *) p ); if ( param ) /* copy parameters from one process space to another */ { /* copy parameters to new process address space */ /* first copy them to kernel */ argnum = 0; argsize = 0; args = U2K_GET_ADR ( param, cur->proc ); while ( args[argnum] ) { arg = U2K_GET_ADR ( args[argnum++], cur->proc ); argsize += strlen ( arg ) + 1; } if ( argnum > 0 ) { kargs = kmalloc ( (argnum + 1) * sizeof (void *) + argsize ); karg = (void *) kargs + (argnum + 1) * sizeof (void *); argnum = 0; while ( args[argnum] ) { arg = U2K_GET_ADR ( args[argnum], cur->proc ); strcpy ( karg, arg ); kargs[argnum++] = karg; karg += strlen ( karg ) + 1; } kargs[argnum] = NULL; } } SET_ERRNO ( SUCCESS ); kthr = k_proc_start ( prog_name, kargs, prio ); if ( !kthr ) EXIT ( E_NO_MEMORY ); if ( thr_desc ) /* save thread descriptor */ { thr_desc = U2K_GET_ADR ( thr_desc, cur->proc ); thr_desc->thread = kthr; thr_desc->thr_id = kthr->id; } RETURN ( SUCCESS ); }
/*! Callback function called when a signal is delivered to suspended thread */ static int ksignal_received_signal ( kthread_t *kthread, void *param ) { siginfo_t *sig; context_t *context; uint sysid; void *p; sigset_t *set; siginfo_t *info; int retval = EXIT_SUCCESS; ASSERT ( kthread ); /* thread waked by signal or other event? */ if ( param == NULL ) { kthread_set_errno ( kthread, EINTR ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); return EXIT_FAILURE; /* other event interrupted thread */ } /* signal interrupted, but did thread waited for this signal? */ sig = param; /* get syscall which caused thread to be suspend */ context = kthread_get_context ( kthread ); sysid = arch_syscall_get_id ( context ); switch ( sysid ) { case SIGWAITINFO: /* sigwaitinfo */ p = arch_syscall_get_params ( context ); set = *( (sigset_t **) p ); p += sizeof (sigset_t *); info = *( (siginfo_t **) p ); p += sizeof (siginfo_t *); ASSERT ( set ); set = U2K_GET_ADR ( set, kthread_get_process (NULL) ); ASSERT ( set ); if ( info ) info = U2K_GET_ADR ( info, kthread_get_process (NULL) ); retval = EXIT_FAILURE; if ( sigtestset ( set, sig->si_signo ) ) { retval = sig->si_signo; kthread_set_syscall_retval ( kthread, retval ); if ( info ) *info = *sig; kthread_set_errno ( kthread, EXIT_SUCCESS ); /* resume with thread */ kthread_move_to_ready ( kthread, LAST ); kthreads_schedule (); return EXIT_SUCCESS; } else { /* not waiting for this signal */ return EXIT_FAILURE; } default: return EXIT_FAILURE; } }
/*! printf (or return) system information (and details) */ int sys__sysinfo ( void *p ) { char *buffer; size_t buf_size; char **param; /* last param is NULL */ char *param1; /* *param0; */ char usage[] = "Usage: sysinfo [programs|threads|memory]"; char look_console[] = "(sysinfo printed on console)"; buffer = *( (char **) p ); p += sizeof (char *); ASSERT_ERRNO_AND_EXIT ( buffer, EINVAL ); buffer = U2K_GET_ADR ( buffer, kthread_get_process (NULL) ); buf_size = *( (size_t *) p ); p += sizeof (size_t *); param = *( (char ***) p ); param = U2K_GET_ADR ( param, kthread_get_process (NULL) ); /* param0 = U2K_GET_ADR ( param[0], kthread_get_process (NULL) ); -- param0 should be "sysinfo" so actualy its not required */ if ( param[1] == NULL ) { /* only basic info defined in kernel/startup.c */ extern char system_info[]; if ( strlen ( system_info ) > buf_size ) EXIT ( ENOMEM ); strcpy ( buffer, system_info ); EXIT ( EXIT_SUCCESS ); } else { param1 = U2K_GET_ADR ( param[1], kthread_get_process (NULL) ); /* extended info is requested */ if ( strcmp ( "programs", param1 ) == 0 ) { EXIT ( k_list_programs ( buffer, buf_size ) ); /* TODO: "program prog_name" => print help_msg */ } else if ( strcmp ( "memory", param1 ) == 0 ) { k_memory_info (); if ( strlen ( look_console ) > buf_size ) EXIT ( ENOMEM ); strcpy ( buffer, look_console ); EXIT ( EXIT_SUCCESS ); /* TODO: "memory [segments|modules|***]" */ } else if ( strcmp ( "threads", param1 ) == 0 ) { kthread_info (); if ( strlen ( look_console ) > buf_size ) EXIT ( ENOMEM ); strcpy ( buffer, look_console ); EXIT ( EXIT_SUCCESS ); /* TODO: "thread id" */ } else { if ( strlen ( usage ) > buf_size ) EXIT ( ENOMEM ); strcpy ( buffer, usage ); EXIT ( ESRCH ); } } }
/*! * Send message to queue or signal to thread */ int sys__msg_post ( void *p ) { /* parameters on thread stack */ int dest_type; /* MSG_QUEUE, MSG_THREAD or MSG_SIGNAL */ void *dest; /* (msg_q *) or (thread_t *) */ msg_t *msg; /* { type, size, data[0..size-1] } */ uint flags; /* local variables */ thread_t *thr; kthread_t *kthr, *new_kthr; kthrmsg_qs *thrmsg; kgmsg_q *kgmsgq; kmsg_q *kmsgq; msg_q *msgq; kmsg_t *kmsg; msg_t *cmsg; kprocess_t *proc; dest_type = *( (int *) p ); p += sizeof (int); dest = *( (void **) p ); p += sizeof (void *); msg = *( (msg_t **) p ); p += sizeof (msg_t *); flags = *( (uint *) p ); ASSERT_ERRNO_AND_EXIT ( dest && msg, E_INVALID_HANDLE ); dest = U2K_GET_ADR ( dest, k_get_active_process () ); msg = U2K_GET_ADR ( msg, k_get_active_process () ); if ( dest_type == MSG_THREAD || dest_type == MSG_SIGNAL ) { thr = dest; kthr = k_get_kthread ( thr ); ASSERT_ERRNO_AND_EXIT ( kthr, E_DONT_EXIST ); thrmsg = k_get_thrmsg ( kthr ); kmsgq = &thrmsg->msgq; } else if ( dest_type == MSG_QUEUE ) { msgq = dest; kgmsgq = msgq->handle; ASSERT_ERRNO_AND_EXIT ( kgmsgq && kgmsgq->id == msgq->id, E_INVALID_HANDLE ); kmsgq = &kgmsgq->mq; } else { EXIT ( E_INVALID_TYPE ); } if ( dest_type == MSG_THREAD || dest_type == MSG_QUEUE ) { /* send message to queue */ if ( kmsgq->min_prio <= msg->type ) /* msg has required prio. */ { kmsg = kmalloc ( sizeof (kmsg_t) + msg->size ); ASSERT_ERRNO_AND_EXIT ( kmsg, E_NO_MEMORY ); kmsg->msg.type = msg->type; kmsg->msg.size = msg->size; memcpy ( kmsg->msg.data, msg->data, msg->size ); list_append ( &kmsgq->msgs, kmsg, &kmsg->list ); /* is thread waiting for message? */ if ( k_release_thread ( &kmsgq->thrq ) ) k_schedule_threads (); EXIT ( SUCCESS ); } else { /* ignore message */ EXIT ( E_IGNORED ); } } /* must be MSG_SIGNAL */ if ( thrmsg->sig_prio <= msg->type ) { /* create thread that will service this signal */ cmsg = k_create_thread_private_storage ( kthr, sizeof (msg_t) + msg->size ); cmsg->type = msg->type; cmsg->size = msg->size; memcpy ( cmsg->data, msg->data, msg->size ); proc = k_get_thread_process ( kthr ); new_kthr = k_create_thread ( thrmsg->signal_handler, K2U_GET_ADR ( cmsg, proc ), proc->pi->exit, k_get_thread_prio ( kthr ) + 1, NULL, 0, 1, proc ); ASSERT_ERRNO_AND_EXIT ( new_kthr, k_get_errno() ); k_set_thread_private_storage ( new_kthr, cmsg ); SET_ERRNO ( SUCCESS ); k_schedule_threads (); RETURN ( SUCCESS ); } else { /* ignore signal */ EXIT ( E_IGNORED ); } }
/*! * Receive message from queue (global or from own thread message queue) */ int sys__msg_recv ( void *p ) { /* parameters on thread stack */ int src_type; /* MSG_QUEUE or MSG_THREAD */ void *src; /* (msg_q *) or (thread_t *) */ msg_t *msg; /* { type, size, data[0..size-1] } */ int type; /* message type (identifier) */ size_t size; /* size of 'data' member */ uint flags; /* local variables */ kthread_t *kthr; kthrmsg_qs *thrmsg; kgmsg_q *kgmsgq; kmsg_q *kmsgq; msg_q *msgq; kmsg_t *kmsg; src_type = *( (int *) p ); p += sizeof (int); src = *( (void **) p ); p += sizeof (void *); msg = *( (msg_t **) p ); p += sizeof (msg_t *); type = *( (int *) p ); p += sizeof (int); size = *( (size_t *) p ); p += sizeof (size_t); flags = *( (uint *) p ); ASSERT_ERRNO_AND_EXIT ( src && msg, E_INVALID_HANDLE ); src = U2K_GET_ADR ( src, k_get_active_process () ); msg = U2K_GET_ADR ( msg, k_get_active_process () ); ASSERT_ERRNO_AND_EXIT ( src_type == MSG_THREAD || src_type == MSG_QUEUE, E_INVALID_TYPE ); if ( src_type == MSG_THREAD ) { kthr = k_get_active_thread (); thrmsg = k_get_thrmsg ( kthr ); kmsgq = &thrmsg->msgq; } else { /* src_type == MSG_QUEUE */ msgq = src; kgmsgq = msgq->handle; ASSERT_ERRNO_AND_EXIT ( kgmsgq && kgmsgq->id == msgq->id, E_INVALID_HANDLE ); kmsgq = &kgmsgq->mq; } /* get first message from queue */ kmsg = list_get ( &kmsgq->msgs, FIRST ); if ( type != 0 ) /* type != 0 => search for first message 'type' */ while ( kmsg && kmsg->msg.type != type ) kmsg = list_get_next ( &kmsg->list ); if ( kmsg ) /* have message */ { if ( size < kmsg->msg.size ) { msg->size = 0; EXIT ( E_TOO_BIG ); } msg->type = kmsg->msg.type; msg->size = kmsg->msg.size; memcpy ( msg->data, kmsg->msg.data, msg->size ); kmsg = list_remove ( &kmsgq->msgs, FIRST, &kmsg->list ); ASSERT ( kmsg ); kfree ( kmsg ); EXIT ( SUCCESS ); } else { /* queue empty! */ if ( !( flags & IPC_WAIT ) ) EXIT ( E_EMPTY ); SET_ERRNO ( E_RETRY ); /* block thread */ k_enqueue_thread ( NULL, &kmsgq->thrq ); k_schedule_threads (); RETURN ( E_RETRY ); } }