/*! * Process syscalls * (syscall is forwarded from arch interrupt subsystem to k_syscall) */ void k_syscall ( uint irqn ) { int id, retval; void *act_thr, *context, *params; ASSERT ( irqn == SOFTWARE_INTERRUPT ); act_thr = k_get_active_thread (); context = k_get_thread_context ( act_thr ); id = arch_syscall_get_id ( context ); ASSERT ( id >= 0 && id < SYSFUNCS ); params = arch_syscall_get_params ( context ); retval = k_sysfunc[id] ( params ); if ( id != THREAD_EXIT ) arch_syscall_set_retval ( context, retval ); }
static int kmq_send ( void *p, kthread_t *sender ) { mqd_t *mqdes; char *msg_ptr; size_t msg_len; uint msg_prio; kmq_queue_t *kq_queue; kobject_t *kobj; kmq_msg_t *kmq_msg; kthread_t *kthread; int retval; mqdes = *( (mqd_t **) p ); p += sizeof (mqd_t *); msg_ptr = *( (char **) p ); p += sizeof (char *); msg_len = *( (size_t *) p ); p += sizeof (size_t); msg_prio = *( (uint *) p ); ASSERT_ERRNO_AND_EXIT ( mqdes && msg_ptr, EINVAL ); ASSERT_ERRNO_AND_EXIT ( msg_prio <= MQ_PRIO_MAX, EINVAL ); kobj = mqdes->ptr; ASSERT_ERRNO_AND_EXIT ( kobj, EBADF ); ASSERT_ERRNO_AND_EXIT ( list_find ( &kobjects, &kobj->list ), EBADF ); kq_queue = kobj->kobject; ASSERT_ERRNO_AND_EXIT ( kq_queue->id == mqdes->id, EBADF ); ASSERT_ERRNO_AND_EXIT ( list_find ( &kmq_queue, &kq_queue->list ), EBADF ); if ( kq_queue->attr.mq_curmsgs >= kq_queue->attr.mq_maxmsg ) { if ( (kobj->flags & O_NONBLOCK) ) return EAGAIN; /* block thread */ kthread_enqueue ( sender, &kq_queue->send_q, 1, NULL, NULL ); kthreads_schedule (); return EAGAIN; } if ( msg_len > kq_queue->attr.mq_msgsize ) return EMSGSIZE; kmq_msg = kmalloc ( sizeof (kmq_msg_t) + msg_len ); ASSERT_ERRNO_AND_EXIT ( kmq_msg, ENOMEM ); /* create message */ kmq_msg->msg_size = msg_len; kmq_msg->msg_prio = msg_prio; memcpy ( &kmq_msg->msg_data[0], msg_ptr, msg_len ); list_sort_add ( &kq_queue->msg_list, kmq_msg, &kmq_msg->list, ( int (*)(void *, void *) ) cmp_mq_msg ); kq_queue->attr.mq_curmsgs++; /* is there a blocked receiver? */ if ( (kthread = kthreadq_remove ( &kq_queue->recv_q, NULL )) ) { /* "save" sender thread */ kthread_move_to_ready ( sender, FIRST ); kthread_set_errno ( sender, EXIT_SUCCESS ); kthread_set_syscall_retval ( sender, EXIT_SUCCESS ); /* unblock receiver */ kthread_set_active ( kthread ); /* temporary */ p = arch_syscall_get_params ( kthread_get_context (kthread) ); retval = kmq_receive ( p, kthread ); if ( retval >= 0 ) { kthread_set_errno ( kthread, EXIT_SUCCESS ); kthread_set_syscall_retval ( kthread, retval ); } else { kthread_set_errno ( kthread, -retval ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); } kthreads_schedule (); } return EXIT_SUCCESS; }
static int kmq_receive ( void *p, kthread_t *receiver ) { mqd_t *mqdes; char *msg_ptr; size_t msg_len; uint *msg_prio; kmq_queue_t *kq_queue; kobject_t *kobj; kmq_msg_t *kmq_msg; kthread_t *kthread; int retval; mqdes = *( (mqd_t **) p ); p += sizeof (mqd_t *); msg_ptr = *( (char **) p ); p += sizeof (char *); msg_len = *( (size_t *) p ); p += sizeof (size_t); msg_prio = *( (uint **) p ); ASSERT_ERRNO_AND_EXIT ( mqdes && msg_ptr, -EINVAL ); kobj = mqdes->ptr; ASSERT_ERRNO_AND_EXIT ( kobj, -EBADF ); ASSERT_ERRNO_AND_EXIT ( list_find ( &kobjects, &kobj->list ), -EBADF ); kq_queue = kobj->kobject; ASSERT_ERRNO_AND_EXIT ( kq_queue->id == mqdes->id, -EBADF ); ASSERT_ERRNO_AND_EXIT ( list_find ( &kmq_queue, &kq_queue->list ), -EBADF ); if ( kq_queue->attr.mq_curmsgs == 0 ) { if ( (kobj->flags & O_NONBLOCK) ) return -EAGAIN; /* block thread */ kthread_enqueue ( receiver, &kq_queue->recv_q, 1, NULL, NULL ); kthreads_schedule (); return -EAGAIN; } if ( msg_len < kq_queue->attr.mq_msgsize ) return -EMSGSIZE; kmq_msg = list_remove ( &kq_queue->msg_list, FIRST, NULL ); memcpy ( msg_ptr, &kmq_msg->msg_data[0], kmq_msg->msg_size ); msg_len = kmq_msg->msg_size; if ( msg_prio ) *msg_prio = kmq_msg->msg_prio; kfree (kmq_msg); kq_queue->attr.mq_curmsgs--; /* is there a blocked sender? */ if ( (kthread = kthreadq_remove ( &kq_queue->send_q, NULL )) ) { /* "save" receiver thread */ kthread_move_to_ready ( receiver, FIRST ); kthread_set_errno ( receiver, EXIT_SUCCESS ); kthread_set_syscall_retval ( receiver, msg_len ); /* unblock sender */ kthread_set_active ( kthread ); /* temporary */ p = arch_syscall_get_params ( kthread_get_context (kthread) ); retval = kmq_send ( p, kthread ); if ( retval == EXIT_SUCCESS ) { kthread_set_errno ( kthread, EXIT_SUCCESS ); kthread_set_syscall_retval ( kthread, retval ); } else { kthread_set_errno ( kthread, retval ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); } kthreads_schedule (); } return msg_len; }
/*! 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; } }