Windows NT 4.0 source code leak
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

/* 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