The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linuxkpi/common/src/linux_schedule.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c981bf44cbbde215303caea2ada61f33


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.