/* * Routine: _wait_queue_select64_one * Purpose: * Select the best thread off a wait queue that meet the * supplied criteria. * Conditions: * at splsched * wait queue locked * possibly recursive * Returns: * a locked thread - if one found * Note: * This is where the sync policy of the wait queue comes * into effect. For now, we just assume FIFO. */ static thread_t _wait_queue_select64_one( wait_queue_t wq, event64_t event) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; thread_t t = THREAD_NULL; queue_t q; assert(wq->wq_fifo); q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_t set_queue; /* * We have to check the set wait queue. */ set_queue = (wait_queue_t)wql->wql_setqueue; wait_queue_lock(set_queue); if (! wait_queue_empty(set_queue)) { t = _wait_queue_select64_one(set_queue, event); } wait_queue_unlock(set_queue); if (t != THREAD_NULL) return t; } else { /* * Otherwise, its a thread. If it is waiting on * the event we are posting to this queue, pull * it off the queue and stick it in out wake_queue. */ thread_t t = (thread_t)wq_element; if (t->wait_event == event) { thread_lock(t); remqueue(q, (queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; return t; /* still locked */ } } wq_element = wqe_next; } return THREAD_NULL; }
static int recv_event(int *pid_store, int *event_store, timer_t *timer) { bool intr_flag; local_intr_save(intr_flag); wait_queue_t *wait_queue = &(current->event_box.wait_queue); if (wait_queue_empty(wait_queue)) { current->state = PROC_SLEEPING; current->wait_state = WT_EVENT_RECV; ipc_add_timer(timer); local_intr_restore(intr_flag); schedule(); local_intr_save(intr_flag); ipc_del_timer(timer); } int ret = -1; wait_t *wait; if ((wait = wait_queue_first(wait_queue)) != NULL) { struct proc_struct *proc = wait->proc; *pid_store = proc->pid, *event_store = proc->event_box.event, ret = 0; wakeup_wait(wait_queue, wait, WT_EVENT_SEND, 1); } local_intr_restore(intr_flag); return ret; }
/* * Routine: wait_queue_select64_thread * Purpose: * Look for a thread and remove it from the queues, if * (and only if) the thread is waiting on the supplied * <wait_queue, event> pair. * Conditions: * at splsched * wait queue locked * possibly recursive * Returns: * KERN_NOT_WAITING: Thread is not waiting here. * KERN_SUCCESS: It was, and is now removed (returned locked) */ static kern_return_t _wait_queue_select64_thread( wait_queue_t wq, event64_t event, thread_t thread) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; kern_return_t res = KERN_NOT_WAITING; queue_t q = &wq->wq_queue; thread_lock(thread); if ((thread->wait_queue == wq) && (thread->wait_event == event)) { remqueue((queue_entry_t) thread); thread->at_safe_point = FALSE; thread->wait_event = NO_EVENT64; thread->wait_queue = WAIT_QUEUE_NULL; /* thread still locked */ return KERN_SUCCESS; } thread_unlock(thread); /* * The wait_queue associated with the thread may be one of this * wait queue's sets. Go see. If so, removing it from * there is like removing it from here. */ wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); if (wq_element->wqe_type == WAIT_QUEUE_LINK || wq_element->wqe_type == WAIT_QUEUE_LINK_NOALLOC) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_set_t set_queue = wql->wql_setqueue; wqs_lock(set_queue); if (! wait_queue_empty(&set_queue->wqs_wait_queue)) { res = _wait_queue_select64_thread(&set_queue->wqs_wait_queue, event, thread); } wqs_unlock(set_queue); if (res == KERN_SUCCESS) return KERN_SUCCESS; } wq_element = wqe_next; } return res; }
void dev_stdin_write(char c) { bool intr_flag; if (c != '\0') { local_intr_save(intr_flag); { stdin_buffer[p_wpos % STDIN_BUFSIZE] = c; if (p_wpos - p_rpos < STDIN_BUFSIZE) { p_wpos ++; } if (!wait_queue_empty(wait_queue)) { wakeup_queue(wait_queue, WT_KBD, 1); } } local_intr_restore(intr_flag); } }
int ipc_sem_post_max(sem_t sem_id, int max) { assert(pls_read(current)->sem_queue != NULL); sem_undo_t *semu; sem_queue_t *sem_queue = pls_read(current)->sem_queue; down(&(sem_queue->sem)); semu = semu_list_search(&(sem_queue->semu_list), sem_id); up(&(sem_queue->sem)); if(semu != NULL) { int i; int ret = 0; for(i = 0; i < max; ++i) { if(wait_queue_empty(&(semu->sem->wait_queue))) break; usem_up(semu->sem); ++ret; } return ret; } return -E_INVAL; }
/* * Routine: semaphore_dereference * * Release a reference on a semaphore. If this is the last reference, * the semaphore data structure is deallocated. */ void semaphore_dereference( semaphore_t semaphore) { int ref_count; spl_t spl_level; if (semaphore != NULL) { spl_level = splsched(); semaphore_lock(semaphore); ref_count = --(semaphore->ref_count); semaphore_unlock(semaphore); splx(spl_level); if (ref_count == 0) { assert(wait_queue_empty(&semaphore->wait_queue)); zfree(semaphore_zone, semaphore); } } }
/* * Routine: _wait_queue_select64_one * Purpose: * Select the best thread off a wait queue that meet the * supplied criteria. * Conditions: * at splsched * wait queue locked * possibly recursive * Returns: * a locked thread - if one found * Note: * This is where the sync policy of the wait queue comes * into effect. For now, we just assume FIFO/LIFO. */ static thread_t _wait_queue_select64_one( wait_queue_t wq, event64_t event) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; thread_t t = THREAD_NULL; queue_t q; q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ if (wq_element->wqe_type == WAIT_QUEUE_LINK || wq_element->wqe_type == WAIT_QUEUE_LINK_NOALLOC) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_set_t set_queue = wql->wql_setqueue; /* * We have to check the set wait queue. If the set * supports pre-posting, it isn't already preposted, * and we didn't find a thread in the set, then mark it. * * If we later find a thread, there may be a spurious * pre-post here on this set. The wait side has to check * for that either pre- or post-wait. */ wqs_lock(set_queue); if (! wait_queue_empty(&set_queue->wqs_wait_queue)) { t = _wait_queue_select64_one(&set_queue->wqs_wait_queue, event); } if (t != THREAD_NULL) { wqs_unlock(set_queue); return t; } if (event == NO_EVENT64 && set_queue->wqs_prepost && !wql_is_preposted(wql)) { queue_t ppq = &set_queue->wqs_preposts; queue_enter(ppq, wql, wait_queue_link_t, wql_preposts); } wqs_unlock(set_queue); } else { /* * Otherwise, its a thread. If it is waiting on * the event we are posting to this queue, pull * it off the queue and stick it in out wake_queue. */ t = (thread_t)wq_element; if (t->wait_event == event) { thread_lock(t); remqueue((queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; return t; /* still locked */ } t = THREAD_NULL; } wq_element = wqe_next; } return THREAD_NULL; }
/* * Routine: _wait_queue_select64_all * Purpose: * Select all threads off a wait queue that meet the * supplied criteria. * Conditions: * at splsched * wait queue locked * wake_queue initialized and ready for insertion * possibly recursive * Returns: * a queue of locked threads */ static void _wait_queue_select64_all( wait_queue_t wq, event64_t event, queue_t wake_queue) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; queue_t q; q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ if (wq_element->wqe_type == WAIT_QUEUE_LINK || wq_element->wqe_type == WAIT_QUEUE_LINK_NOALLOC) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_set_t set_queue = wql->wql_setqueue; /* * We have to check the set wait queue. If it is marked * as pre-post, and it is the "generic event" then mark * it pre-posted now (if not already). */ wqs_lock(set_queue); if (event == NO_EVENT64 && set_queue->wqs_prepost && !wql_is_preposted(wql)) { queue_t ppq = &set_queue->wqs_preposts; queue_enter(ppq, wql, wait_queue_link_t, wql_preposts); } if (! wait_queue_empty(&set_queue->wqs_wait_queue)) _wait_queue_select64_all(&set_queue->wqs_wait_queue, event, wake_queue); wqs_unlock(set_queue); } else { /* * Otherwise, its a thread. If it is waiting on * the event we are posting to this queue, pull * it off the queue and stick it in out wake_queue. */ thread_t t = (thread_t)wq_element; if (t->wait_event == event) { thread_lock(t); remqueue((queue_entry_t) t); enqueue (wake_queue, (queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; /* returned locked */ } } wq_element = wqe_next; } }
/* * Routine: _wait_queue_select64_all * Purpose: * Select all threads off a wait queue that meet the * supplied criteria. * Conditions: * at splsched * wait queue locked * wake_queue initialized and ready for insertion * possibly recursive * Returns: * a queue of locked threads */ static void _wait_queue_select64_all( wait_queue_t wq, event64_t event, queue_t wake_queue) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; queue_t q; q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_t set_queue; /* * We have to check the set wait queue. */ set_queue = (wait_queue_t)wql->wql_setqueue; wait_queue_lock(set_queue); if (set_queue->wq_isprepost) { wait_queue_set_t wqs = (wait_queue_set_t)set_queue; /* * Preposting is only for sets and wait queue * is the first element of set */ wqs->wqs_refcount++; } if (! wait_queue_empty(set_queue)) _wait_queue_select64_all(set_queue, event, wake_queue); wait_queue_unlock(set_queue); } else { /* * Otherwise, its a thread. If it is waiting on * the event we are posting to this queue, pull * it off the queue and stick it in out wake_queue. */ thread_t t = (thread_t)wq_element; if (t->wait_event == event) { thread_lock(t); remqueue(q, (queue_entry_t) t); enqueue (wake_queue, (queue_entry_t) t); t->wait_queue = WAIT_QUEUE_NULL; t->wait_event = NO_EVENT64; t->at_safe_point = FALSE; /* returned locked */ } } wq_element = wqe_next; } }
/* * Routine: wait_queue_peek64_locked * Purpose: * Select the best thread from a wait queue that meet the * supplied criteria, but leave it on the queue it was * found on. The thread, and the actual wait_queue the * thread was found on are identified. * Conditions: * at splsched * wait queue locked * possibly recursive * Returns: * a locked thread - if one found * a locked waitq - the one the thread was found on * Note: * Both the waitq the thread was actually found on, and * the supplied wait queue, are locked after this. */ __private_extern__ void wait_queue_peek64_locked( wait_queue_t wq, event64_t event, thread_t *tp, wait_queue_t *wqp) { wait_queue_element_t wq_element; wait_queue_element_t wqe_next; thread_t t; queue_t q; assert(wq->wq_fifo); *tp = THREAD_NULL; q = &wq->wq_queue; wq_element = (wait_queue_element_t) queue_first(q); while (!queue_end(q, (queue_entry_t)wq_element)) { WAIT_QUEUE_ELEMENT_CHECK(wq, wq_element); wqe_next = (wait_queue_element_t) queue_next((queue_t) wq_element); /* * We may have to recurse if this is a compound wait queue. */ if (wq_element->wqe_type == WAIT_QUEUE_LINK) { wait_queue_link_t wql = (wait_queue_link_t)wq_element; wait_queue_t set_queue; /* * We have to check the set wait queue. */ set_queue = (wait_queue_t)wql->wql_setqueue; wait_queue_lock(set_queue); if (! wait_queue_empty(set_queue)) { wait_queue_peek64_locked(set_queue, event, tp, wqp); } if (*tp != THREAD_NULL) { if (*wqp != set_queue) wait_queue_unlock(set_queue); return; /* thread and its waitq locked */ } wait_queue_unlock(set_queue); } else { /* * Otherwise, its a thread. If it is waiting on * the event we are posting to this queue, return * it locked, but leave it on the queue. */ thread_t t = (thread_t)wq_element; if (t->wait_event == event) { thread_lock(t); *tp = t; *wqp = wq; return; } } wq_element = wqe_next; } }
int exec_line(int argc, char *argv[]) { struct alias *al; int i; if(!argc) return 0; ui_print("do action: "); for(i = 0; i < argc; i++) ui_print("%s ", argv[i]); ui_print("\n"); if(strcmp(argv[0], "load") == 0) { ui_animation(1); } else if(strcmp(argv[0], "unload") == 0) { ui_animation(3); } else if(strcmp(argv[0], "poweron") == 0) { power_state = 1; } else if(strcmp(argv[0], "poweroff") == 0) { power_state = 1; } else if(strcmp(argv[0], "putbin") == 0) { for(i = 0;;) { al = get_alias("bin", i++); if(al) ui_bin_update(i, al->arg); else break; } al = get_alias("timeout", 0); if(al) ui_bin_update(i, al->arg); } else if(strncmp(argv[0], "send", 4) == 0) { if(strcmp(argv[0], "send_txt") == 0) { io_send("\002"); ui_print("--> <STX>\n"); } for(i = 1; i < argc; i++) { const char *s = argv[i]; if(strcmp(s, "power_state") == 0) s = power_state? "1": "NULL"; al = get_alias(s, 0); ui_print("--> %s\n", al? al->str: s); io_send(al? al->str: s); } if(strcmp(argv[0], "send_txt") == 0) { io_send("\003"); ui_print("--> <ETX>\n"); } } else if(strcmp(argv[0], "wait") == 0) { for(i = 1; i < argc; i++) wait_queue_add_tail(argv[i]); for(;!wait_queue_empty(); ui_animation(2)); } else if(strcmp(argv[0], "wait_timeout") == 0) { struct timeval a, b, d; int t; al = get_alias("timeout", 0); t = al? al->num: TIMEOUT; for(i = 1; i < argc; i++) wait_queue_add_tail(argv[i]); gettimeofday(&a, NULL); for(;!wait_queue_empty(); ui_animation(2)) { gettimeofday(&b, NULL); timersub(&b, &a, &d); if(d.tv_sec > t) { ui_print("timeout for waiting %s\n", wait_queue_head()); al->arg++; return -1; } } } else if(strcmp(argv[0], "handshake") == 0) { char word[SZ]; ui_print("--> %s\n", argv[1]); io_send(argv[1]); while(io_get_word(word) <= 0); ui_print("<-- %s\n", word); if(strcmp(word, argv[2]) != 0) return -1; } return 0; }