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/kern/rt_thread.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  * Mach Operating System
    3  * Copyright (c) 1993,1992 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        rt_thread.c,v $
   29  * Revision 2.2  93/11/17  17:20:03  dbg
   30  *      Renamed 'rt' or 'realtime' threads and timers to 'periodic'
   31  *      threads and timers (even though they can be used for nonperiodic
   32  *      threads).
   33  *      [93/11/16            dbg]
   34  * 
   35  *      Use thread_lock instead of ith_lock.
   36  *      [93/07/12            dbg]
   37  * 
   38  *      Handle starting timer better.
   39  *      [93/06/28            dbg]
   40  * 
   41  *      Changed thread_{get,set}_deadline_timer to
   42  *      thread_{get,set}_realtime_timers.
   43  *      [93/06/25            dbg]
   44  * 
   45  *      Use clock_read to read clock without locking.
   46  *      [93/06/18            dbg]
   47  * 
   48  *      machparam.h -> machspl.h
   49  *      [93/05/21            dbg]
   50  * 
   51  *      Conditionalize for MACH_RT.
   52  *      [93/05/17            dbg]
   53  * 
   54  *      Changed for flexible thread scheduling fields.
   55  *      [93/05/12            dbg]
   56  * 
   57  *      Added thread_get_deadline_timer, thread_set_deadline_timer.
   58  *      [93/04/15            dbg]
   59  * 
   60  *      Use sleep/wakeup instead of suspend/resume to wait for wakeup
   61  *      timer.
   62  *      [93/04/02            dbg]
   63  * 
   64  *      Moved thread_{get,set}_attributes here.
   65  *      [93/03/31            dbg]
   66  * 
   67  *      Merged into microkernel mainline.
   68  * 
   69  *      Checked time_specs to make sure they're valid
   70  *      [92/09/11       savage]
   71  *      Changed period and deadline to time_spec_t.
   72  *      [92/09/06       savage]
   73  *      Switched to use clock parameter instead of constant.  Cleanup.
   74  *      [92/07/12       savage]
   75  *      Replaced rt_timers with more generic mach_timers
   76  *      [92/06/22       savage]
   77  *      Replaced wakeup queue with rt_timer mechanism
   78  *      [92/05/05       savage]
   79  *      Re-vamped :-)
   80  *      [92/02/22       savage]
   81  *      Created
   82  *      [90/06/28       tatsuo]
   83  * 
   84  */
   85 #include <mach_rt.h>
   86 
   87 #include <mach/kern_return.h>
   88 #include <mach/realtime_policy.h>
   89 #include <mach/time_spec.h>
   90 
   91 #include <ipc/ipc_object.h>
   92 #include <ipc/ipc_port.h>
   93 
   94 #include <kern/clock.h>
   95 #include <kern/lock.h>
   96 #include <kern/mach_param.h>
   97 #include <kern/mach_timer.h>
   98 #include <kern/rt_thread.h>
   99 #include <kern/thread.h>
  100 #include <kern/zalloc.h>
  101 
  102 #include <vm/vm_kern.h>
  103 
  104 #include <machine/machspl.h>
  105 
  106 #if     MACH_RT
  107 /*
  108  *      Routine:        thread_get_periodic_timers
  109  *      Purpose:        gets the wakeup and deadline timers for a thread.
  110  */
  111 kern_return_t
  112 thread_get_periodic_timers(
  113         thread_t        thread,
  114         mach_timer_t    *wakeup_timer_p,                /* OUT */
  115         mach_timer_t    *deadline_timer_p)
  116 {
  117         mach_timer_t    wakeup_timer, deadline_timer;
  118 
  119         if (thread == THREAD_NULL)
  120             return KERN_INVALID_ARGUMENT;
  121 
  122         thread_lock(thread);
  123         wakeup_timer = thread->rt_wakeup_timer;
  124         mach_timer_reference(wakeup_timer);
  125         deadline_timer = thread->rt_deadline_timer;
  126         mach_timer_reference(deadline_timer);
  127         thread_unlock(thread);
  128 
  129         *wakeup_timer_p = wakeup_timer;
  130         *deadline_timer_p = deadline_timer;
  131 
  132         return KERN_SUCCESS;
  133 }
  134 
  135 /*
  136  *      Routine:        thread_set_periodic_timers
  137  *      Purpose:        sets the wakeup and deadline timers for a thread.
  138  */
  139 kern_return_t
  140 thread_set_periodic_timers(
  141         thread_t        thread,
  142         mach_timer_t    new_wakeup_timer,
  143         mach_timer_t    new_deadline_timer)
  144 {
  145         mach_timer_t    old_wakeup_timer;
  146         mach_timer_t    old_deadline_timer;
  147 
  148         if (thread == THREAD_NULL)
  149             return KERN_INVALID_ARGUMENT;
  150 
  151         /*
  152          *      Make thread references to the new timers
  153          *      to keep them alive even if all send rights
  154          *      vanish.
  155          */
  156         if (!mach_timer_thread_reference(new_wakeup_timer)) {
  157             /* dead already (?) */
  158             return KERN_INVALID_ARGUMENT;
  159         }
  160         if (!mach_timer_thread_reference(new_deadline_timer)) {
  161             mach_timer_thread_deallocate(new_wakeup_timer);
  162             return KERN_INVALID_ARGUMENT;
  163         }
  164 
  165 
  166         /*
  167          *      Swap the old and new timers.
  168          */
  169         thread_lock(thread);
  170         old_wakeup_timer = thread->rt_wakeup_timer;
  171         thread->rt_wakeup_timer = new_wakeup_timer;
  172         old_deadline_timer = thread->rt_deadline_timer;
  173         thread->rt_deadline_timer = new_deadline_timer;
  174         thread_unlock(thread);
  175 
  176         /*
  177          *      Deallocate the thread-references to
  178          *      the old timers.
  179          */
  180         if (old_wakeup_timer != 0)
  181             mach_timer_thread_deallocate(old_wakeup_timer);
  182         if (old_deadline_timer != 0)
  183             mach_timer_thread_deallocate(old_deadline_timer);
  184 
  185         return KERN_SUCCESS;
  186 }
  187 
  188 /*
  189  *      Routine:        periodic_thread_create
  190  *      Purpose:        Creates a thread via thread_create, sets scheduling 
  191  *                      parameters, sets execution state, and then either
  192  *                      thread_resumes the thread or enqueues it to be resumed
  193  *                      later.
  194  *      Conditions:     None
  195  */
  196 kern_return_t periodic_thread_create(
  197         task_t                  parent_task,
  198         mach_clock_t            clock,
  199         policy_param_realtime_t rt_attr,
  200         ipc_port_t              deadline_port,
  201         int                     state_flavor,
  202         thread_state_t          state,
  203         natural_t               state_count,
  204         thread_t                *child_thread)  /* out */
  205 {
  206         register
  207         thread_t        thread;
  208         mach_timer_t    wakeup_timer;
  209         mach_timer_t    deadline_timer;
  210         int             periodic;
  211         kern_return_t   ret;
  212 
  213         if (parent_task == TASK_NULL || clock == 0)
  214             return KERN_INVALID_ARGUMENT;
  215 
  216         /*
  217          *      Are the time_specs legitimate?
  218          */
  219         if (!time_spec_valid(rt_attr.start_time) ||
  220             !time_spec_valid(rt_attr.period) ||
  221             !time_spec_valid(rt_attr.deadline))
  222         {
  223             return KERN_INVALID_VALUE;
  224         }
  225         if (rt_attr.start_when != START_TIME_ABSOLUTE &&
  226             rt_attr.start_when != START_TIME_RELATIVE)
  227         {
  228             return KERN_INVALID_VALUE;
  229         }
  230 
  231         /*
  232          *      Convert zero period or deadline to infinity.
  233          */
  234         if (!time_spec_nonzero(rt_attr.period)) {
  235             time_spec_set_infinite(rt_attr.period);
  236         }
  237         if (!time_spec_nonzero(rt_attr.deadline)) {
  238             time_spec_set_infinite(rt_attr.deadline);
  239         }
  240 
  241         /*
  242          *      Create the thread.
  243          */
  244         {
  245             thread_t    temp_thread;    /* to keep 'thread' in register */
  246 
  247             ret = thread_create(parent_task, &temp_thread);
  248             if (ret != KERN_SUCCESS)
  249                 return ret;
  250 
  251             thread = temp_thread;
  252         }
  253 
  254         /*
  255          *      Set initial register state for the thread.
  256          */
  257         ret = thread_setstatus(thread, state_flavor, state, state_count);
  258         if (ret != KERN_SUCCESS) {
  259             (void) thread_terminate(thread);
  260             return ret;
  261         }
  262 
  263         /*
  264          *      Create a wakeup timer for the thread.
  265          */
  266         ret = timer_create(clock, &wakeup_timer);
  267         if (ret != KERN_SUCCESS) {
  268             (void) thread_terminate(thread);
  269             thread_deallocate(thread);
  270             return ret;
  271         }
  272 
  273         /*
  274          *      Create a deadline timer for the thread.
  275          */
  276         ret = timer_create(clock, &deadline_timer);
  277         if (ret != KERN_SUCCESS) {
  278             (void) timer_terminate(wakeup_timer);
  279             (void) thread_terminate(thread);
  280             thread_deallocate(thread);
  281             return ret;
  282         }
  283 
  284         /*
  285          *      Calculate the absolute start time, so that
  286          *      the wakeup and deadline timers are consistent.
  287          *      Give it to thread_set_policy_param.
  288          */
  289         if (rt_attr.start_when == START_TIME_RELATIVE) {
  290             time_spec_t cur_time;
  291             clock_read(cur_time, clock);
  292             time_spec_add(rt_attr.start_time, cur_time);
  293             rt_attr.start_when = START_TIME_ABSOLUTE;
  294         }
  295 
  296         /*
  297          *      Set the scheduling policy and attributes for
  298          *      the thread.  Do this before registering the
  299          *      timers for the thread, so that the timers
  300          *      can be set later (with the wakeup-thread
  301          *      and deadline port).
  302          */
  303         ret = thread_set_policy_param(thread,
  304                                       FALSE,
  305                                       (natural_t *)&rt_attr,
  306                                       POLICY_PARAM_REALTIME_COUNT);
  307         if (ret != KERN_SUCCESS) {
  308             (void) thread_terminate(thread);
  309             return ret;
  310         }
  311 
  312         /*
  313          *      Register the timers with the thread.
  314          */
  315         (void) thread_set_periodic_timers(thread,
  316                                           wakeup_timer,
  317                                           deadline_timer);
  318 
  319         /*
  320          *      Set the 'periodic' flag for the timers.
  321          */
  322         if (time_spec_infinite(rt_attr.period))
  323             periodic = 0;               /* not periodic */
  324         else
  325             periodic = TIMER_PERIODIC;  /* periodic thread */
  326 
  327         /*
  328          *      Set the wakeup timer for the starting time
  329          *      of the thread, and make it periodic if thread
  330          *      is periodic.
  331          */
  332         ret = timer_sleep_periodic(wakeup_timer,
  333                                    rt_attr.start_time,
  334                                    rt_attr.period,
  335                                    thread,
  336                                    TIMER_ABSOLUTE | periodic);
  337         if (ret != KERN_SUCCESS) {
  338             (void) thread_terminate(thread);
  339             return ret;
  340         }
  341 
  342         /*
  343          *      Set the deadline timer, if the thread has
  344          *      a deadline.
  345          */
  346         if (!time_spec_infinite(rt_attr.deadline)) {
  347             time_spec_t deadline_time;
  348 
  349             deadline_time = rt_attr.start_time;
  350             time_spec_add(deadline_time, rt_attr.deadline);
  351             ret = timer_arm(deadline_timer,
  352                             deadline_time,
  353                             rt_attr.period,
  354                             deadline_port,
  355                             THREAD_NULL,
  356                             TIMER_THREAD_SUSPEND | TIMER_ABSOLUTE | periodic);
  357             if (ret != KERN_SUCCESS) {
  358                 /*
  359                  *      Bad parameter to time?
  360                  */
  361                 (void) thread_terminate(thread);
  362                 return ret;
  363             }
  364         }
  365 
  366         /*
  367          *      Resume the thread.  If it has a delayed start,
  368          *      it will be waiting for the wakeup timer.
  369          */
  370         (void) thread_resume(thread);
  371 
  372         /*
  373          *      Return the child thread.
  374          */
  375         *child_thread = thread;
  376         return KERN_SUCCESS;
  377 }
  378 
  379 
  380 /*
  381  *      Routine:        periodic_thread_restart
  382  *      Purpose:        Resets timers and execution state for periodic threads.
  383  *                      This routine is usually only called via fiddling with
  384  *                      the user stack and is never invoked directly.
  385  *      Conditions:     None
  386  */
  387 kern_return_t periodic_thread_restart(
  388         thread_t        thread)
  389 {
  390         mach_timer_t    wakeup_timer;
  391         mach_timer_t    deadline_timer;
  392 
  393         if (thread == THREAD_NULL)
  394             return KERN_INVALID_ARGUMENT;
  395 
  396         /*
  397          *      Thread must have wakeup and deadline timers
  398          */
  399         deadline_timer = thread->rt_deadline_timer;
  400         wakeup_timer   = thread->rt_wakeup_timer;
  401         if (deadline_timer == 0 || wakeup_timer == 0)
  402             return KERN_INVALID_ARGUMENT;
  403 
  404         /*
  405          *      Cancel the current iteration of the deadline timer.
  406          *      If the thread is periodic, this resets the deadline
  407          *      timer to the deadline for the thread`s next
  408          *      execution period.
  409          */
  410 
  411         (void) timer_cancel(deadline_timer, TIMER_PERIODIC);
  412 
  413         /*
  414          *      If the thread is not periodic, terminate it.
  415          *
  416          *      XXX locking on timer
  417          */
  418         if ((wakeup_timer->tm_flags & TELT_PERIODIC) == 0) {
  419             return thread_terminate(thread);
  420         }
  421 
  422         /*
  423          *      Periodic thread.  Wait for the next
  424          *      expiration of the wakeup timer.
  425          */
  426         timer_wait(wakeup_timer, thread);
  427 
  428         /*
  429          *      Thread is now waiting for timer.
  430          *      If it is the current thread, block to
  431          *      wait for timer.
  432          *
  433          *      If thread is NOT the current thread, it better
  434          *      be suspended...
  435          */
  436         if (thread == current_thread()) {
  437             thread_block(CONTINUE_NULL);
  438         }
  439 
  440         return KERN_SUCCESS;
  441 }
  442 
  443 #else   /* MACH_RT */
  444 
  445 /*
  446  *      Periodic thread interfaces are not implemented, and all
  447  *      return KERN_FAILURE.
  448  */
  449 kern_return_t
  450 thread_get_periodic_timers(
  451         thread_t        thread,
  452         mach_timer_t    *wakeup_timer_p,                /* OUT */
  453         mach_timer_t    *deadline_timer_p)
  454 {
  455         return KERN_FAILURE;
  456 }
  457 
  458 kern_return_t
  459 thread_set_periodic_timers(
  460         thread_t        thread,
  461         mach_timer_t    new_wakeup_timer,
  462         mach_timer_t    new_deadline_timer)
  463 {
  464         return KERN_FAILURE;
  465 }
  466 
  467 kern_return_t periodic_thread_create(
  468         task_t                  parent_task,
  469         mach_clock_t            clock,
  470         policy_param_realtime_t rt_attr,
  471         ipc_port_t              deadline_port,
  472         int                     state_flavor,
  473         thread_state_t          state,
  474         natural_t               state_count,
  475         thread_t                *child_thread)  /* out */
  476 {
  477         return KERN_FAILURE;
  478 }
  479 
  480 kern_return_t periodic_thread_restart(
  481         thread_t        thread)
  482 {
  483         return KERN_FAILURE;
  484 }
  485 
  486 #endif  /* MACH_RT */

Cache object: 1627cc90d8132f76284d8e635be4cf59


[ 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.