home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / Papers / atomicity / Code / atomicity.h < prev   
Encoding:
C/C++ Source or Header  |  1999-06-25  |  19.3 KB  |  646 lines  |  [TEXT/CWIE]

  1. /****************************************************************************************
  2.     atomicity.h
  3.     
  4.         The grabbing hands
  5.             grab all they can.
  6.         Everything counts
  7.             in large amounts.
  8.     
  9.     Copyright © 1998-1999 Red Shed Software. All rights reserved.
  10.     by Jonathan 'Wolf' Rentzsch (jon@redshed.net)
  11.     This code requires a 68020 or later or any PowerPC.
  12.     
  13.     Commenter    Date                Comment
  14.     ---------    -----------------    -----------------------------------------------------
  15.     wolf        Mon, Oct 26, 1998    Created as AtomicStacks.h/AtomicStacks.c.
  16.     wolf        Mon, Nov 9, 1998    PowerPC code rolled in.
  17.     wolf        Wed, Nov 18, 1998    Rolled in AtomicQueue code.
  18.                                     
  19.                                     Renamed to AtomicLists.h/AtomicLists.c.
  20.     wolf        Mon, Nov 23, 1998    Added guarded lists code.
  21.     wolf        Wed, Nov 25, 1998    Added ___Off functions and ___Type macros.
  22.                                     
  23.                                     Reworked file to be more comprehensible &
  24.                                     navigatible.
  25.     wolf        Mon, Nov 30, 1998    PushGuardedAtomicStack() was modified to be atomic.
  26.     wolf        Wed, Dec 2, 1998    Added requirement checking.
  27.     wolf        Thu, Dec 24, 1998    Added StealGuardedAtomicStackType() macro.
  28.     wolf        Tue, Mar 23, 1999    Added conditionally compiled 'extern "C" {}'
  29.                                     declaration.
  30.     wolf        Mon, Mar 29, 1999    Added Open Transport compatibility options.
  31.                                     
  32.                                     Now uses size_t and offsetof() instead of long and
  33.                                     my offof() macro, respectively.
  34.                                     
  35.                                     Renamed to atomicity.h/atomicity.c.
  36.     wolf        Wed, Mar 31, 1999    Reworked OpenTransport compatibility & documented it.
  37.                                     
  38.                                     Added AtomicLocks.
  39.                                     
  40.                                     Now can stand without require.h (just comment it out
  41.                                     in atomicity.c).
  42.                                     
  43.                                     The new public AtomicLocks code obsoleted my private
  44.                                     IncrementGuardedAtomicStack() function, so the
  45.                                     function has been removed and the Guarded Stack (and
  46.                                     thus the Guarded Queue) code has been moved to Atomic
  47.                                     Locks.
  48.     wolf        Thu, Apr 15, 1999    Added Peek[Guarded]AtomicQueue[Off|Type]().
  49.     wolf        Thu, Apr 22, 1999    Moved the OpenTransport compatibility settings into
  50.                                     their own file: atomicity.config.h.
  51.     wolf        Fri, Apr 30, 1999    Added Peek[Guarded]AtomicStack[Off|Type].
  52.     wolf        Mon, May 3, 1999    Changed name of AtomicQueue's fields from (pushed,
  53.                                     toPop) to (input, output) to ease understanding.
  54.                                     
  55.                                     Rearranged the parameter order of the ___Off and
  56.                                     ___Type functions. Before it was ( OFFSET, STACK )
  57.                                     and ( STRUCTURE, FIELD, STACK ). Now it's
  58.                                     ( STACK, OFFSET ) and ( STACK, STRUCTURE, FIELD ).
  59.                                     This breaks existing code, but the fix is simple and
  60.                                     the new way is easier to remember. I wanted to make
  61.                                     this change before I distributed my code on the
  62.                                     MacHack 99 CD-ROM.
  63.     wolf        Fri, May 7, 1999    The Open Transport Compatibility Options weren't
  64.                                     working correctly for some reason (apparently my
  65.                                     concepts about what !defined() means is wrong).
  66.                                     I reworked it a little and now all is well.
  67.                                     
  68.                                     Added (OpenAtomicity(), CloseAtomicity()) macros
  69.                                     that call thru to (InitOpenTransport(),
  70.                                     CloseOpenTransport()) as needed depending on the
  71.                                     settings in atomicity.config.h.
  72.     
  73.     ************************************************************************************/
  74.  
  75. #ifndef        _atomicity_
  76. #define        _atomicity_
  77.  
  78. #include    <stddef.h>
  79. #include    "atomicity.config.h"
  80. #include    "extern_c.h"
  81.  
  82. begin_extern_c
  83.  
  84. /****************************************************************************************
  85. *    
  86. *    Atomic Stacks
  87. *    
  88. ****************************************************************************************/
  89. #pragma mark    --Atomic Stacks--
  90.  
  91. typedef    struct    AtomicElement    AtomicElement, AtomicStack;
  92.  
  93. struct    AtomicElement    {
  94.     AtomicElement    *next;
  95.     
  96. #ifdef    __cplusplus
  97.     AtomicElement() : next( nil ){}
  98. #endif
  99. };
  100.  
  101. /**************************
  102. *    
  103. *    Atomic Stack Functions
  104. *
  105. *    An atomic stack is an atomic last-in-first-out list.
  106. *
  107. *    These are the lowest level functions to atomically manipulate stacks.
  108. *    
  109. **************************/
  110. #pragma mark    --Atomic Stack Functions--
  111.  
  112. //    Atomically set element->next to stack->next, set stack->next to element.
  113.  
  114.     extern
  115.     pascal
  116.     void
  117. MyPushAtomicStack(
  118.     AtomicElement    *element,
  119.     AtomicStack        *stack );
  120.  
  121. //    Atomically store stack->next, set stack->next to stack->next->next, and return the
  122. //    first element. It's okay if stack->next == nil: PopAtomicStack() will return nil.
  123.  
  124.     extern
  125.     pascal
  126.     AtomicElement*
  127. MyPopAtomicStack(
  128.     AtomicStack        *stack );
  129.  
  130. //    Atomically store stack->next, set stack->next to nil, and return the
  131. //    first element. It's okay if stack->next == nil: StealAtomicStack() will return nil.
  132.  
  133.     extern
  134.     pascal
  135.     AtomicElement*
  136. MyStealAtomicStack(
  137.     AtomicStack        *stack );
  138.  
  139. //    Simply returns stack->next.
  140.  
  141.     extern
  142.     pascal
  143.     AtomicElement*
  144. PeekAtomicStack(
  145.     AtomicStack        *stack );
  146.  
  147. /**************************
  148. *    
  149. *    Atomic Stack Offset Functions
  150. *
  151. *    Convenience routines for when the AtomicElement field in your structure
  152. *    can't be the first field. You supply the coercions and field offset.
  153. *    
  154. **************************/
  155. #pragma mark    --Atomic Stack Offset Functions--
  156.  
  157. //    Adds offset to element, and calls PushAtomicStack().
  158.  
  159.     extern
  160.     pascal
  161.     void
  162. PushAtomicStackOff(
  163.     void            *element,
  164.     AtomicStack        *stack,
  165.     size_t            offset );
  166.  
  167. //    Calls PopAtomicStack(), if the result is not nil, subtracts offset from the result
  168. //    and returns it.
  169.  
  170.     extern
  171.     pascal
  172.     AtomicElement*
  173. PopAtomicStackOff(
  174.     AtomicStack        *stack,
  175.     size_t            offset );
  176.  
  177. //    Calls StealAtomicStack(), if the result is not nil, subtracts offset from the result
  178. //    and returns it.
  179.  
  180.     extern
  181.     pascal
  182.     AtomicElement*
  183. StealAtomicStackOff(
  184.     AtomicStack        *stack,
  185.     size_t            offset );
  186.  
  187. //    Calls PeekAtomicStack(), if the result is not nil, subtracts offset from the result
  188. //    and returns it.
  189.  
  190.     extern
  191.     pascal
  192.     AtomicElement*
  193. PeekAtomicStackOff(
  194.     AtomicStack        *stack,
  195.     size_t            offset );
  196.  
  197. /**************************
  198. *    
  199. *    Atomic Stack Type Functions
  200. *
  201. *    Convenience routines for when the AtomicElement field in your structure
  202. *    can't be the first field. You supply the structure and field names. It does
  203. *    the coercions and offsets for you.
  204. *    
  205. **************************/
  206. #pragma mark    --Atomic Stack Type Functions--
  207.  
  208. #define        PushAtomicStackType( ELEMENT, STACK, STRUCTURE, FIELD )    \
  209.                 PushAtomicStackOff( (ELEMENT), (STACK), offsetof( STRUCTURE, FIELD ) )
  210.  
  211. #define        PopAtomicStackType( STACK, STRUCTURE, FIELD )    \
  212.                 ((STRUCTURE*) PopAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  213.  
  214. #define        StealAtomicStackType( STACK, STRUCTURE, FIELD )    \
  215.                 ((STRUCTURE*) StealAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  216.  
  217. #define        PeekAtomicStackType( STACK, STRUCTURE, FIELD )    \
  218.                 ((STRUCTURE*) PeekAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  219.  
  220. /****************************************************************************************
  221. *    
  222. *    AtomicLock
  223. *    
  224. ****************************************************************************************/
  225. #pragma mark    -
  226. #pragma mark    --Atomic Locks--
  227.  
  228. typedef    unsigned    long    AtomicLock;
  229.  
  230.     extern
  231.     pascal
  232.     long    //    Non-zero if successfully grabbed.
  233. MyGrabAtomicLock(
  234.     AtomicLock    *lock );
  235.  
  236.     extern
  237.     void
  238. ReleaseAtomicLock(
  239.     AtomicLock    *lock );
  240.  
  241. /****************************************************************************************
  242.     Open Transport Compatibility Options
  243.  
  244.     Define DontUseOpenTransport *or* UseOpenTransportIfAvailable *or*
  245.     OnlyUseOpenTransport in the file atomicity.config.h. If you don't define any of
  246.     these, the default is UseOpenTransportIfAvailable.
  247.     
  248.     If you define UseOpenTransportIfAvailable or OnlyUseOpenTransport, you *must* call
  249.     InitOpenTransport() in the beginning of your application. If you don't want to
  250.     juggle whether or not to call InitOpenTransport(), simply always call
  251.     OpenAtomicity(). If you defined UseOpenTransportIfAvailable or OnlyUseOpenTransport,
  252.     it maps to InitOpenTransport(), otherwise it maps to noErr.
  253.     
  254.     DontUseOpenTransport:
  255.         o    Open Transport Libraries: Not Required.
  256.         o    Runtime Overhead: None.
  257.     
  258.     UseOpenTransportIfAvailable:
  259.         o    Open Transport Libraries: Required (preferably weakly imported).
  260.         o    Runtime Overhead: Small (larger if requirements checking is turned on).
  261.     
  262.     OnlyUseOpenTransport:
  263.         o    Open Transport Libraries: Required (preferably strongly imported).
  264.         o    Runtime Overhead: None.
  265.     
  266.     ************************************************************************************/
  267. #pragma mark    -
  268. #pragma mark    --Open Transport Compatibility Options--
  269.  
  270. #if        defined(DontUseOpenTransport)
  271.     #define    PushAtomicStack( ELEMENT, STACK )    MyPushAtomicStack( ELEMENT, STACK )
  272.     #define    PopAtomicStack( STACK )                MyPopAtomicStack( STACK )
  273.     #define    StealAtomicStack( STACK )            MyStealAtomicStack( STACK )
  274.     #define    GrabAtomicLock( LOCK )                MyGrabAtomicLock( LOCK )
  275.     #define    OpenAtomicity()                        noErr
  276.     #define    CloseAtomicity()                    
  277. #elif    defined(OnlyUseOpenTransport)
  278.     #include    "OpenTransport.h"
  279.     #define    PushAtomicStack( ELEMENT, STACK )    OTLIFOEnqueue( (OTLIFO*) STACK, (OTLink*) ELEMENT )
  280.     #define    PopAtomicStack( STACK )                (AtomicElement*) OTLIFODequeue( (OTLIFO*) STACK )
  281.     #define    StealAtomicStack( STACK )            (AtomicElement*) OTLIFOStealList( (OTLIFO*) STACK )
  282.     #define    GrabAtomicLock( LOCK )                OTCompareAndSwap32( 0, 1, LOCK )
  283.     #define    OpenAtomicity()                        InitOpenTransport()
  284.     #define    CloseAtomicity()                    CloseOpenTransport()
  285. #else    //    UseOpenTransportIfAvailable
  286.     #include    "OpenTransport.h"
  287.     extern    void                                PushAtomicStack( AtomicElement *element, AtomicStack *stack );
  288.     extern    AtomicElement*                         PopAtomicStack( AtomicStack *stack );
  289.     extern    AtomicElement*                         StealAtomicStack( AtomicStack *stack );
  290.     extern    Boolean                                GrabAtomicLock( AtomicLock *lock );
  291.     #define    OpenAtomicity()                        InitOpenTransport()
  292.     #define    CloseAtomicity()                    CloseOpenTransport()
  293. #endif
  294.  
  295. /****************************************************************************************
  296. *    
  297. *    Guarded Atomic Stacks
  298. *    
  299. ****************************************************************************************/
  300. #pragma mark    -
  301. #pragma mark    --Guarded Atomic Stacks--
  302.  
  303. typedef    struct    GuardedAtomicElement    GuardedAtomicElement;
  304.  
  305. struct    GuardedAtomicElement    {
  306.     GuardedAtomicElement    *next;
  307.     AtomicLock                lock;
  308.     
  309. #ifdef    __cplusplus
  310.     GuardedAtomicElement() : next( nil ), lock( 0 ){}
  311. #endif
  312. };
  313.  
  314. /**************************
  315. *    
  316. *    Guarded Atomic Stack Functions
  317. *
  318. *    A guarded atomic stack doesn't allow an element to be pushed more than once.
  319. *    Pushing an element more than once on a stack corrupts the stack into a nasty
  320. *    circular list. These functions test whether the element in already on a stack
  321. *    before blindly pushing the element, saving your stack from corruption.
  322. *    
  323. **************************/
  324. #pragma mark    --Guarded Atomic Stack Functions--
  325.  
  326. //    Call GrabAtomicLock() on element->lock. If successful, call PushAtomicStack() and
  327. //    return true. Otherwise return false.
  328.  
  329.     extern
  330.     pascal
  331.     long
  332. PushGuardedAtomicStack(
  333.     GuardedAtomicElement    *element,
  334.     AtomicStack                *stack );
  335.  
  336. //    Call PopAtomicStack(). If the result isn't nil, call ReleaseAtomicLock() on the popped
  337. //    element->lock and return the popped element. Otherwise return nil.
  338.  
  339.     extern
  340.     pascal
  341.     GuardedAtomicElement*
  342. PopGuardedAtomicStack(
  343.     AtomicStack                *stack );
  344.  
  345. //    Simply returns stack->next.
  346.  
  347.     extern
  348.     pascal
  349.     GuardedAtomicElement*
  350. PeekGuardedAtomicStack(
  351.     AtomicStack                *stack );
  352.  
  353. #define        StealGuardedAtomicStack( STACK )    StealAtomicStack( STACK )
  354.  
  355. /**************************
  356. *    
  357. *    Guarded Atomic Stack Offset Functions
  358. *
  359. *    Convenience routines for when the GuardedAtomicElement field in your structure
  360. *    can't be the first field. You supply the coercions and field offset.
  361. *    
  362. **************************/
  363. #pragma mark    --Guarded Atomic Stack Offset Functions--
  364.  
  365. //    Adds offset to element, and calls PushGuardedAtomicStack().
  366.  
  367.     extern
  368.     pascal
  369.     long
  370. PushGuardedAtomicStackOff(
  371.     void            *element,
  372.     AtomicStack        *stack,
  373.     size_t            offset );
  374.  
  375. //    Calls PopGuardedAtomicStack(), if the result is not nil, subtracts offset from
  376. //    the result and returns it.
  377.  
  378.     extern
  379.     pascal
  380.     GuardedAtomicElement*
  381. PopGuardedAtomicStackOff(
  382.     AtomicStack        *stack,
  383.     size_t            offset );
  384.  
  385. //    Calls PeekGuardedAtomicStack(), if the result is not nil, subtracts offset from
  386. //    the result and returns it.
  387.  
  388.     extern
  389.     pascal
  390.     GuardedAtomicElement*
  391. PeekGuardedAtomicStackOff(
  392.     AtomicStack        *stack,
  393.     size_t            offset );
  394.  
  395. #define        StealGuardedAtomicStackOff( STACK, OFF )    StealAtomicStackOff( STACK, OFF )
  396.  
  397. /**************************
  398. *    
  399. *    Guarded Atomic Stack Type Functions
  400. *
  401. *    Convenience routines for when the GuardedAtomicElement field in your structure
  402. *    can't be the first field. You supply the structure and field names. It does
  403. *    the coercions and offsets for you.
  404. *    
  405. **************************/
  406. #pragma mark    --Guarded Atomic Stack Type Functions--
  407.  
  408. #define        PushGuardedAtomicStackType( ELEMENT, STACK, STRUCTURE, FIELD )    \
  409.                 PushGuardedAtomicStackOff( (ELEMENT), (STACK), offsetof( STRUCTURE, FIELD ) )
  410.  
  411. #define        PopGuardedAtomicStackType( STACK, STRUCTURE, FIELD )    \
  412.                 ((STRUCTURE*) PopGuardedAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  413.  
  414. #define        StealGuardedAtomicStackType( STACK, STRUCTURE, FIELD )    \
  415.                 ((STRUCTURE*) StealGuardedAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  416.  
  417. #define        PeekGuardedAtomicStackType( STACK, STRUCTURE, FIELD )    \
  418.                 ((STRUCTURE*) PeekAtomicStackOff( (STACK), offsetof( STRUCTURE, FIELD ) ))
  419.  
  420. /****************************************************************************************
  421. *    
  422. *    Atomic Queues
  423. *    
  424. ****************************************************************************************/
  425. #pragma mark    -
  426. #pragma mark    --Atomic Queues--
  427.  
  428. typedef    struct    {
  429.     AtomicStack        input;
  430.     AtomicStack        output;
  431. }    AtomicQueue;
  432.  
  433. /**************************
  434. *    
  435. *    Atomic Queue Functions
  436. *
  437. *    An atomic queue is an atomic first-in-first-out list.
  438. *    
  439. **************************/
  440. #pragma mark    --Atomic Queue Functions--
  441.  
  442. //    Simply calls PushAtomicStack() with queue->input.
  443.  
  444.     extern
  445.     pascal
  446.     void
  447. PushAtomicQueue(
  448.     AtomicElement    *element,
  449.     AtomicQueue        *queue );
  450.  
  451. //    Calls PopAtomicStack() with queue->output. If the result is not nil,
  452. //    PopAtomicQueue() returns it. Otherwise PopAtomicQueue() calls
  453. //    StealAtomicList() on queue->input. If the result is not nil,
  454. //    PopAtomicQueue() calls PopAtomicStack() on each element in the stolen stack,
  455. //    then calling PushAtomicStack() with queue->output, effectively "reversing" the
  456. //    stack into a queue.
  457.  
  458.     extern
  459.     pascal
  460.     AtomicElement*
  461. PopAtomicQueue(
  462.     AtomicQueue        *queue );
  463.  
  464. //    Calls PopAtomicQueue(). If the result is not nil, then it calls PushAtomicStack()
  465. //    with the result on queue->output.
  466.  
  467.     extern
  468.     pascal
  469.     AtomicElement*
  470. PeekAtomicQueue(
  471.     AtomicQueue        *queue );
  472.  
  473. /**************************
  474. *    
  475. *    Atomic Queue Offset Functions
  476. *
  477. *    Convenience routines for when the AtomicElement field in your structure
  478. *    can't be the first field. You supply the coercions and field offset.
  479. *    
  480. **************************/
  481. #pragma mark    --Atomic Queue Offset Functions--
  482.  
  483. //    Adds offset to element, and calls PushAtomicQueue().
  484.  
  485.     extern
  486.     pascal
  487.     void
  488. PushAtomicQueueOff(
  489.     void            *element,
  490.     AtomicQueue        *queue,
  491.     size_t            offset );
  492.  
  493. //    Calls PopAtomicQueue(), if the result is not nil, subtracts offset from
  494. //    the result and returns it.
  495.  
  496.     extern
  497.     pascal
  498.     AtomicElement*
  499. PopAtomicQueueOff(
  500.     AtomicQueue        *queue,
  501.     size_t            offset );
  502.  
  503. //    Calls PeekAtomicStack(). If the result is not nil, subtracts offset from
  504. //    the result and returns it.
  505.  
  506.     extern
  507.     pascal
  508.     AtomicElement*
  509. PeekAtomicQueueOff(
  510.     AtomicQueue        *queue,
  511.     size_t            offset );
  512.  
  513. /**************************
  514. *    
  515. *    Atomic Queue Type Functions
  516. *
  517. *    Convenience routines for when the AtomicElement field in your structure
  518. *    can't be the first field. You supply the structure and field names. It does
  519. *    the coercions and offsets for you.
  520. *    
  521. **************************/
  522. #pragma mark    --Atomic Queue Type Functions--
  523.  
  524. #define        PushAtomicQueueType( ELEMENT, QUEUE, STRUCTURE, FIELD )    \
  525.                 PushAtomicQueueOff( (ELEMENT), (QUEUE), offsetof( STRUCTURE, FIELD ) )
  526.  
  527. #define        PopAtomicQueueType( QUEUE, STRUCTURE, FIELD )    \
  528.                 ((STRUCTURE*) PopAtomicQueueOff( (QUEUE), offsetof( STRUCTURE, FIELD ) ))
  529.  
  530. #define        PeekAtomicQueueType( QUEUE, STRUCTURE, FIELD )    \
  531.                 ((STRUCTURE*) PeekAtomicQueueOff( (QUEUE), offsetof( STRUCTURE, FIELD ) ))
  532.  
  533. /****************************************************************************************
  534. *    
  535. *    Guarded Atomic Queues
  536. *    
  537. ****************************************************************************************/
  538. #pragma mark    -
  539. #pragma mark    --Guarded Atomic Queues--
  540.  
  541. /**************************
  542. *    
  543. *    Guarded Atomic Queue Functions
  544. *
  545. *    A guarded atomic queue is an atomic queue that doesn't allow an element to be
  546. *    pushed more than once.
  547. *    
  548. **************************/
  549. #pragma mark    --Guarded Atomic Queue Functions--
  550.  
  551. //    Simply calls PushGuardedAtomicStack() with queue->input.
  552.  
  553.     extern
  554.     pascal
  555.     long
  556. PushGuardedAtomicQueue(
  557.     GuardedAtomicElement    *element,
  558.     AtomicQueue                *queue );
  559.  
  560. //    Calls PopGuardedAtomicStack() with queue->output. If the result is not nil,
  561. //    PopGuardedAtomicQueue() returns it. Otherwise PopGuardedAtomicQueue() calls
  562. //    StealAtomicList() on queue->input. If the result is not nil,
  563. //    PopGuardedAtomicQueue() calls PopAtomicStack() on each element in the stolen stack,
  564. //    then calling PushAtomicStack() with queue->output, effectively "reversing" the
  565. //    stack into a queue.
  566.  
  567.     extern
  568.     pascal
  569.     GuardedAtomicElement*
  570. PopGuardedAtomicQueue(
  571.     AtomicQueue        *queue );
  572.  
  573. //    If queue->output.next is nil, then PeekGuardedAtomicQueue() calls
  574. //    StealAtomicList() on queue->input. If the result is not nil,
  575. //    PopGuardedAtomicQueue() calls PopAtomicStack() on each element in the stolen stack,
  576. //    then calling PushAtomicStack() with queue->output, effectively "reversing" the
  577. //    stack into a queue. PeekGuardedAtomicQueue() returns queue->output.next.
  578.  
  579.     extern
  580.     pascal
  581.     GuardedAtomicElement*
  582. PeekGuardedAtomicQueue(
  583.     AtomicQueue        *queue );
  584.  
  585. /**************************
  586. *    
  587. *    Guarded Atomic Queue Offset Functions
  588. *
  589. *    Convenience routines for when the AtomicElement field in your structure
  590. *    can't be the first field. You supply the coercions and field offset.
  591. *    
  592. **************************/
  593. #pragma mark    --Guarded Atomic Queue Offset Functions--
  594.  
  595. //    Adds offset to element, and calls PushGuardedAtomicQueue().
  596.  
  597.     extern
  598.     pascal
  599.     long
  600. PushGuardedAtomicQueueOff(
  601.     void            *element,
  602.     AtomicQueue        *queue,
  603.     size_t            offset );
  604.  
  605. //    Calls PopGuardedAtomicQueue(), if the result is not nil, subtracts offset from
  606. //    the result and returns it.
  607.  
  608.     extern
  609.     pascal
  610.     GuardedAtomicElement*
  611. PopGuardedAtomicQueueOff(
  612.     AtomicQueue        *queue,
  613.     size_t            offset );
  614.  
  615. //    Calls PekkGuardedAtomicQueue(), if the result is not nil, subtracts offset from
  616. //    the result and returns it.
  617.  
  618.     extern
  619.     pascal
  620.     GuardedAtomicElement*
  621. PeekGuardedAtomicQueueOff(
  622.     AtomicQueue        *queue,
  623.     size_t            offset );
  624.  
  625. /**************************
  626. *    
  627. *    Guarded Atomic Queue Type Functions
  628. *
  629. *    Convenience routines for when the AtomicElement field in your structure
  630. *    can't be the first field. You supply the structure and field names. It does
  631. *    the coercions and offsets for you.
  632. *    
  633. **************************/
  634. #pragma mark    --Guarded Atomic Queue Type Functions--
  635.  
  636. #define        PushGuardedAtomicQueueType( ELEMENT, QUEUE, STRUCTURE, FIELD )    \
  637.                 PushGuardedAtomicQueueOff( (ELEMENT), (QUEUE), offsetof( STRUCTURE, FIELD ) )
  638.  
  639. #define        PopGuardedAtomicQueueType( QUEUE, STRUCTURE, FIELD )    \
  640.                 ((STRUCTURE*) PopGuardedAtomicQueueOff( (QUEUE), offsetof( STRUCTURE, FIELD ) ))
  641.  
  642. #define        PeekGuardedAtomicQueueType( QUEUE, STRUCTURE, FIELD )    \
  643.                 ((STRUCTURE*) PeekGuardedAtomicQueueOff( (QUEUE), offsetof( STRUCTURE, FIELD ) ))
  644.  
  645. end_extern_c
  646. #endif    //    _atomicity_