1 /*- 2 * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conds 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conds, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conds and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/proc.h> 30 #include <sys/signalvar.h> 31 #include <sys/sleepqueue.h> 32 33 #include <linux/delay.h> 34 #include <linux/errno.h> 35 #include <linux/kernel.h> 36 #include <linux/list.h> 37 #include <linux/sched.h> 38 #include <linux/spinlock.h> 39 #include <linux/wait.h> 40 41 static int 42 linux_add_to_sleepqueue(void *wchan, struct task_struct *task, 43 const char *wmesg, int timeout, int state) 44 { 45 int flags, ret; 46 47 MPASS((state & ~(TASK_PARKED | TASK_NORMAL)) == 0); 48 49 flags = SLEEPQ_SLEEP | ((state & TASK_INTERRUPTIBLE) != 0 ? 50 SLEEPQ_INTERRUPTIBLE : 0); 51 52 sleepq_add(wchan, NULL, wmesg, flags, 0); 53 if (timeout != 0) 54 sleepq_set_timeout(wchan, timeout); 55 56 DROP_GIANT(); 57 if ((state & TASK_INTERRUPTIBLE) != 0) { 58 if (timeout == 0) 59 ret = -sleepq_wait_sig(wchan, 0); 60 else 61 ret = -sleepq_timedwait_sig(wchan, 0); 62 } else { 63 if (timeout == 0) { 64 sleepq_wait(wchan, 0); 65 ret = 0; 66 } else 67 ret = -sleepq_timedwait(wchan, 0); 68 } 69 PICKUP_GIANT(); 70 71 /* filter return value */ 72 if (ret != 0 && ret != -EWOULDBLOCK) { 73 linux_schedule_save_interrupt_value(task, ret); 74 ret = -ERESTARTSYS; 75 } 76 return (ret); 77 } 78 79 unsigned int 80 linux_msleep_interruptible(unsigned int ms) 81 { 82 int ret; 83 84 /* guard against invalid values */ 85 if (ms == 0) 86 ms = 1; 87 ret = -pause_sbt("lnxsleep", mstosbt(ms), 0, C_HARDCLOCK | C_CATCH); 88 89 switch (ret) { 90 case -EWOULDBLOCK: 91 return (0); 92 default: 93 linux_schedule_save_interrupt_value(current, ret); 94 return (ms); 95 } 96 } 97 98 static int 99 wake_up_task(struct task_struct *task, unsigned int state) 100 { 101 int ret, wakeup_swapper; 102 103 ret = wakeup_swapper = 0; 104 sleepq_lock(task); 105 if ((atomic_read(&task->state) & state) != 0) { 106 set_task_state(task, TASK_WAKING); 107 wakeup_swapper = sleepq_signal(task, SLEEPQ_SLEEP, 0, 0); 108 ret = 1; 109 } 110 sleepq_release(task); 111 if (wakeup_swapper) 112 kick_proc0(); 113 return (ret); 114 } 115 116 bool 117 linux_signal_pending(struct task_struct *task) 118 { 119 struct thread *td; 120 sigset_t pending; 121 122 td = task->task_thread; 123 PROC_LOCK(td->td_proc); 124 pending = td->td_siglist; 125 SIGSETOR(pending, td->td_proc->p_siglist); 126 SIGSETNAND(pending, td->td_sigmask); 127 PROC_UNLOCK(td->td_proc); 128 return (!SIGISEMPTY(pending)); 129 } 130 131 bool 132 linux_fatal_signal_pending(struct task_struct *task) 133 { 134 struct thread *td; 135 bool ret; 136 137 td = task->task_thread; 138 PROC_LOCK(td->td_proc); 139 ret = SIGISMEMBER(td->td_siglist, SIGKILL) || 140 SIGISMEMBER(td->td_proc->p_siglist, SIGKILL); 141 PROC_UNLOCK(td->td_proc); 142 return (ret); 143 } 144 145 bool 146 linux_signal_pending_state(long state, struct task_struct *task) 147 { 148 149 MPASS((state & ~TASK_NORMAL) == 0); 150 151 if ((state & TASK_INTERRUPTIBLE) == 0) 152 return (false); 153 return (linux_signal_pending(task)); 154 } 155 156 void 157 linux_send_sig(int signo, struct task_struct *task) 158 { 159 struct thread *td; 160 161 td = task->task_thread; 162 PROC_LOCK(td->td_proc); 163 tdsignal(td, signo); 164 PROC_UNLOCK(td->td_proc); 165 } 166 167 int 168 autoremove_wake_function(wait_queue_t *wq, unsigned int state, int flags, 169 void *key __unused) 170 { 171 struct task_struct *task; 172 int ret; 173 174 task = wq->private; 175 if ((ret = wake_up_task(task, state)) != 0) 176 list_del_init(&wq->task_list); 177 return (ret); 178 } 179 180 int 181 default_wake_function(wait_queue_t *wq, unsigned int state, int flags, 182 void *key __unused) 183 { 184 return (wake_up_task(wq->private, state)); 185 } 186 187 void 188 linux_init_wait_entry(wait_queue_t *wq, int flags) 189 { 190 191 memset(wq, 0, sizeof(*wq)); 192 wq->flags = flags; 193 wq->private = current; 194 wq->func = autoremove_wake_function; 195 INIT_LIST_HEAD(&wq->task_list); 196 } 197 198 void 199 linux_wake_up(wait_queue_head_t *wqh, unsigned int state, int nr, bool locked) 200 { 201 wait_queue_t *pos, *next; 202 203 if (!locked) 204 spin_lock(&wqh->lock); 205 list_for_each_entry_safe(pos, next, &wqh->task_list, task_list) { 206 if (pos->func == NULL) { 207 if (wake_up_task(pos->private, state) != 0 && --nr == 0) 208 break; 209 } else { 210 if (pos->func(pos, state, 0, NULL) != 0 && --nr == 0) 211 break; 212 } 213 } 214 if (!locked) 215 spin_unlock(&wqh->lock); 216 } 217 218 void 219 linux_prepare_to_wait(wait_queue_head_t *wqh, wait_queue_t *wq, int state) 220 { 221 222 spin_lock(&wqh->lock); 223 if (list_empty(&wq->task_list)) 224 __add_wait_queue(wqh, wq); 225 set_task_state(current, state); 226 spin_unlock(&wqh->lock); 227 } 228 229 void 230 linux_finish_wait(wait_queue_head_t *wqh, wait_queue_t *wq) 231 { 232 233 spin_lock(&wqh->lock); 234 set_task_state(current, TASK_RUNNING); 235 if (!list_empty(&wq->task_list)) { 236 __remove_wait_queue(wqh, wq); 237 INIT_LIST_HEAD(&wq->task_list); 238 } 239 spin_unlock(&wqh->lock); 240 } 241 242 bool 243 linux_waitqueue_active(wait_queue_head_t *wqh) 244 { 245 bool ret; 246 247 spin_lock(&wqh->lock); 248 ret = !list_empty(&wqh->task_list); 249 spin_unlock(&wqh->lock); 250 return (ret); 251 } 252 253 int 254 linux_wait_event_common(wait_queue_head_t *wqh, wait_queue_t *wq, int timeout, 255 unsigned int state, spinlock_t *lock) 256 { 257 struct task_struct *task; 258 int ret; 259 260 if (lock != NULL) 261 spin_unlock_irq(lock); 262 263 /* range check timeout */ 264 if (timeout < 1) 265 timeout = 1; 266 else if (timeout == MAX_SCHEDULE_TIMEOUT) 267 timeout = 0; 268 269 task = current; 270 271 /* 272 * Our wait queue entry is on the stack - make sure it doesn't 273 * get swapped out while we sleep. 274 */ 275 PHOLD(task->task_thread->td_proc); 276 sleepq_lock(task); 277 if (atomic_read(&task->state) != TASK_WAKING) { 278 ret = linux_add_to_sleepqueue(task, task, "wevent", timeout, 279 state); 280 } else { 281 sleepq_release(task); 282 ret = 0; 283 } 284 PRELE(task->task_thread->td_proc); 285 286 if (lock != NULL) 287 spin_lock_irq(lock); 288 return (ret); 289 } 290 291 int 292 linux_schedule_timeout(int timeout) 293 { 294 struct task_struct *task; 295 int ret; 296 int state; 297 int remainder; 298 299 task = current; 300 301 /* range check timeout */ 302 if (timeout < 1) 303 timeout = 1; 304 else if (timeout == MAX_SCHEDULE_TIMEOUT) 305 timeout = 0; 306 307 remainder = ticks + timeout; 308 309 sleepq_lock(task); 310 state = atomic_read(&task->state); 311 if (state != TASK_WAKING) { 312 ret = linux_add_to_sleepqueue(task, task, "sched", timeout, 313 state); 314 } else { 315 sleepq_release(task); 316 ret = 0; 317 } 318 set_task_state(task, TASK_RUNNING); 319 320 if (timeout == 0) 321 return (MAX_SCHEDULE_TIMEOUT); 322 323 /* range check return value */ 324 remainder -= ticks; 325 326 /* range check return value */ 327 if (ret == -ERESTARTSYS && remainder < 1) 328 remainder = 1; 329 else if (remainder < 0) 330 remainder = 0; 331 else if (remainder > timeout) 332 remainder = timeout; 333 return (remainder); 334 } 335 336 static void 337 wake_up_sleepers(void *wchan) 338 { 339 int wakeup_swapper; 340 341 sleepq_lock(wchan); 342 wakeup_swapper = sleepq_signal(wchan, SLEEPQ_SLEEP, 0, 0); 343 sleepq_release(wchan); 344 if (wakeup_swapper) 345 kick_proc0(); 346 } 347 348 #define bit_to_wchan(word, bit) ((void *)(((uintptr_t)(word) << 6) | (bit))) 349 350 void 351 linux_wake_up_bit(void *word, int bit) 352 { 353 354 wake_up_sleepers(bit_to_wchan(word, bit)); 355 } 356 357 int 358 linux_wait_on_bit_timeout(unsigned long *word, int bit, unsigned int state, 359 int timeout) 360 { 361 struct task_struct *task; 362 void *wchan; 363 int ret; 364 365 /* range check timeout */ 366 if (timeout < 1) 367 timeout = 1; 368 else if (timeout == MAX_SCHEDULE_TIMEOUT) 369 timeout = 0; 370 371 task = current; 372 wchan = bit_to_wchan(word, bit); 373 for (;;) { 374 sleepq_lock(wchan); 375 if ((*word & (1 << bit)) == 0) { 376 sleepq_release(wchan); 377 ret = 0; 378 break; 379 } 380 set_task_state(task, state); 381 ret = linux_add_to_sleepqueue(wchan, task, "wbit", timeout, 382 state); 383 if (ret != 0) 384 break; 385 } 386 set_task_state(task, TASK_RUNNING); 387 388 return (ret); 389 } 390 391 void 392 linux_wake_up_atomic_t(atomic_t *a) 393 { 394 395 wake_up_sleepers(a); 396 } 397 398 int 399 linux_wait_on_atomic_t(atomic_t *a, unsigned int state) 400 { 401 struct task_struct *task; 402 void *wchan; 403 int ret; 404 405 task = current; 406 wchan = a; 407 for (;;) { 408 sleepq_lock(wchan); 409 if (atomic_read(a) == 0) { 410 sleepq_release(wchan); 411 ret = 0; 412 break; 413 } 414 set_task_state(task, state); 415 ret = linux_add_to_sleepqueue(wchan, task, "watomic", 0, state); 416 if (ret != 0) 417 break; 418 } 419 set_task_state(task, TASK_RUNNING); 420 421 return (ret); 422 } 423 424 bool 425 linux_wake_up_state(struct task_struct *task, unsigned int state) 426 { 427 428 return (wake_up_task(task, state) != 0); 429 } 430