From a8968330aff45e0b8cf278f49fa337d5fcb9bfd8 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Fri, 28 Mar 2014 17:09:15 +0100 Subject: Import and compile code for article 6.5 --- sos-code-article6.5/sos/kwaitq.c | 249 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 sos-code-article6.5/sos/kwaitq.c (limited to 'sos-code-article6.5/sos/kwaitq.c') diff --git a/sos-code-article6.5/sos/kwaitq.c b/sos-code-article6.5/sos/kwaitq.c new file mode 100644 index 0000000..b4a451e --- /dev/null +++ b/sos-code-article6.5/sos/kwaitq.c @@ -0,0 +1,249 @@ +/* Copyright (C) 2004 David Decotigny + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. +*/ + +#include +#include +#include +#include + +#include "kwaitq.h" + + +sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, + const char *name) +{ + memset(kwq, 0x0, sizeof(struct sos_kwaitq)); + +#ifdef SOS_KWQ_DEBUG + if (! name) + name = ""; + strzcpy(kwq->name, name, SOS_KWQ_DEBUG_MAX_NAMELEN); +#endif + list_init_named(kwq->waiting_list, + prev_entry_in_kwaitq, next_entry_in_kwaitq); + + return SOS_OK; +} + + +sos_ret_t sos_kwaitq_dispose(struct sos_kwaitq *kwq) +{ + sos_ui32_t flags; + sos_ret_t retval; + + sos_disable_IRQs(flags); + if (list_is_empty_named(kwq->waiting_list, + prev_entry_in_kwaitq, next_entry_in_kwaitq)) + retval = SOS_OK; + else + retval = -SOS_EBUSY; + + sos_restore_IRQs(flags); + return retval; +} + + +sos_bool_t sos_kwaitq_is_empty(const struct sos_kwaitq *kwq) +{ + sos_ui32_t flags; + sos_ret_t retval; + + sos_disable_IRQs(flags); + retval = list_is_empty_named(kwq->waiting_list, + prev_entry_in_kwaitq, next_entry_in_kwaitq); + + sos_restore_IRQs(flags); + return retval; +} + + +sos_ret_t sos_kwaitq_init_entry(struct sos_kwaitq_entry *kwq_entry) +{ + memset(kwq_entry, 0x0, sizeof(struct sos_kwaitq_entry)); + kwq_entry->thread = sos_thread_get_current(); + return SOS_OK; +} + + +/** Internal helper function equivalent to sos_kwaitq_add_entry(), but + without interrupt protection scheme, and explicit priority + ordering */ +inline static sos_ret_t _kwaitq_add_entry(struct sos_kwaitq *kwq, + struct sos_kwaitq_entry *kwq_entry) +{ + /* This entry is already added in the kwaitq ! */ + SOS_ASSERT_FATAL(NULL == kwq_entry->kwaitq); + + /* sos_kwaitq_init_entry() has not been called ?! */ + SOS_ASSERT_FATAL(NULL != kwq_entry->thread); + + /* (Re-)Initialize wakeup status of the entry */ + kwq_entry->wakeup_triggered = FALSE; + kwq_entry->wakeup_status = SOS_OK; + + /* Add the thread in the list */ + list_add_tail_named(kwq->waiting_list, kwq_entry, + prev_entry_in_kwaitq, next_entry_in_kwaitq); + + /* Update the list of waitqueues for the thread */ + list_add_tail_named(kwq_entry->thread->kwaitq_list, kwq_entry, + prev_entry_for_thread, next_entry_for_thread); + + kwq_entry->kwaitq = kwq; + + return SOS_OK; +} + + +sos_ret_t sos_kwaitq_add_entry(struct sos_kwaitq *kwq, + struct sos_kwaitq_entry *kwq_entry) +{ + sos_ui32_t flags; + sos_ret_t retval; + + sos_disable_IRQs(flags); + retval = _kwaitq_add_entry(kwq, kwq_entry); + sos_restore_IRQs(flags); + + return retval; +} + + +/** Internal helper function equivalent to sos_kwaitq_remove_entry(), + but without interrupt protection scheme */ +inline static sos_ret_t +_kwaitq_remove_entry(struct sos_kwaitq *kwq, + struct sos_kwaitq_entry *kwq_entry) +{ + SOS_ASSERT_FATAL(kwq_entry->kwaitq == kwq); + + list_delete_named(kwq->waiting_list, kwq_entry, + prev_entry_in_kwaitq, next_entry_in_kwaitq); + + list_delete_named(kwq_entry->thread->kwaitq_list, kwq_entry, + prev_entry_for_thread, next_entry_for_thread); + + kwq_entry->kwaitq = NULL; + return SOS_OK; +} + + +sos_ret_t sos_kwaitq_remove_entry(struct sos_kwaitq *kwq, + struct sos_kwaitq_entry *kwq_entry) +{ + sos_ui32_t flags; + sos_ret_t retval; + + sos_disable_IRQs(flags); + retval = _kwaitq_remove_entry(kwq, kwq_entry); + sos_restore_IRQs(flags); + + return retval; +} + + +sos_ret_t sos_kwaitq_wait(struct sos_kwaitq *kwq, + struct sos_time *timeout) +{ + sos_ui32_t flags; + sos_ret_t retval; + struct sos_kwaitq_entry kwq_entry; + + sos_kwaitq_init_entry(& kwq_entry); + + sos_disable_IRQs(flags); + + retval = _kwaitq_add_entry(kwq, & kwq_entry); + + /* Wait for wakeup or timeout */ + sos_thread_sleep(timeout); + /* Woken up ! */ + + /* Sleep delay elapsed ? */ + if (! kwq_entry.wakeup_triggered) + { + /* Yes (timeout occured, or wakeup on another waitqueue): remove + the waitq entry by ourselves */ + _kwaitq_remove_entry(kwq, & kwq_entry); + retval = -SOS_EINTR; + } + else + { + retval = kwq_entry.wakeup_status; + } + + sos_restore_IRQs(flags); + + /* We were correctly awoken: position return status */ + return retval; +} + + +sos_ret_t sos_kwaitq_wakeup(struct sos_kwaitq *kwq, + unsigned int nb_threads, + sos_ret_t wakeup_status) +{ + sos_ui32_t flags; + + sos_disable_IRQs(flags); + + /* Wake up as much threads waiting in waitqueue as possible (up to + nb_threads), scanning the list in FIFO order */ + while (! list_is_empty_named(kwq->waiting_list, + prev_entry_in_kwaitq, next_entry_in_kwaitq)) + { + struct sos_kwaitq_entry *kwq_entry + = list_get_head_named(kwq->waiting_list, + prev_entry_in_kwaitq, next_entry_in_kwaitq); + + /* Enough threads woken up ? */ + if (nb_threads <= 0) + break; + + /* + * Ok: wake up the thread for this entry + */ + + /* Thread already woken up ? */ + if (SOS_THR_RUNNING == sos_thread_get_state(kwq_entry->thread)) + { + /* Yes => Do nothing because WE are that woken-up thread. In + particular: don't call set_ready() here because this + would result in an inconsistent configuration (currently + running thread marked as "waiting for CPU"...). */ + continue; + } + else + { + /* No => wake it up now. */ + sos_sched_set_ready(kwq_entry->thread); + } + + /* Remove this waitq entry */ + _kwaitq_remove_entry(kwq, kwq_entry); + kwq_entry->wakeup_triggered = TRUE; + kwq_entry->wakeup_status = wakeup_status; + + /* Next iteration... */ + nb_threads --; + } + + sos_restore_IRQs(flags); + + return SOS_OK; +} -- cgit v1.2.3