/*! * Block thread (on conditional variable) and release monitor */ int sys__monitor_wait ( monitor_t *monitor, monitor_q *queue ) { kmonitor_t *kmonitor; kmonitor_q *kqueue; ASSERT_ERRNO_AND_EXIT ( monitor && monitor->ptr, E_INVALID_HANDLE ); ASSERT_ERRNO_AND_EXIT ( queue && queue->ptr, E_INVALID_HANDLE ); kmonitor = monitor->ptr; kqueue = queue->ptr; ASSERT_ERRNO_AND_EXIT ( kmonitor->owner == k_get_active_thread (), E_NOT_OWNER ); disable_interrupts (); SET_ERRNO ( SUCCESS ); k_set_thread_qdata ( NULL, kmonitor ); k_enqueue_thread ( NULL, &kqueue->queue ); kmonitor->owner = k_threadq_get ( &kmonitor->queue ); if ( !k_release_thread ( &kmonitor->queue ) ) kmonitor->lock = FALSE; k_schedule_threads (); enable_interrupts (); EXIT ( SUCCESS ); }
/* Add alarm to alarm pool if its expiration time is defined If expiration time is in the past, alarm will be immediately activated! */ static void k_alarm_add ( kalarm_t *kalarm ) { int reschedule = 0; /* if exp_time is given (>0) add it into active alarms */ if ( kalarm->alarm.exp_time.sec + kalarm->alarm.exp_time.nsec > 0 ) { kalarm->active = 1; list_sort_add ( &kalarms, kalarm, &kalarm->list, alarm_cmp ); } else { kalarm->active = 0; } reschedule = k_schedule_alarms (); /* this or other alarm may expire */ SET_ERRNO ( SUCCESS ); /* block thread? */ if ( kalarm->active && ( kalarm->alarm.flags & IPC_WAIT ) ) { k_enqueue_thread ( NULL, &kalarm->queue ); reschedule = 1; } if ( reschedule ) k_schedule_threads (); }
/*! * Lock monitor (or block trying) */ int sys__monitor_lock ( monitor_t *monitor ) { kmonitor_t *kmonitor; ASSERT_ERRNO_AND_EXIT ( monitor && monitor->ptr, E_INVALID_HANDLE ); disable_interrupts (); kmonitor = monitor->ptr; SET_ERRNO ( SUCCESS ); if ( !kmonitor->lock ) { kmonitor->lock = TRUE; kmonitor->owner = k_get_active_thread (); } else { k_enqueue_thread ( NULL, &kmonitor->queue ); k_schedule_threads (); } enable_interrupts (); 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; }
/*! Lock device */ int k_device_lock ( kdevice_t *dev, int wait ) { if ( !wait && dev->locked ) return -1; if ( dev->locked ) { k_enqueue_thread ( NULL, &dev->thrq ); k_schedule_threads (); } dev->locked = TRUE; return 0; }
/*! Release first or all threads from monitor queue (cond.var.) */ static int k_monitor_release ( monitor_q *queue, int broadcast ) { kmonitor_q *kqueue; kthread_t *kthr; kmonitor_t *kmonitor; int reschedule = 0; ASSERT_ERRNO_AND_EXIT ( queue && queue->ptr, E_INVALID_HANDLE ); disable_interrupts (); kqueue = queue->ptr; do { kthr = k_threadq_get ( &kqueue->queue ); /* first from queue */ if ( !kthr ) break; kmonitor = k_get_thread_qdata ( kthr ); if ( !kmonitor->lock ) /* monitor not locked? */ { /* unblocked thread becomes monitor owner */ kmonitor->lock = TRUE; kmonitor->owner = kthr; k_release_thread ( &kqueue->queue );/*to ready threads*/ reschedule++; } else { /* move thread from monitor queue (cond.var.) to monitor entrance queue */ kthr = k_threadq_remove ( &kqueue->queue, NULL ); k_enqueue_thread ( kthr, &kmonitor->queue ); } } while ( kthr && broadcast ); SET_ERRNO ( SUCCESS ); if ( reschedule ) k_schedule_threads (); enable_interrupts (); EXIT ( SUCCESS ); }
//int sys__wait_for_alarm ( void *alarm, int wait ) int sys__wait_for_alarm ( void *p ) { void *id; int wait; kalarm_t *kalarm; int retval; id = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( id, E_INVALID_HANDLE ); p += sizeof (void *); wait = *( (int *) p ); kalarm = id; ASSERT_ERRNO_AND_EXIT ( kalarm && kalarm->magic == ALARM_MAGIC, E_INVALID_HANDLE ); retval = 0; SET_ERRNO ( SUCCESS ); if ( kalarm->active ) { if ( wait & IPC_WAIT ) { k_enqueue_thread ( NULL, &kalarm->queue ); k_schedule_threads (); } else { SET_ERRNO ( E_NOT_EXPIRED ); retval = -E_NOT_EXPIRED; } } return retval; }
/*! * 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 ); } }
/*! Receive message from queue (global or from own thread message queue) */ int sys__msg_recv ( int src_type, void *src, msg_t *msg, int type, size_t size, uint flags ) { kthread_t *kthr; kthrmsg_qs *thrmsg; kgmsg_q *kgmsgq; kmsg_q *kmsgq; msg_q *msgq; kmsg_t *kmsg; SYS_ENTRY(); ASSERT_ERRNO_AND_SYS_EXIT ( src_type == MSG_THREAD || ( src_type == MSG_QUEUE && src ), E_INVALID_TYPE ); ASSERT_ERRNO_AND_SYS_EXIT ( msg && size > 0, E_INVALID_HANDLE ); 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_SYS_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; SYS_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 ); SYS_EXIT ( SUCCESS ); } else { /* queue empty! */ if ( !( flags & IPC_WAIT ) ) SYS_EXIT ( E_EMPTY ); //SET_ERRNO ( E_RETRY ); /* block thread */ k_enqueue_thread ( NULL, &kmsgq->thrq ); k_schedule_threads (); SYS_EXIT ( E_RETRY ); } }