Print this page
    
update to acpica-unix2-20140114
acpica-unix2-20130823
PANKOVs restructure
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/intel/io/acpica/executer/exmutex.c
          +++ new/usr/src/common/acpica/components/executer/exmutex.c
   1      -
   2    1  /******************************************************************************
   3    2   *
   4    3   * Module Name: exmutex - ASL Mutex Acquire/Release functions
   5    4   *
   6    5   *****************************************************************************/
   7    6  
   8    7  /*
   9      - * Copyright (C) 2000 - 2011, Intel Corp.
        8 + * Copyright (C) 2000 - 2014, Intel Corp.
  10    9   * All rights reserved.
  11   10   *
  12   11   * Redistribution and use in source and binary forms, with or without
  13   12   * modification, are permitted provided that the following conditions
  14   13   * are met:
  15   14   * 1. Redistributions of source code must retain the above copyright
  16   15   *    notice, this list of conditions, and the following disclaimer,
  17   16   *    without modification.
  18   17   * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19   18   *    substantially similar to the "NO WARRANTY" disclaimer below
  20   19   *    ("Disclaimer") and any redistribution must be conditioned upon
  21   20   *    including a substantially similar Disclaimer requirement for further
  22   21   *    binary redistribution.
  23   22   * 3. Neither the names of the above-listed copyright holders nor the names
  24   23   *    of any contributors may be used to endorse or promote products derived
  25   24   *    from this software without specific prior written permission.
  26   25   *
  27   26   * Alternatively, this software may be distributed under the terms of the
  28   27   * GNU General Public License ("GPL") version 2 as published by the Free
  29   28   * Software Foundation.
  30   29   *
  31   30   * NO WARRANTY
  32   31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33   32   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34   33   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35   34   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36   35   * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37   36   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38   37   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39   38   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40   39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41   40   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42   41   * POSSIBILITY OF SUCH DAMAGES.
  43   42   */
  44   43  
  45   44  #define __EXMUTEX_C__
  46   45  
  47   46  #include "acpi.h"
  48   47  #include "accommon.h"
  49   48  #include "acinterp.h"
  50   49  #include "acevents.h"
  51   50  
  52   51  #define _COMPONENT          ACPI_EXECUTER
  53   52          ACPI_MODULE_NAME    ("exmutex")
  54   53  
  55   54  /* Local prototypes */
  56   55  
  57   56  static void
  58   57  AcpiExLinkMutex (
  59   58      ACPI_OPERAND_OBJECT     *ObjDesc,
  60   59      ACPI_THREAD_STATE       *Thread);
  61   60  
  62   61  
  63   62  /*******************************************************************************
  64   63   *
  65   64   * FUNCTION:    AcpiExUnlinkMutex
  66   65   *
  67   66   * PARAMETERS:  ObjDesc             - The mutex to be unlinked
  68   67   *
  69   68   * RETURN:      None
  70   69   *
  71   70   * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
  72   71   *
  73   72   ******************************************************************************/
  74   73  
  75   74  void
  76   75  AcpiExUnlinkMutex (
  77   76      ACPI_OPERAND_OBJECT     *ObjDesc)
  78   77  {
  79   78      ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
  80   79  
  81   80  
  82   81      if (!Thread)
  83   82      {
  84   83          return;
  85   84      }
  86   85  
  87   86      /* Doubly linked list */
  88   87  
  89   88      if (ObjDesc->Mutex.Next)
  90   89      {
  91   90          (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
  92   91      }
  93   92  
  94   93      if (ObjDesc->Mutex.Prev)
  95   94      {
  96   95          (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
  97   96  
  98   97          /*
  99   98           * Migrate the previous sync level associated with this mutex to
 100   99           * the previous mutex on the list so that it may be preserved.
 101  100           * This handles the case where several mutexes have been acquired
 102  101           * at the same level, but are not released in opposite order.
 103  102           */
 104  103          (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
 105  104              ObjDesc->Mutex.OriginalSyncLevel;
 106  105      }
 107  106      else
 108  107      {
 109  108          Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
 110  109      }
 111  110  }
 112  111  
 113  112  
 114  113  /*******************************************************************************
 115  114   *
 116  115   * FUNCTION:    AcpiExLinkMutex
 117  116   *
 118  117   * PARAMETERS:  ObjDesc             - The mutex to be linked
 119  118   *              Thread              - Current executing thread object
 120  119   *
 121  120   * RETURN:      None
 122  121   *
 123  122   * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
 124  123   *
 125  124   ******************************************************************************/
 126  125  
 127  126  static void
 128  127  AcpiExLinkMutex (
 129  128      ACPI_OPERAND_OBJECT     *ObjDesc,
 130  129      ACPI_THREAD_STATE       *Thread)
 131  130  {
 132  131      ACPI_OPERAND_OBJECT     *ListHead;
 133  132  
 134  133  
 135  134      ListHead = Thread->AcquiredMutexList;
 136  135  
 137  136      /* This object will be the first object in the list */
 138  137  
 139  138      ObjDesc->Mutex.Prev = NULL;
 140  139      ObjDesc->Mutex.Next = ListHead;
 141  140  
 142  141      /* Update old first object to point back to this object */
 143  142  
 144  143      if (ListHead)
 145  144      {
 146  145          ListHead->Mutex.Prev = ObjDesc;
 147  146      }
 148  147  
 149  148      /* Update list head */
 150  149  
 151  150      Thread->AcquiredMutexList = ObjDesc;
 152  151  }
 153  152  
 154  153  
 155  154  /*******************************************************************************
 156  155   *
 157  156   * FUNCTION:    AcpiExAcquireMutexObject
 158  157   *
 159  158   * PARAMETERS:  Timeout             - Timeout in milliseconds
 160  159   *              ObjDesc             - Mutex object
 161  160   *              ThreadId            - Current thread state
 162  161   *
 163  162   * RETURN:      Status
 164  163   *
 165  164   * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
 166  165   *              path that supports multiple acquires by the same thread.
 167  166   *
 168  167   * MUTEX:       Interpreter must be locked
 169  168   *
 170  169   * NOTE: This interface is called from three places:
 171  170   * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
 172  171   * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
 173  172   *    global lock
 174  173   * 3) From the external interface, AcpiAcquireGlobalLock
 175  174   *
 176  175   ******************************************************************************/
 177  176  
 178  177  ACPI_STATUS
 179  178  AcpiExAcquireMutexObject (
 180  179      UINT16                  Timeout,
 181  180      ACPI_OPERAND_OBJECT     *ObjDesc,
 182  181      ACPI_THREAD_ID          ThreadId)
 183  182  {
 184  183      ACPI_STATUS             Status;
 185  184  
 186  185  
 187  186      ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
 188  187  
 189  188  
 190  189      if (!ObjDesc)
 191  190      {
 192  191          return_ACPI_STATUS (AE_BAD_PARAMETER);
 193  192      }
 194  193  
 195  194      /* Support for multiple acquires by the owning thread */
 196  195  
 197  196      if (ObjDesc->Mutex.ThreadId == ThreadId)
 198  197      {
 199  198          /*
 200  199           * The mutex is already owned by this thread, just increment the
 201  200           * acquisition depth
 202  201           */
 203  202          ObjDesc->Mutex.AcquisitionDepth++;
 204  203          return_ACPI_STATUS (AE_OK);
 205  204      }
 206  205  
 207  206      /* Acquire the mutex, wait if necessary. Special case for Global Lock */
 208  207  
 209  208      if (ObjDesc == AcpiGbl_GlobalLockMutex)
 210  209      {
 211  210          Status = AcpiEvAcquireGlobalLock (Timeout);
 212  211      }
 213  212      else
 214  213      {
 215  214          Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
 216  215                      Timeout);
 217  216      }
 218  217  
 219  218      if (ACPI_FAILURE (Status))
 220  219      {
 221  220          /* Includes failure from a timeout on TimeDesc */
 222  221  
 223  222          return_ACPI_STATUS (Status);
 224  223      }
 225  224  
 226  225      /* Acquired the mutex: update mutex object */
 227  226  
 228  227      ObjDesc->Mutex.ThreadId = ThreadId;
 229  228      ObjDesc->Mutex.AcquisitionDepth = 1;
 230  229      ObjDesc->Mutex.OriginalSyncLevel = 0;
 231  230      ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
 232  231  
 233  232      return_ACPI_STATUS (AE_OK);
 234  233  }
 235  234  
 236  235  
 237  236  /*******************************************************************************
 238  237   *
 239  238   * FUNCTION:    AcpiExAcquireMutex
 240  239   *
 241  240   * PARAMETERS:  TimeDesc            - Timeout integer
 242  241   *              ObjDesc             - Mutex object
 243  242   *              WalkState           - Current method execution state
 244  243   *
 245  244   * RETURN:      Status
 246  245   *
 247  246   * DESCRIPTION: Acquire an AML mutex
 248  247   *
 249  248   ******************************************************************************/
 250  249  
 251  250  ACPI_STATUS
 252  251  AcpiExAcquireMutex (
 253  252      ACPI_OPERAND_OBJECT     *TimeDesc,
 254  253      ACPI_OPERAND_OBJECT     *ObjDesc,
 255  254      ACPI_WALK_STATE         *WalkState)
 256  255  {
 257  256      ACPI_STATUS             Status;
 258  257  
 259  258  
 260  259      ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
 261  260  
 262  261  
 263  262      if (!ObjDesc)
 264  263      {
 265  264          return_ACPI_STATUS (AE_BAD_PARAMETER);
 266  265      }
 267  266  
 268  267      /* Must have a valid thread state struct */
 269  268  
 270  269      if (!WalkState->Thread)
 271  270      {
 272  271          ACPI_ERROR ((AE_INFO,
 273  272              "Cannot acquire Mutex [%4.4s], null thread info",
 274  273              AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 275  274          return_ACPI_STATUS (AE_AML_INTERNAL);
 276  275      }
 277  276  
 278  277      /*
 279  278       * Current sync level must be less than or equal to the sync level of the
 280  279       * mutex. This mechanism provides some deadlock prevention
 281  280       */
 282  281      if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
 283  282      {
 284  283          ACPI_ERROR ((AE_INFO,
 285  284              "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
 286  285              AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 287  286              WalkState->Thread->CurrentSyncLevel));
 288  287          return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 289  288      }
 290  289  
 291  290      Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
 292  291                  ObjDesc, WalkState->Thread->ThreadId);
 293  292      if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
 294  293      {
 295  294          /* Save Thread object, original/current sync levels */
 296  295  
 297  296          ObjDesc->Mutex.OwnerThread = WalkState->Thread;
 298  297          ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
 299  298          WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
 300  299  
 301  300          /* Link the mutex to the current thread for force-unlock at method exit */
 302  301  
 303  302          AcpiExLinkMutex (ObjDesc, WalkState->Thread);
 304  303      }
 305  304  
 306  305      return_ACPI_STATUS (Status);
 307  306  }
 308  307  
 309  308  
 310  309  /*******************************************************************************
 311  310   *
 312  311   * FUNCTION:    AcpiExReleaseMutexObject
 313  312   *
 314  313   * PARAMETERS:  ObjDesc             - The object descriptor for this op
 315  314   *
 316  315   * RETURN:      Status
 317  316   *
 318  317   * DESCRIPTION: Release a previously acquired Mutex, low level interface.
 319  318   *              Provides a common path that supports multiple releases (after
 320  319   *              previous multiple acquires) by the same thread.
 321  320   *
 322  321   * MUTEX:       Interpreter must be locked
 323  322   *
 324  323   * NOTE: This interface is called from three places:
 325  324   * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
 326  325   * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
 327  326   *    global lock
 328  327   * 3) From the external interface, AcpiReleaseGlobalLock
 329  328   *
 330  329   ******************************************************************************/
 331  330  
 332  331  ACPI_STATUS
 333  332  AcpiExReleaseMutexObject (
  
    | ↓ open down ↓ | 314 lines elided | ↑ open up ↑ | 
 334  333      ACPI_OPERAND_OBJECT     *ObjDesc)
 335  334  {
 336  335      ACPI_STATUS             Status = AE_OK;
 337  336  
 338  337  
 339  338      ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
 340  339  
 341  340  
 342  341      if (ObjDesc->Mutex.AcquisitionDepth == 0)
 343  342      {
 344      -        return (AE_NOT_ACQUIRED);
      343 +        return_ACPI_STATUS (AE_NOT_ACQUIRED);
 345  344      }
 346  345  
 347  346      /* Match multiple Acquires with multiple Releases */
 348  347  
 349  348      ObjDesc->Mutex.AcquisitionDepth--;
 350  349      if (ObjDesc->Mutex.AcquisitionDepth != 0)
 351  350      {
 352  351          /* Just decrement the depth and return */
 353  352  
 354  353          return_ACPI_STATUS (AE_OK);
 355  354      }
 356  355  
 357  356      if (ObjDesc->Mutex.OwnerThread)
 358  357      {
 359  358          /* Unlink the mutex from the owner's list */
 360  359  
 361  360          AcpiExUnlinkMutex (ObjDesc);
 362  361          ObjDesc->Mutex.OwnerThread = NULL;
 363  362      }
 364  363  
 365  364      /* Release the mutex, special case for Global Lock */
 366  365  
 367  366      if (ObjDesc == AcpiGbl_GlobalLockMutex)
 368  367      {
 369  368          Status = AcpiEvReleaseGlobalLock ();
 370  369      }
 371  370      else
 372  371      {
 373  372          AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 374  373      }
 375  374  
 376  375      /* Clear mutex info */
 377  376  
 378  377      ObjDesc->Mutex.ThreadId = 0;
 379  378      return_ACPI_STATUS (Status);
 380  379  }
 381  380  
 382  381  
 383  382  /*******************************************************************************
 384  383   *
 385  384   * FUNCTION:    AcpiExReleaseMutex
 386  385   *
 387  386   * PARAMETERS:  ObjDesc             - The object descriptor for this op
 388  387   *              WalkState           - Current method execution state
 389  388   *
 390  389   * RETURN:      Status
 391  390   *
 392  391   * DESCRIPTION: Release a previously acquired Mutex.
 393  392   *
 394  393   ******************************************************************************/
 395  394  
 396  395  ACPI_STATUS
 397  396  AcpiExReleaseMutex (
 398  397      ACPI_OPERAND_OBJECT     *ObjDesc,
 399  398      ACPI_WALK_STATE         *WalkState)
 400  399  {
 401  400      ACPI_STATUS             Status = AE_OK;
 402  401      UINT8                   PreviousSyncLevel;
 403  402      ACPI_THREAD_STATE       *OwnerThread;
 404  403  
 405  404  
 406  405      ACPI_FUNCTION_TRACE (ExReleaseMutex);
 407  406  
 408  407  
 409  408      if (!ObjDesc)
 410  409      {
 411  410          return_ACPI_STATUS (AE_BAD_PARAMETER);
 412  411      }
 413  412  
 414  413      OwnerThread = ObjDesc->Mutex.OwnerThread;
 415  414  
 416  415      /* The mutex must have been previously acquired in order to release it */
 417  416  
 418  417      if (!OwnerThread)
 419  418      {
 420  419          ACPI_ERROR ((AE_INFO,
 421  420              "Cannot release Mutex [%4.4s], not acquired",
 422  421              AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 423  422          return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
 424  423      }
 425  424  
 426  425      /* Must have a valid thread ID */
 427  426  
 428  427      if (!WalkState->Thread)
 429  428      {
 430  429          ACPI_ERROR ((AE_INFO,
 431  430              "Cannot release Mutex [%4.4s], null thread info",
 432  431              AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 433  432          return_ACPI_STATUS (AE_AML_INTERNAL);
 434  433      }
 435  434  
 436  435      /*
 437  436       * The Mutex is owned, but this thread must be the owner.
 438  437       * Special case for Global Lock, any thread can release
 439  438       */
 440  439      if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
 441  440          (ObjDesc != AcpiGbl_GlobalLockMutex))
 442  441      {
 443  442          ACPI_ERROR ((AE_INFO,
 444  443              "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
 445  444              (UINT32) WalkState->Thread->ThreadId,
 446  445              AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 447  446              (UINT32) OwnerThread->ThreadId));
 448  447          return_ACPI_STATUS (AE_AML_NOT_OWNER);
 449  448      }
 450  449  
 451  450      /*
 452  451       * The sync level of the mutex must be equal to the current sync level. In
 453  452       * other words, the current level means that at least one mutex at that
 454  453       * level is currently being held. Attempting to release a mutex of a
 455  454       * different level can only mean that the mutex ordering rule is being
 456  455       * violated. This behavior is clarified in ACPI 4.0 specification.
 457  456       */
 458  457      if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
 459  458      {
 460  459          ACPI_ERROR ((AE_INFO,
 461  460              "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
 462  461              AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 463  462              ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
 464  463          return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 465  464      }
 466  465  
 467  466      /*
 468  467       * Get the previous SyncLevel from the head of the acquired mutex list.
 469  468       * This handles the case where several mutexes at the same level have been
 470  469       * acquired, but are not released in reverse order.
 471  470       */
 472  471      PreviousSyncLevel =
 473  472          OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
 474  473  
 475  474      Status = AcpiExReleaseMutexObject (ObjDesc);
 476  475      if (ACPI_FAILURE (Status))
 477  476      {
 478  477          return_ACPI_STATUS (Status);
 479  478      }
 480  479  
 481  480      if (ObjDesc->Mutex.AcquisitionDepth == 0)
 482  481      {
 483  482          /* Restore the previous SyncLevel */
 484  483  
 485  484          OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
 486  485      }
 487  486  
 488  487      return_ACPI_STATUS (Status);
 489  488  }
 490  489  
 491  490  
 492  491  /*******************************************************************************
 493  492   *
 494  493   * FUNCTION:    AcpiExReleaseAllMutexes
 495  494   *
 496  495   * PARAMETERS:  Thread              - Current executing thread object
 497  496   *
 498  497   * RETURN:      Status
 499  498   *
 500  499   * DESCRIPTION: Release all mutexes held by this thread
 501  500   *
 502  501   * NOTE: This function is called as the thread is exiting the interpreter.
 503  502   * Mutexes are not released when an individual control method is exited, but
 504  503   * only when the parent thread actually exits the interpreter. This allows one
 505  504   * method to acquire a mutex, and a different method to release it, as long as
 506  505   * this is performed underneath a single parent control method.
 507  506   *
  
    | ↓ open down ↓ | 153 lines elided | ↑ open up ↑ | 
 508  507   ******************************************************************************/
 509  508  
 510  509  void
 511  510  AcpiExReleaseAllMutexes (
 512  511      ACPI_THREAD_STATE       *Thread)
 513  512  {
 514  513      ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
 515  514      ACPI_OPERAND_OBJECT     *ObjDesc;
 516  515  
 517  516  
 518      -    ACPI_FUNCTION_ENTRY ();
      517 +    ACPI_FUNCTION_NAME (ExReleaseAllMutexes);
 519  518  
 520  519  
 521  520      /* Traverse the list of owned mutexes, releasing each one */
 522  521  
 523  522      while (Next)
 524  523      {
 525  524          ObjDesc = Next;
 526  525          Next = ObjDesc->Mutex.Next;
 527  526  
 528  527          ObjDesc->Mutex.Prev = NULL;
 529  528          ObjDesc->Mutex.Next = NULL;
 530  529          ObjDesc->Mutex.AcquisitionDepth = 0;
 531  530  
      531 +        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
      532 +            "Force-releasing held mutex: %p\n", ObjDesc));
      533 +
 532  534          /* Release the mutex, special case for Global Lock */
 533  535  
 534  536          if (ObjDesc == AcpiGbl_GlobalLockMutex)
 535  537          {
 536  538              /* Ignore errors */
 537  539  
 538  540              (void) AcpiEvReleaseGlobalLock ();
 539  541          }
 540  542          else
 541  543          {
 542  544              AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 543  545          }
 544  546  
 545  547          /* Mark mutex unowned */
 546  548  
 547  549          ObjDesc->Mutex.OwnerThread = NULL;
 548  550          ObjDesc->Mutex.ThreadId = 0;
 549  551  
 550  552          /* Update Thread SyncLevel (Last mutex is the important one) */
 551  553  
 552  554          Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
 553  555      }
 554  556  }
  
    | ↓ open down ↓ | 13 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX