PATH 
ADC Home > Documentation > Hardware > Device Managers and Drivers > PCI Card Services > Designing PCI Cards and Drivers for Power Macintosh Computers


  

Atomic Services

Open Transport supplies atomic services that help reduce the need for drivers to disable and enable interrupts.

Note

Don't confuse these services with the DSL atomic services described in Chapter 11.

IMPORTANT

Many atomic services have strict alignment requirements. Be sure to heed the following warnings. The OTAllocMem and all STREAMS message blocks are guaranteed to be aligned to 32-bit boundaries. On STREAMS message blocks, this applies to the actual start of the message, not the b_rptr field itself, which may not be aligned at all. In 16-bit operations, if the 16 bits cross a 32-bit boundary the atomic function will not work properly. In 32-bit functions, it is important that the variable being operated on be aligned on a 32-bit boundary.

The first set of services atomically sets, clears, or tests a single bit in a byte. The first parameter is a pointer to a single byte, and the second is a bit number from 0 to 7. The functions return the previous value of the bit. Bit 0 corresponds to a mask of 0x01, and bit 7 corresponds to a mask of 0x80.

Boolean OTAtomicSetBit      (UInt8* theByte, size_t theBitNo);
Boolean OTAtomicClearBit    (UInt8* theByte, size_t theBitNo);
Boolean OTAtomicTestBit     (UInt8* theByte, size_t theBitNo);
Boolean OTAcquireLock       (UInt8* theByte);
void    OTClearLock         (UInt8* theByte);

OTAcquireLock is a faster equivalent of OTAtomicSetBit(theByte, 0). It returns true if the lock could be acquired (that is, if the bit was flipped from off to on). OTClearLock is a macro that just zeroes the byte.

The second set of services atomically add to a 32-, 16-, or 8-bit variable. By using a negative number, they can subtract. The return value is the new value of the variable as it is when the operation is completed.

SInt32 OTAtomicAdd32 (SInt32, SInt32* varToBeAddedTo);
SInt16 OTAtomicAdd16 (SInt16, SInt16* varToBeAddedTo);
SInt8  OTAtomicAdd8  (SInt8,  SInt8*  varToBeAddedTo);

The third service is a general compare and swap. It determines if the value at where still contains the value oVal ; if so, it substitutes the value nVal. If the compare and swap succeeds, the function returns true, otherwise false.

Boolean OTCompareAndSwap32
                    (UInt32 oVal, UInt32* nVal, UInt32** where);
Boolean OTCompareAndSwap16
                    (UInt16 oVal, UInt16* nVal, UInt16** where);
Boolean OTCompareAndSwap8
                    (UInt8 oVal,  UInt8* nVal,  UInt8** where);

The fourth set of services is an atomic last in, first out (LIFO) list. OTLIFOEnqueue and OTLIFODequeue are self-explanatory. OTLIFOStealList lets you remove all of the elements from the LIFO list atomically, so that the elements in the list can be iterated at your leisure by traditional means. OTLIFOReverseList is for those who find that LIFO lists are next to useless in networking. Once the OTLIFOStealList function has been executed, the result can be passed to OTLIFOReverseList, which can be used to flip the list into a first in, first out (FIFO) configuration. The OTLink and the OTLIFO parameters must both be aligned on 32-bit boundaries. Note that OTLIFOReverseList is not atomic.



struct OTLink
{
    void*   fNext;
};


struct OTLIFO struct OTLIFO
{
    void*   fLink;
};


void        OTLIFOEnqueue   (OTLIFO* list, OTLink* toAdd);
OTLink*     OTLIFODequeue   (OTLIFO* list);
OTLink*     OTLIFOStealList (OTLIFO* list);
OTLink*     OTReverseList   (OTLink* firstInList);

The last set of services performs enqueueing and dequeueing from a LIFO list. It is used internally in the STREAMS implementation; it is exported so you can use it if it proves useful. If you look at the Open Transport LIFO implementation, it assumes that the structures being linked have their links pointing at the next link, and so on. Unfortunately, STREAMS messages ( msgb structures) are not linked this way internally (the b_cont field does not point to the b_cont field of the next message block but instead points to the actual message block itself). These two functions let you create a LIFO list where the head pointer of the list points to the actual object, but the next pointer in the object is at some arbitrary offset. It is important that the links and the list itself be aligned on 32-bit boundaries for these functions to work properly.

void* OTEnqueue
        (void** list, void* newListHead, size_t offsetOfNextPtr);
void* OTDequeue
        (void** theList, size_t offsetOfNextPtr);

© 1999 Apple Computer, Inc. – (Last Updated 26 March 99)