Print this page
    
7127  remove -Wno-missing-braces from Makefile.uts
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/os/callb.c
          +++ new/usr/src/uts/common/os/callb.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  #include <sys/param.h>
  27   27  #include <sys/t_lock.h>
  28   28  #include <sys/types.h>
  29   29  #include <sys/time.h>
  30   30  #include <sys/sysmacros.h>
  31   31  #include <sys/systm.h>
  32   32  #include <sys/cpuvar.h>
  33   33  #include <sys/user.h>
  34   34  #include <sys/proc.h>
  35   35  #include <sys/callb.h>
  36   36  #include <sys/kmem.h>
  37   37  #include <sys/cmn_err.h>
  38   38  #include <sys/swap.h>
  39   39  #include <sys/vmsystm.h>
  40   40  #include <sys/class.h>
  41   41  #include <sys/debug.h>
  42   42  #include <sys/thread.h>
  43   43  #include <sys/kobj.h>
  44   44  #include <sys/ddi.h>    /* for delay() */
  45   45  #include <sys/taskq.h>  /* For TASKQ_NAMELEN */
  46   46  
  47   47  #define CB_MAXNAME      TASKQ_NAMELEN
  48   48  
  49   49  /*
  50   50   * The callb mechanism provides generic event scheduling/echoing.
  51   51   * A callb function is registered and called on behalf of the event.
  52   52   */
  53   53  typedef struct callb {
  54   54          struct callb    *c_next;        /* next in class or on freelist */
  55   55          kthread_id_t    c_thread;       /* ptr to caller's thread struct */
  56   56          char            c_flag;         /* info about the callb state */
  57   57          uchar_t         c_class;        /* this callb's class */
  58   58          kcondvar_t      c_done_cv;      /* signal callb completion */
  59   59          boolean_t       (*c_func)();    /* cb function: returns true if ok */
  60   60          void            *c_arg;         /* arg to c_func */
  61   61          char            c_name[CB_MAXNAME+1]; /* debug:max func name length */
  62   62  } callb_t;
  63   63  
  64   64  /*
  65   65   * callb c_flag bitmap definitions
  66   66   */
  67   67  #define CALLB_FREE              0x0
  68   68  #define CALLB_TAKEN             0x1
  69   69  #define CALLB_EXECUTING         0x2
  70   70  
  71   71  /*
  72   72   * Basic structure for a callb table.
  73   73   * All callbs are organized into different class groups described
  74   74   * by ct_class array.
  75   75   * The callbs within a class are single-linked and normally run by a
  76   76   * serial execution.
  77   77   */
  78   78  typedef struct callb_table {
  79   79          kmutex_t ct_lock;               /* protect all callb states */
  80   80          callb_t *ct_freelist;           /* free callb structures */
  81   81          int     ct_busy;                /* != 0 prevents additions */
  82   82          kcondvar_t ct_busy_cv;          /* to wait for not busy    */
  83   83          int     ct_ncallb;              /* num of callbs allocated */
  84   84          callb_t *ct_first_cb[NCBCLASS]; /* ptr to 1st callb in a class */
  85   85  } callb_table_t;
  
    | ↓ open down ↓ | 85 lines elided | ↑ open up ↑ | 
  86   86  
  87   87  int callb_timeout_sec = CPR_KTHREAD_TIMEOUT_SEC;
  88   88  
  89   89  static callb_id_t callb_add_common(boolean_t (*)(void *, int),
  90   90      void *, int, char *, kthread_id_t);
  91   91  
  92   92  static callb_table_t callb_table;       /* system level callback table */
  93   93  static callb_table_t *ct = &callb_table;
  94   94  static kmutex_t callb_safe_mutex;
  95   95  callb_cpr_t     callb_cprinfo_safe = {
  96      -        &callb_safe_mutex, CALLB_CPR_ALWAYS_SAFE, 0, 0, 0 };
       96 +        &callb_safe_mutex, CALLB_CPR_ALWAYS_SAFE, NULL, {0}, {0} };
  97   97  
  98   98  /*
  99   99   * Init all callb tables in the system.
 100  100   */
 101  101  void
 102  102  callb_init()
 103  103  {
 104  104          callb_table.ct_busy = 0;        /* mark table open for additions */
 105  105          mutex_init(&callb_safe_mutex, NULL, MUTEX_DEFAULT, NULL);
 106  106          mutex_init(&callb_table.ct_lock, NULL, MUTEX_DEFAULT, NULL);
 107  107  }
 108  108  
 109  109  /*
 110  110   * callout_add() is called to register func() be called later.
 111  111   */
 112  112  static callb_id_t
 113  113  callb_add_common(boolean_t (*func)(void *arg, int code),
 114  114      void *arg, int class, char *name, kthread_id_t t)
 115  115  {
 116  116          callb_t *cp;
 117  117  
 118  118          ASSERT(class < NCBCLASS);
 119  119  
 120  120          mutex_enter(&ct->ct_lock);
 121  121          while (ct->ct_busy)
 122  122                  cv_wait(&ct->ct_busy_cv, &ct->ct_lock);
 123  123          if ((cp = ct->ct_freelist) == NULL) {
 124  124                  ct->ct_ncallb++;
 125  125                  cp = (callb_t *)kmem_zalloc(sizeof (callb_t), KM_SLEEP);
 126  126          }
 127  127          ct->ct_freelist = cp->c_next;
 128  128          cp->c_thread = t;
 129  129          cp->c_func = func;
 130  130          cp->c_arg = arg;
 131  131          cp->c_class = (uchar_t)class;
 132  132          cp->c_flag |= CALLB_TAKEN;
 133  133  #ifdef DEBUG
 134  134          if (strlen(name) > CB_MAXNAME)
 135  135                  cmn_err(CE_WARN, "callb_add: name of callback function '%s' "
 136  136                      "too long -- truncated to %d chars",
 137  137                      name, CB_MAXNAME);
 138  138  #endif
 139  139          (void) strncpy(cp->c_name, name, CB_MAXNAME);
 140  140          cp->c_name[CB_MAXNAME] = '\0';
 141  141  
 142  142          /*
 143  143           * Insert the new callb at the head of its class list.
 144  144           */
 145  145          cp->c_next = ct->ct_first_cb[class];
 146  146          ct->ct_first_cb[class] = cp;
 147  147  
 148  148          mutex_exit(&ct->ct_lock);
 149  149          return ((callb_id_t)cp);
 150  150  }
 151  151  
 152  152  /*
 153  153   * The default function to add an entry to the callback table.  Since
 154  154   * it uses curthread as the thread identifier to store in the table,
 155  155   * it should be used for the normal case of a thread which is calling
 156  156   * to add ITSELF to the table.
 157  157   */
 158  158  callb_id_t
 159  159  callb_add(boolean_t (*func)(void *arg, int code),
 160  160      void *arg, int class, char *name)
 161  161  {
 162  162          return (callb_add_common(func, arg, class, name, curthread));
 163  163  }
 164  164  
 165  165  /*
 166  166   * A special version of callb_add() above for use by threads which
 167  167   * might be adding an entry to the table on behalf of some other
 168  168   * thread (for example, one which is constructed but not yet running).
 169  169   * In this version the thread id is an argument.
 170  170   */
 171  171  callb_id_t
 172  172  callb_add_thread(boolean_t (*func)(void *arg, int code),
 173  173      void *arg, int class, char *name, kthread_id_t t)
 174  174  {
 175  175          return (callb_add_common(func, arg, class, name, t));
 176  176  }
 177  177  
 178  178  /*
 179  179   * callout_delete() is called to remove an entry identified by id
 180  180   * that was originally placed there by a call to callout_add().
 181  181   * return -1 if fail to delete a callb entry otherwise return 0.
 182  182   */
 183  183  int
 184  184  callb_delete(callb_id_t id)
 185  185  {
 186  186          callb_t **pp;
 187  187          callb_t *me = (callb_t *)id;
 188  188  
 189  189          mutex_enter(&ct->ct_lock);
 190  190  
 191  191          for (;;) {
 192  192                  pp = &ct->ct_first_cb[me->c_class];
 193  193                  while (*pp != NULL && *pp != me)
 194  194                          pp = &(*pp)->c_next;
 195  195  
 196  196  #ifdef DEBUG
 197  197                  if (*pp != me) {
 198  198                          cmn_err(CE_WARN, "callb delete bogus entry 0x%p",
 199  199                              (void *)me);
 200  200                          mutex_exit(&ct->ct_lock);
 201  201                          return (-1);
 202  202                  }
 203  203  #endif /* DEBUG */
 204  204  
 205  205                  /*
 206  206                   * It is not allowed to delete a callb in the middle of
 207  207                   * executing otherwise, the callb_execute() will be confused.
 208  208                   */
 209  209                  if (!(me->c_flag & CALLB_EXECUTING))
 210  210                          break;
 211  211  
 212  212                  cv_wait(&me->c_done_cv, &ct->ct_lock);
 213  213          }
 214  214          /* relink the class list */
 215  215          *pp = me->c_next;
 216  216  
 217  217          /* clean up myself and return the free callb to the head of freelist */
 218  218          me->c_flag = CALLB_FREE;
 219  219          me->c_next = ct->ct_freelist;
 220  220          ct->ct_freelist = me;
 221  221  
 222  222          mutex_exit(&ct->ct_lock);
 223  223          return (0);
 224  224  }
 225  225  
 226  226  /*
 227  227   * class:       indicates to execute all callbs in the same class;
 228  228   * code:        optional argument for the callb functions.
 229  229   * return:       = 0: success
 230  230   *              != 0: ptr to string supplied when callback was registered
 231  231   */
 232  232  void *
 233  233  callb_execute_class(int class, int code)
 234  234  {
 235  235          callb_t *cp;
 236  236          void *ret = NULL;
 237  237  
 238  238          ASSERT(class < NCBCLASS);
 239  239  
 240  240          mutex_enter(&ct->ct_lock);
 241  241  
 242  242          for (cp = ct->ct_first_cb[class];
 243  243              cp != NULL && ret == 0; cp = cp->c_next) {
 244  244                  while (cp->c_flag & CALLB_EXECUTING)
 245  245                          cv_wait(&cp->c_done_cv, &ct->ct_lock);
 246  246                  /*
 247  247                   * cont if the callb is deleted while we're sleeping
 248  248                   */
 249  249                  if (cp->c_flag == CALLB_FREE)
 250  250                          continue;
 251  251                  cp->c_flag |= CALLB_EXECUTING;
 252  252  
 253  253  #ifdef CALLB_DEBUG
 254  254                  printf("callb_execute: name=%s func=%p arg=%p\n",
 255  255                      cp->c_name, (void *)cp->c_func, (void *)cp->c_arg);
 256  256  #endif /* CALLB_DEBUG */
 257  257  
 258  258                  mutex_exit(&ct->ct_lock);
 259  259                  /* If callback function fails, pass back client's name */
 260  260                  if (!(*cp->c_func)(cp->c_arg, code))
 261  261                          ret = cp->c_name;
 262  262                  mutex_enter(&ct->ct_lock);
 263  263  
 264  264                  cp->c_flag &= ~CALLB_EXECUTING;
 265  265                  cv_broadcast(&cp->c_done_cv);
 266  266          }
 267  267          mutex_exit(&ct->ct_lock);
 268  268          return (ret);
 269  269  }
 270  270  
 271  271  /*
 272  272   * callers make sure no recursive entries to this func.
 273  273   * dp->cc_lockp is registered by callb_add to protect callb_cpr_t structure.
 274  274   *
 275  275   * When calling to stop a kernel thread (code == CB_CODE_CPR_CHKPT) we
 276  276   * use a cv_timedwait() in case the kernel thread is blocked.
 277  277   *
 278  278   * Note that this is a generic callback handler for daemon CPR and
 279  279   * should NOT be changed to accommodate any specific requirement in a daemon.
 280  280   * Individual daemons that require changes to the handler shall write
 281  281   * callback routines in their own daemon modules.
 282  282   */
 283  283  boolean_t
 284  284  callb_generic_cpr(void *arg, int code)
 285  285  {
 286  286          callb_cpr_t *cp = (callb_cpr_t *)arg;
 287  287          clock_t ret = 0;                        /* assume success */
 288  288  
 289  289          mutex_enter(cp->cc_lockp);
 290  290  
 291  291          switch (code) {
 292  292          case CB_CODE_CPR_CHKPT:
 293  293                  cp->cc_events |= CALLB_CPR_START;
 294  294  #ifdef CPR_NOT_THREAD_SAFE
 295  295                  while (!(cp->cc_events & CALLB_CPR_SAFE))
 296  296                          /* cv_timedwait() returns -1 if it times out. */
 297  297                          if ((ret = cv_reltimedwait(&cp->cc_callb_cv,
 298  298                              cp->cc_lockp, (callb_timeout_sec * hz),
 299  299                              TR_CLOCK_TICK)) == -1)
 300  300                                  break;
 301  301  #endif
 302  302                  break;
 303  303  
 304  304          case CB_CODE_CPR_RESUME:
 305  305                  cp->cc_events &= ~CALLB_CPR_START;
 306  306                  cv_signal(&cp->cc_stop_cv);
 307  307                  break;
 308  308          }
 309  309          mutex_exit(cp->cc_lockp);
 310  310          return (ret != -1);
 311  311  }
 312  312  
 313  313  /*
 314  314   * The generic callback function associated with kernel threads which
 315  315   * are always considered safe.
 316  316   */
 317  317  /* ARGSUSED */
 318  318  boolean_t
 319  319  callb_generic_cpr_safe(void *arg, int code)
 320  320  {
 321  321          return (B_TRUE);
 322  322  }
 323  323  /*
 324  324   * Prevent additions to callback table.
 325  325   */
 326  326  void
 327  327  callb_lock_table(void)
 328  328  {
 329  329          mutex_enter(&ct->ct_lock);
 330  330          ASSERT(ct->ct_busy == 0);
 331  331          ct->ct_busy = 1;
 332  332          mutex_exit(&ct->ct_lock);
 333  333  }
 334  334  
 335  335  /*
 336  336   * Allow additions to callback table.
 337  337   */
 338  338  void
 339  339  callb_unlock_table(void)
 340  340  {
 341  341          mutex_enter(&ct->ct_lock);
 342  342          ASSERT(ct->ct_busy != 0);
 343  343          ct->ct_busy = 0;
 344  344          cv_broadcast(&ct->ct_busy_cv);
 345  345          mutex_exit(&ct->ct_lock);
 346  346  }
 347  347  
 348  348  /*
 349  349   * Return a boolean value indicating whether a particular kernel thread is
 350  350   * stopped in accordance with the cpr callback protocol.  If returning
 351  351   * false, also return a pointer to the thread name via the 2nd argument.
 352  352   */
 353  353  boolean_t
 354  354  callb_is_stopped(kthread_id_t tp, caddr_t *thread_name)
 355  355  {
 356  356          callb_t *cp;
 357  357          boolean_t ret_val;
 358  358  
 359  359          mutex_enter(&ct->ct_lock);
 360  360  
 361  361          for (cp = ct->ct_first_cb[CB_CL_CPR_DAEMON];
 362  362              cp != NULL && tp != cp->c_thread; cp = cp->c_next)
 363  363                  ;
 364  364  
 365  365          ret_val = (cp != NULL);
 366  366          if (ret_val) {
 367  367                  /*
 368  368                   * We found the thread in the callback table and have
 369  369                   * provisionally set the return value to true.  Now
 370  370                   * see if it is marked "safe" and is sleeping or stopped.
 371  371                   */
 372  372                  callb_cpr_t *ccp = (callb_cpr_t *)cp->c_arg;
 373  373  
 374  374                  *thread_name = cp->c_name;      /* in case not stopped */
 375  375                  mutex_enter(ccp->cc_lockp);
 376  376  
 377  377                  if (ccp->cc_events & CALLB_CPR_SAFE) {
 378  378                          int retry;
 379  379  
 380  380                          mutex_exit(ccp->cc_lockp);
 381  381                          for (retry = 0; retry < CALLB_MAX_RETRY; retry++) {
 382  382                                  thread_lock(tp);
 383  383                                  if (tp->t_state & (TS_SLEEP | TS_STOPPED)) {
 384  384                                          thread_unlock(tp);
 385  385                                          break;
 386  386                                  }
 387  387                                  thread_unlock(tp);
 388  388                                  delay(CALLB_THREAD_DELAY);
 389  389                          }
 390  390                          ret_val = retry < CALLB_MAX_RETRY;
 391  391                  } else {
 392  392                          ret_val =
 393  393                              (ccp->cc_events & CALLB_CPR_ALWAYS_SAFE) != 0;
 394  394                          mutex_exit(ccp->cc_lockp);
 395  395                  }
 396  396          } else {
 397  397                  /*
 398  398                   * Thread not found in callback table.  Make the best
 399  399                   * attempt to identify the thread in the error message.
 400  400                   */
 401  401                  ulong_t offset;
 402  402                  char *sym = kobj_getsymname((uintptr_t)tp->t_startpc,
 403  403                      &offset);
 404  404  
 405  405                  *thread_name = sym ? sym : "*unknown*";
 406  406          }
 407  407  
 408  408          mutex_exit(&ct->ct_lock);
 409  409          return (ret_val);
 410  410  }
  
    | ↓ open down ↓ | 304 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX