mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
11 KiB
300 lines
11 KiB
/* lock.h, /atalk-ii/ins, Garth Conboy, 11/21/92 */
|
|
/* Copyright (c) 1992 by Pacer Software Inc., La Jolla, CA */
|
|
|
|
/* GC - Initial coding.
|
|
|
|
Definitions, declarations, and explinations of locking requirements
|
|
for the portbale AppleTalk stack and router.
|
|
|
|
There are three main "events" that are relevant to the operation of
|
|
portable code base:
|
|
|
|
packets - Network activity. These are calls to DdpPacketIn(),
|
|
GleanAarpInfo(), or ArapIncomingPacket() that are
|
|
caused by by incoming calls to XxxxPacketInYyyy ("Xxxx"
|
|
being interface type [LocalTalk, Ethernet, etc.], and
|
|
"Yyyy" being "AT" or "AARP") in "depend.c". Basically
|
|
incoming packets to the portable stack/router. Also,
|
|
in asynchronous transmit completion environments, the
|
|
completion (call to the transmit completion routine) of
|
|
an XxxxPacketOut operation counts as a "packet" event.
|
|
|
|
timers - Timers going off. These are the calls to the completion
|
|
routines supplied to StartTimer().
|
|
|
|
users - User activity. This is "application level" activity --
|
|
incoming calls to the "top" of the stack (e.g. calls
|
|
OpenSocketOnNode, DeliverDdp, AdspSend, PapGetNextJob,
|
|
etc.).
|
|
|
|
Locking requirements vary depending upon which of these "events" can
|
|
"happen at the same time" -- either interrupting each other (one event
|
|
starting (asynchronously) before the event currently being processed
|
|
finishes or returns) or running concurrently on a different processor
|
|
(in a multi-processor (MP) environment).
|
|
|
|
Two types of locking are supported in the portable code base:
|
|
|
|
deferrals - Events of type "packets" and "timers" can be deferred
|
|
during access to critical memory locations and data
|
|
structures. If timers are deferred, no timers will go
|
|
go off until timers are "undeferred." If packets are
|
|
deferred, incoming packets will be copied and queued
|
|
for processing later. When packets are "undeferred"
|
|
the deferred packet queue(s) will be processed and the
|
|
packets serially handed to the approriate incoming
|
|
packet handling rotuine (e.g. DdpPacketIn ). Deferrals
|
|
of packets and/or timers can be nested; if one routine
|
|
calls for packet deferral and then calls another routine
|
|
that also calls for packet deferral, two subsequent
|
|
calls for packet undeferral must be made in order to
|
|
re-enable incoming packet processing. Calls for packet
|
|
or timer deferral must be balanced: generally at entry
|
|
to a routine a call to DeferIncomingPackets() or
|
|
DeferTimerChecking() or both would be made, and at exit
|
|
from the routine would be calls to HandleDeferredPackets()
|
|
or HandleDeferredTimerChecks() or both.
|
|
|
|
locks - A mechanism to protect "small chunks" of code (say a
|
|
maximum of a couple hundred instructions) from being
|
|
interrupted while they execute on a single processor.
|
|
These locks may be implemented by either "turning off
|
|
interrupts," or "raising the interrupt level" sufficiently
|
|
high that no other of the above AppleTalk "events" will
|
|
run until the lock is released, or as "spin locks" if
|
|
an attempt to get a "held lock" will yield processing to
|
|
the holder of the lock while it is spinning waiting for
|
|
the lock to be released.
|
|
|
|
In an MP environment, a lock must behave as described
|
|
above on the "current" processor. On other processors,
|
|
an attempt to obtain a "held lock" must result in a
|
|
"spin wait" (or moral evquivalent) until the lock is
|
|
released on the "holding processor."
|
|
|
|
Multiple "lock types" are defined below (e.g. the Adsp
|
|
lock, the routing information lock, etc.); this
|
|
differentiation can be used in MP environments so that
|
|
if processor one holds the "Adsp lock," processor two
|
|
would only be blocked from performing some Adsp operations
|
|
and could grab other AppleTalk locks uninhibitedly.
|
|
An implementation can choose to "merge" all of these
|
|
lock types into a single "AppleTalk lock," or ignore
|
|
them completely in a single processor "turn off
|
|
interrupts" or "raise interrupt level" environment.
|
|
|
|
Locks have no priority level associated with them and
|
|
may not nest. A single "tread of execution" may hold
|
|
only one lock at a time and may only "take" a single
|
|
lock once without an interviening "release." If these
|
|
rules are ignored there is a strong possibility of
|
|
deadlocks occurring or at the very least MP-safeness
|
|
could be lost.
|
|
|
|
The portable code base can be configured (and is, further down in this
|
|
file) to use either, or both, of these locking mechanisms.
|
|
|
|
The following table lists the scenarios in which events may impact one
|
|
another ("happen at the same time" or "interrupt one another):
|
|
|
|
A - A totally serial environment no event will interrupt another.
|
|
|
|
B - Multiple packets will be handed to the stack "at the same time,"
|
|
that is, a call to XxxxPacketInYyyy may be placed before a
|
|
previous call returns. Or, a packet event could happen during
|
|
the processing of a "user" or "timer" event.
|
|
|
|
C - Timers go off asynchronously. A time could "fire" while another
|
|
event is being processed.
|
|
|
|
D - "User" events happen asynchronously. Due to process exchange or
|
|
an MP environment a "user" event could interrupt (or happen
|
|
concurrently on another processor) during the processing of
|
|
a "packet," "timer," or another "user" event.
|
|
|
|
If the target environment is "non-A" it is likely that more than one
|
|
of "B," "C," or "D" apply. The following table matches the above
|
|
environment types to their required locking support:
|
|
|
|
A - No locking is required. [e.g. some standalone network
|
|
devices such a print or FAX servers]
|
|
|
|
Only B - Packet deferral or locks.
|
|
|
|
Only C - Timer deferral or locks.
|
|
|
|
B and C - Packet and Timer deferral or locks. [e.g. OS/2, the
|
|
"default" environment]
|
|
|
|
D (with - Locks. [e.g. WindowsNT]
|
|
A or B or
|
|
neither)
|
|
|
|
In the latter four cases, packet/timer deferral may need to be used,
|
|
potentially in addition to locks, in multi-interrupt-level environments
|
|
in which locks are implemented as "true non-yielding spin locks." For
|
|
example, suppose a user event is being processed at "level 5" and
|
|
then a packet event running at "level 7" interrupts this, further suppose
|
|
that the user event held a lock that will is also required by the packet
|
|
event. The packet event would then spin waiting for the lock to be
|
|
released, but spinning at "level 7" would take precedence over running
|
|
at "level 5," so deadlock would exist. With packet deferrals, the
|
|
user event would defer packet procesing as required and this deadlock
|
|
would be avoided.
|
|
|
|
In "B" or "C" environments using deferrals, EnterCriticalSection() and
|
|
LeaveCriticalSection() must be defined to do something like "disable
|
|
interrupts" -- these are used while working with deferral queues and
|
|
deferral nesting counts.
|
|
|
|
Got all of that?
|
|
*/
|
|
|
|
/* The following define the lock types. */
|
|
|
|
typedef enum { GenericLock,
|
|
TimerLock,
|
|
DdpLock,
|
|
RoutingLock,
|
|
AarpLock,
|
|
PortsLock,
|
|
ArapLock,
|
|
AdspLock,
|
|
AtpLock,
|
|
PapLock,
|
|
AspLock
|
|
} LockType;
|
|
|
|
/* The following the define the target environment specific locking
|
|
requirements. */
|
|
|
|
#if defined(TotallySynchronousEnvironment) or defined(TSE)
|
|
|
|
/* No packet deferrals. */
|
|
|
|
#define DeferIncomingPackets()
|
|
#define HandleIncomingPackets()
|
|
#define DeferAtpPackets()
|
|
#define HandleAtpPackets()
|
|
#define DeferAdspPackets()
|
|
#define HandleAdspPackets()
|
|
|
|
/* No timer deferrals. */
|
|
|
|
#define DeferTimerChecking()
|
|
#define HandleDeferredTimerChecks()
|
|
|
|
/* No locks. */
|
|
|
|
#define TakeLock(lock)
|
|
#define ReleaseLock(lock)
|
|
#define EnterCriticalSection()
|
|
#define LeaveCriticalSection()
|
|
|
|
#elif Iam a WindowsNT
|
|
|
|
/* No packet deferrals. */
|
|
|
|
#define DeferIncomingPackets()
|
|
#define HandleIncomingPackets()
|
|
#define DeferAtpPackets()
|
|
#define HandleAtpPackets()
|
|
#define DeferAdspPackets()
|
|
#define HandleAdspPackets()
|
|
|
|
/* No timer deferrals. */
|
|
|
|
#define DeferTimerChecking()
|
|
#define HandleDeferredTimerChecks()
|
|
|
|
/* Use locks. */
|
|
|
|
#define IncludeLockingCode 1
|
|
#define EnterCriticalSection() TakeLock(GenericLock)
|
|
#define LeaveCriticalSection() ReleaseLock(GenericLock)
|
|
|
|
#elif Iam an OS2
|
|
|
|
/* No locks. */
|
|
|
|
#define TakeLock(lock)
|
|
#define ReleaseLock(lock)
|
|
|
|
/* Use deferrals. */
|
|
|
|
#define IncludePacketDeferralCode 1
|
|
#define IncludeTimerDeferralCode 1
|
|
|
|
#elif defined(UseJustPacketDeferral)
|
|
|
|
/* No timer deferrals. */
|
|
|
|
#define DeferTimerChecking()
|
|
#define HandleDeferredTimerChecks()
|
|
|
|
/* No locks. */
|
|
|
|
#define TakeLock(lock)
|
|
#define ReleaseLock(lock)
|
|
|
|
/* Use packet deferrals. */
|
|
|
|
#define IncludePacketDeferralCode 1
|
|
|
|
#elif defined(UseJustTimerDeferral)
|
|
|
|
/* No packet deferrals. */
|
|
|
|
#define DeferIncomingPackets()
|
|
#define HandleIncomingPackets()
|
|
#define DeferAtpPackets()
|
|
#define HandleAtpPackets()
|
|
#define DeferAdspPackets()
|
|
#define HandleAdspPackets()
|
|
|
|
/* No locks. */
|
|
|
|
#define TakeLock(lock)
|
|
#define ReleaseLock(lock)
|
|
|
|
/* Use timer deferrals. */
|
|
|
|
#define IncludeTimerDeferralCode 1
|
|
|
|
#elif Iam a Primos
|
|
|
|
/* This is the test environment, so these settings may, or may not,
|
|
make any sense. */
|
|
|
|
#define IncludePacketDeferralCode 1
|
|
#define IncludeTimerDeferralCode 1
|
|
#define IncludeLockingCode 1
|
|
|
|
#define EnterCriticalSection() DeferTimerChecking()
|
|
#define LeaveCriticalSection() HandleDeferredTimerChecks()
|
|
|
|
#else
|
|
|
|
/* No locks. */
|
|
|
|
#define TakeLock(lock)
|
|
#define ReleaseLock(lock)
|
|
|
|
/* Use deferrals. */
|
|
|
|
#define IncludePacketDeferralCode 1
|
|
#define IncludeTimerDeferralCode 1
|
|
|
|
#endif
|
|
|
|
/* Declare the lock oriented routines. */
|
|
|
|
#if not defined(EnterCriticalSection)
|
|
extern void far EnterCriticalSection(void);
|
|
extern void far LeaveCriticalSection(void);
|
|
#endif
|
|
|
|
#if not defined(TakeLock)
|
|
extern void far TakeLock(LockType lock);
|
|
extern void far ReleaseLock(LockType lock);
|
|
#endif
|