[a9153ec] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @ingroup rtems_bsd_rtems |
---|
| 5 | * |
---|
| 6 | * @brief TODO. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /* |
---|
| 10 | * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved. |
---|
| 11 | * |
---|
| 12 | * embedded brains GmbH |
---|
| 13 | * Obere Lagerstr. 30 |
---|
| 14 | * 82178 Puchheim |
---|
| 15 | * Germany |
---|
| 16 | * <rtems@embedded-brains.de> |
---|
| 17 | * |
---|
[8420b94] | 18 | * Redistribution and use in source and binary forms, with or without |
---|
| 19 | * modification, are permitted provided that the following conditions |
---|
| 20 | * are met: |
---|
| 21 | * 1. Redistributions of source code must retain the above copyright |
---|
| 22 | * notice, this list of conditions and the following disclaimer. |
---|
| 23 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 24 | * notice, this list of conditions and the following disclaimer in the |
---|
| 25 | * documentation and/or other materials provided with the distribution. |
---|
| 26 | * |
---|
| 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
| 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
| 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 37 | * SUCH DAMAGE. |
---|
[a9153ec] | 38 | */ |
---|
| 39 | |
---|
[5d21d7a] | 40 | /* |
---|
[473437c] | 41 | * FIXME: This seems to be a completely broken implementation. |
---|
[5d21d7a] | 42 | */ |
---|
| 43 | |
---|
[e599318] | 44 | #include <machine/rtems-bsd-config.h> |
---|
[473437c] | 45 | |
---|
| 46 | #include <rtems/score/statesimpl.h> |
---|
| 47 | #include <rtems/score/threaddispatch.h> |
---|
[a9153ec] | 48 | #include <rtems/score/thread.h> |
---|
[473437c] | 49 | #include <rtems/score/threadqimpl.h> |
---|
[a9153ec] | 50 | |
---|
[e599318] | 51 | #include <rtems/bsd/sys/param.h> |
---|
| 52 | #include <rtems/bsd/sys/types.h> |
---|
| 53 | #include <sys/systm.h> |
---|
| 54 | #include <sys/kernel.h> |
---|
| 55 | #include <sys/ktr.h> |
---|
| 56 | #include <rtems/bsd/sys/lock.h> |
---|
| 57 | #include <sys/mutex.h> |
---|
| 58 | #include <sys/proc.h> |
---|
| 59 | #include <machine/pcpu.h> |
---|
[a9153ec] | 60 | |
---|
| 61 | #define STATES_WAITING_FOR_SLEEP 0x40000 |
---|
| 62 | |
---|
| 63 | static int pause_wchan; |
---|
| 64 | |
---|
| 65 | typedef struct |
---|
| 66 | { |
---|
| 67 | Chain_Node node; |
---|
| 68 | void *ident; |
---|
| 69 | Thread_queue_Control queue; |
---|
| 70 | }sleep_queue_control_t; |
---|
| 71 | |
---|
| 72 | sleep_queue_control_t sleep_queue[BSD_MAXIMUM_SLEEP_QUEUES]; //this memory allocation could use _Workspace_Allocate once inside RTEMS tree |
---|
| 73 | Chain_Control sleep_queue_inactive_nodes; //chain of inactive nodes |
---|
| 74 | Chain_Control sleep_queue_active_nodes; //chain of active nodes |
---|
| 75 | |
---|
| 76 | void |
---|
| 77 | sleepinit(void) |
---|
| 78 | { |
---|
| 79 | int ii; |
---|
| 80 | |
---|
| 81 | /* initialize the sleep queue */ |
---|
| 82 | for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ ) |
---|
| 83 | { |
---|
| 84 | sleep_queue[ii].ident = NULL; |
---|
| 85 | /* |
---|
| 86 | * Initialize the queue we use to block for signals |
---|
| 87 | */ |
---|
| 88 | _Thread_queue_Initialize( |
---|
| 89 | &sleep_queue[ii].queue, |
---|
[e957846] | 90 | THREAD_QUEUE_DISCIPLINE_PRIORITY, |
---|
[a9153ec] | 91 | STATES_WAITING_FOR_SLEEP | STATES_INTERRUPTIBLE_BY_SIGNAL, |
---|
| 92 | EAGAIN |
---|
| 93 | ); |
---|
| 94 | } |
---|
| 95 | //initialize active chain |
---|
| 96 | _Chain_Initialize_empty( &sleep_queue_active_nodes ); |
---|
| 97 | //initialize inactive chain |
---|
| 98 | _Chain_Initialize( &sleep_queue_inactive_nodes, sleep_queue, BSD_MAXIMUM_SLEEP_QUEUES, sizeof( sleep_queue_control_t )); |
---|
| 99 | } |
---|
| 100 | |
---|
| 101 | sleep_queue_control_t* |
---|
| 102 | sleep_queue_lookup(void *ident) |
---|
| 103 | { |
---|
| 104 | int ii; |
---|
| 105 | |
---|
| 106 | /* initialize the sleep queue */ |
---|
| 107 | for( ii = 0; ii < BSD_MAXIMUM_SLEEP_QUEUES; ii++ ) |
---|
| 108 | { |
---|
| 109 | if( sleep_queue[ii].ident == ident ) |
---|
| 110 | { |
---|
| 111 | return &sleep_queue[ii]; |
---|
| 112 | } |
---|
| 113 | } |
---|
| 114 | return NULL; |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | sleep_queue_control_t* |
---|
| 118 | sleep_queue_get(void *ident) |
---|
| 119 | { |
---|
| 120 | sleep_queue_control_t *sq; |
---|
| 121 | |
---|
| 122 | sq = sleep_queue_lookup( ident ); |
---|
| 123 | if (sq == NULL) |
---|
| 124 | { |
---|
| 125 | KASSERT(!_Chain_Is_empty( &inactive_nodes ), ("sleep_queue_get")); |
---|
| 126 | //get a control from the inactive chain |
---|
| 127 | sq = ( sleep_queue_control_t * )_Chain_Get( &sleep_queue_inactive_nodes ); |
---|
| 128 | sq->ident = ident; |
---|
| 129 | _Chain_Append( &sleep_queue_active_nodes, &sq->node ); |
---|
| 130 | } |
---|
| 131 | return sq; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | /* |
---|
| 135 | * Block the current thread until it is awakened from its sleep queue |
---|
| 136 | * or it times out while waiting. |
---|
| 137 | */ |
---|
| 138 | int |
---|
| 139 | sleep_queue_timedwait(void *wchan, int pri, int timeout, int catch) |
---|
| 140 | { |
---|
| 141 | sleep_queue_control_t *sq; |
---|
| 142 | Thread_Control *executing; |
---|
| 143 | ISR_Level level; |
---|
| 144 | |
---|
| 145 | _Thread_Disable_dispatch(); |
---|
| 146 | |
---|
| 147 | sq = sleep_queue_get( wchan ); |
---|
| 148 | |
---|
| 149 | executing = _Thread_Executing; |
---|
| 150 | if( timeout ) |
---|
| 151 | { |
---|
| 152 | executing->Wait.return_code = EWOULDBLOCK; |
---|
| 153 | } |
---|
| 154 | else
|
---|
| 155 | { |
---|
| 156 | executing->Wait.return_code = 0; |
---|
| 157 | } |
---|
| 158 | _ISR_Disable( level ); |
---|
| 159 | _Thread_queue_Enter_critical_section( &sq->queue ); |
---|
| 160 | if( catch ) |
---|
| 161 | { |
---|
| 162 | sq->queue.state |= STATES_INTERRUPTIBLE_BY_SIGNAL; |
---|
| 163 | } |
---|
| 164 | else |
---|
| 165 | { |
---|
| 166 | sq->queue.state &= ~STATES_INTERRUPTIBLE_BY_SIGNAL; |
---|
| 167 | } |
---|
| 168 | executing->Wait.queue = &sq->queue; |
---|
| 169 | _ISR_Enable( level ); |
---|
| 170 | |
---|
[473437c] | 171 | _Thread_queue_Enqueue( &sq->queue, executing, timeout ); |
---|
[a9153ec] | 172 | _Thread_Enable_dispatch(); |
---|
| 173 | return _Thread_Executing->Wait.return_code; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | /* |
---|
| 177 | * General sleep call. Suspends the current thread until a wakeup is |
---|
| 178 | * performed on the specified identifier. The thread will then be made |
---|
| 179 | * runnable with the specified priority. Sleeps at most timo/hz seconds |
---|
| 180 | * (0 means no timeout). If pri includes PCATCH flag, signals are checked |
---|
| 181 | * before and after sleeping, else signals are not checked. Returns 0 if |
---|
| 182 | * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a |
---|
| 183 | * signal needs to be delivered, ERESTART is returned if the current system |
---|
| 184 | * call should be restarted if possible, and EINTR is returned if the system |
---|
| 185 | * call should be interrupted by the signal (return EINTR). |
---|
| 186 | * |
---|
| 187 | * The lock argument is unlocked before the caller is suspended, and |
---|
| 188 | * re-locked before _sleep() returns. If priority includes the PDROP |
---|
| 189 | * flag the lock is not re-locked before returning. |
---|
| 190 | */ |
---|
| 191 | int |
---|
| 192 | _sleep(void *ident, struct lock_object *lock, int priority, const char *wmesg, int timo) |
---|
| 193 | { |
---|
| 194 | struct thread *td; |
---|
| 195 | struct lock_class *class; |
---|
| 196 | int catch, flags, lock_state, pri, rval; |
---|
| 197 | |
---|
| 198 | td = curthread; |
---|
| 199 | #ifdef KTRACE |
---|
| 200 | if (KTRPOINT(td, KTR_CSW)) |
---|
| 201 | ktrcsw(1, 0); |
---|
| 202 | #endif |
---|
| 203 | KASSERT(timo != 0 || mtx_owned(&Giant) || lock != NULL, |
---|
| 204 | ("sleeping without a lock")); |
---|
| 205 | KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep")); |
---|
| 206 | if (priority & PDROP) |
---|
| 207 | KASSERT(lock != NULL && lock != &Giant.lock_object, |
---|
| 208 | ("PDROP requires a non-Giant lock")); |
---|
| 209 | if (lock != NULL) |
---|
| 210 | class = LOCK_CLASS(lock); |
---|
| 211 | else |
---|
| 212 | class = NULL; |
---|
| 213 | |
---|
| 214 | if (cold) { |
---|
| 215 | /* |
---|
| 216 | * During autoconfiguration, just return; |
---|
| 217 | * don't run any other threads or panic below, |
---|
| 218 | * in case this is the idle thread and already asleep. |
---|
| 219 | * XXX: this used to do "s = splhigh(); splx(safepri); |
---|
| 220 | * splx(s);" to give interrupts a chance, but there is |
---|
| 221 | * no way to give interrupts a chance now. |
---|
| 222 | */ |
---|
| 223 | if (lock != NULL && priority & PDROP) |
---|
| 224 | class->lc_unlock(lock); |
---|
| 225 | return (0); |
---|
| 226 | } |
---|
| 227 | catch = priority & PCATCH; |
---|
| 228 | pri = priority & PRIMASK; |
---|
| 229 | |
---|
| 230 | if (lock == &Giant.lock_object) |
---|
| 231 | mtx_assert(&Giant, MA_OWNED); |
---|
| 232 | DROP_GIANT(); |
---|
| 233 | if (lock != NULL && lock != &Giant.lock_object && |
---|
| 234 | !(class->lc_flags & LC_SLEEPABLE)) { |
---|
| 235 | lock_state = class->lc_unlock(lock); |
---|
| 236 | } else |
---|
| 237 | /* GCC needs to follow the Yellow Brick Road */ |
---|
| 238 | lock_state = -1; |
---|
| 239 | |
---|
| 240 | if (lock != NULL && class->lc_flags & LC_SLEEPABLE) { |
---|
| 241 | lock_state = class->lc_unlock(lock); |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | rval = sleep_queue_timedwait(ident, pri, timo, catch); |
---|
| 245 | |
---|
| 246 | #ifdef KTRACE |
---|
| 247 | if (KTRPOINT(td, KTR_CSW)) |
---|
| 248 | ktrcsw(0, 0); |
---|
| 249 | #endif |
---|
| 250 | PICKUP_GIANT(); |
---|
| 251 | if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) { |
---|
| 252 | class->lc_lock(lock, lock_state); |
---|
| 253 | } |
---|
| 254 | return (rval); |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | /* |
---|
| 258 | * pause() is like tsleep() except that the intention is to not be |
---|
| 259 | * explicitly woken up by another thread. Instead, the current thread |
---|
| 260 | * simply wishes to sleep until the timeout expires. It is |
---|
| 261 | * implemented using a dummy wait channel. |
---|
| 262 | */ |
---|
| 263 | int |
---|
| 264 | pause(const char *wmesg, int timo) |
---|
| 265 | { |
---|
| 266 | |
---|
| 267 | KASSERT(timo != 0, ("pause: timeout required")); |
---|
| 268 | return (tsleep(&pause_wchan, 0, wmesg, timo)); |
---|
| 269 | } |
---|
| 270 | |
---|
| 271 | /* |
---|
| 272 | * Make all threads sleeping on the specified identifier runnable. |
---|
| 273 | */ |
---|
| 274 | void |
---|
| 275 | wakeup(void *ident) |
---|
| 276 | { |
---|
| 277 | sleep_queue_control_t *sq; |
---|
| 278 | Thread_Control *the_thread; |
---|
| 279 | |
---|
| 280 | sq = sleep_queue_lookup( ident ); |
---|
| 281 | if (sq == NULL) |
---|
| 282 | { |
---|
| 283 | return (0); |
---|
| 284 | } |
---|
| 285 | |
---|
| 286 | while ( (the_thread = _Thread_queue_Dequeue(&sq->queue)) ) |
---|
| 287 | { |
---|
| 288 | } |
---|
| 289 | return 0; |
---|
| 290 | } |
---|
| 291 | |
---|
[e957846] | 292 | /* |
---|
| 293 | * Make a thread sleeping on the specified identifier runnable. |
---|
| 294 | * May wake more than one thread if a target thread is currently |
---|
| 295 | * swapped out. |
---|
| 296 | */ |
---|
| 297 | void |
---|
| 298 | wakeup_one(void *ident) |
---|
| 299 | { |
---|
| 300 | sleep_queue_control_t *sq; |
---|
| 301 | Thread_Control *the_thread; |
---|
| 302 | |
---|
| 303 | sq = sleep_queue_lookup( ident ); |
---|
| 304 | if (sq == NULL) |
---|
| 305 | { |
---|
| 306 | return (0); |
---|
| 307 | } |
---|
| 308 | the_thread = _Thread_queue_Dequeue(&sq->queue); |
---|
| 309 | return 0; |
---|
| 310 | |
---|
| 311 | } |
---|
| 312 | |
---|