|
[ source navigation ] [ diff markup ] [ identifier search ] [ general search ] |
|||
|
001 /* Copyright (C) 2004 David Decotigny 002 003 This program is free software; you can redistribute it and/or 004 modify it under the terms of the GNU General Public License 005 as published by the Free Software Foundation; either version 2 006 of the License, or (at your option) any later version. 007 008 This program is distributed in the hope that it will be useful, 009 but WITHOUT ANY WARRANTY; without even the implied warranty of 010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 011 GNU General Public License for more details. 012 013 You should have received a copy of the GNU General Public License 014 along with this program; if not, write to the Free Software 015 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 016 USA. 017 */ 018 #ifndef _SOS_KWAITQ_H_ 019 #define _SOS_KWAITQ_H_ 020 021 #include <sos/errno.h> 022 #include <sos/thread.h> 023 #include <sos/time.h> 024 025 026 /** 027 * @kwaitq.h 028 * 029 * Low-level functions to manage queues of threads waiting for a 030 * resource. These functions are public, except 031 * sos_kwaitq_change_priority() that is a callback for the thread 032 * subsystem. However, for higher-level synchronization primitives 033 * such as mutex, semaphores, conditions, ... prefer to look at the 034 * corresponding libraries. 035 */ 036 037 038 /** 039 * Define this if you want to know the names of the kwaitq 040 */ 041 // #define SOS_KWQ_DEBUG 042 043 044 /* Forward declaration */ 045 struct sos_kwaitq_entry; 046 047 048 /** 049 * The threads in the kwaitqs can be ordered in FIFO or in decreasing 050 * priority order. 051 */ 052 typedef enum { SOS_KWQ_ORDER_FIFO, SOS_KWQ_ORDER_PRIO } sos_kwaitq_ordering_t; 053 054 055 #include <sos/sched.h> 056 057 058 /** 059 * Definition of a waitqueue. In a kwaitq, the threads can be ordererd 060 * either in FIFO order (SOS_KWQ_ORDER_FIFO) or in decreasing priority 061 * order (SOS_KWQ_ORDER_PRIO ; with FIFO ordering for same-prio 062 * threads). 063 * 064 * A more efficient method to store the threads ordered by their 065 * priority would have been to use 1 list for each priority level. But 066 * we have to be careful to the size of a kwaitq structure here: 067 * potentially there are thousands of kwaitq in a running system 068 * (basically: 1 per opened file !). The algorithm we use to order the 069 * threads in the kwaitq in this case is highly under-optimal (naive 070 * linear insertion): as an exercise, one can implement a more 071 * efficient algorithm (think of a heap). 072 */ 073 struct sos_kwaitq 074 { 075 #ifdef SOS_KWQ_DEBUG 076 # define SOS_KWQ_DEBUG_MAX_NAMELEN 32 077 char name[SOS_KWQ_DEBUG_MAX_NAMELEN]; 078 #endif 079 sos_kwaitq_ordering_t ordering; 080 struct sos_kwaitq_entry *waiting_list; 081 }; 082 083 084 /** 085 * Definition of an entry for a thread waiting in the waitqueue 086 */ 087 struct sos_kwaitq_entry 088 { 089 /** The thread associted with this entry */ 090 struct sos_thread *thread; 091 092 /** The kwaitqueue this entry belongs to */ 093 struct sos_kwaitq *kwaitq; 094 095 /** TRUE when somebody woke up this entry */ 096 sos_bool_t wakeup_triggered; 097 098 /** The status of wakeup for this entry. @see wakeup_status argument 099 of sos_kwaitq_wakeup() */ 100 sos_ret_t wakeup_status; 101 102 /** Other entries in this kwaitqueue */ 103 struct sos_kwaitq_entry *prev_entry_in_kwaitq, *next_entry_in_kwaitq; 104 105 /** Other entries for the thread */ 106 struct sos_kwaitq_entry *prev_entry_for_thread, *next_entry_for_thread; 107 }; 108 109 110 /** 111 * Initialize an empty waitqueue. 112 * 113 * @param name Used only if SOS_KWQ_DEBUG is defined (safe [deep 114 * copied]) 115 */ 116 sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq, 117 const char *name, 118 sos_kwaitq_ordering_t ordering); 119 120 121 /** 122 * Release a waitqueue, making sure that no thread is in it. 123 * 124 * @return -SOS_EBUSY in case a thread is still in the waitqueue. 125 */ 126 sos_ret_t sos_kwaitq_dispose(struct sos_kwaitq *kwq); 127 128 129 /** 130 * Return whether there are no threads in the waitq 131 */ 132 sos_bool_t sos_kwaitq_is_empty(const struct sos_kwaitq *kwq); 133 134 135 /** 136 * Initialize a waitqueue entry. Mainly consists in updating the 137 * "thread" field of the entry (set to current running thread), and 138 * initializing the remaining of the entry as to indicate it does not 139 * belong to any waitq. 140 */ 141 sos_ret_t sos_kwaitq_init_entry(struct sos_kwaitq_entry *kwq_entry); 142 143 144 /** 145 * Add an entry (previously initialized with sos_kwaitq_init_entry()) 146 * in the given waitqueue. 147 * 148 * @note: No state change/context switch can occur here ! Among other 149 * things: the current executing thread is not preempted. 150 */ 151 sos_ret_t sos_kwaitq_add_entry(struct sos_kwaitq *kwq, 152 struct sos_kwaitq_entry *kwq_entry); 153 154 155 /** 156 * Remove the given kwaitq_entry from the kwaitq. 157 * 158 * @note: No state change/context switch can occur here ! Among other 159 * things: the thread associated with the entry is not necessarilly 160 * the same as the one currently running, and does not preempt the 161 * current running thread if they are different. 162 */ 163 sos_ret_t sos_kwaitq_remove_entry(struct sos_kwaitq *kwq, 164 struct sos_kwaitq_entry *kwq_entry); 165 166 167 /** 168 * Helper function to make the current running thread block in the 169 * given kwaitq, waiting to be woken up by somedy else or by the given 170 * timeout. It calls the sos_kwaitq_add_entry() and 171 * sos_kwaitq_remove_entry(). 172 * 173 * @param timeout The desired timeout (can be NULL => wait for 174 * ever). It is updated by the function to reflect the remaining 175 * timeout in case the thread has been woken-up prior to its 176 * expiration. 177 * 178 * @return -SOS_EINTR when the thread is resumed while it has not be 179 * explicitely woken up by someone calling sos_kwaitq_wakeup() upon 180 * the same waitqueue... This can only happen 1/ if the timeout 181 * expired, or 2/ if the current thread is also in another kwaitq 182 * different to "kwq". Otherwise return the value set by 183 * sos_kwaitq_wakeup(). The timeout remaining is updated in timeout. 184 * 185 * @note This is a BLOCKING FUNCTION 186 */ 187 sos_ret_t sos_kwaitq_wait(struct sos_kwaitq *kwq, 188 struct sos_time *timeout); 189 190 191 /** 192 * Wake up as much as nb_thread threads (SOS_KWQ_WAKEUP_ALL to wake 193 * up all threads) in the kwaitq kwq, in FIFO or decreasing priority 194 * order (depends on the ordering scheme selected at kwaitq 195 * initialization time). 196 * 197 * @param wakeup_status The value returned by sos_kwaitq_wait() when 198 * the thread will effectively woken up due to this wakeup. 199 */ 200 sos_ret_t sos_kwaitq_wakeup(struct sos_kwaitq *kwq, 201 unsigned int nb_threads, 202 sos_ret_t wakeup_status); 203 #define SOS_KWQ_WAKEUP_ALL (~((unsigned int)0)) 204 205 206 /** 207 * @note INTERNAL function (in particular: interrupts not disabled) ! 208 * 209 * @note: The use of this function is RESERVED (to thread.c). Do not 210 * call it directly: use sos_thread_set_priority() for that ! 211 */ 212 sos_ret_t sos_kwaitq_change_priority(struct sos_kwaitq *kwq, 213 struct sos_kwaitq_entry *kwq_entry, 214 sos_sched_priority_t priority); 215 216 #endif /* _SOS_KWAITQ_H_ */
[ source navigation ] | [ diff markup ] | [ identifier search ] | [ general search ] |