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.
145 lines
5.8 KiB
145 lines
5.8 KiB
/* link.h, /atalk-ii/ins, Garth Conboy, 10/12/92 */
|
|
/* Copyright (c) 1992 by Pacer Software Inc., La Jolla, CA */
|
|
|
|
/* GC - Initial coding.
|
|
|
|
Manage the linking/unlinking of reference counted nodes within
|
|
linked lists.
|
|
|
|
*/
|
|
|
|
/* Link to a node: bump the reference count, and return the linked node. This
|
|
macro should be invoked from within a CriticalSection(). RefCount must be
|
|
the first field name is an structures managed by this package:
|
|
|
|
struct tag { int refCount;
|
|
...
|
|
} *Node;
|
|
*/
|
|
|
|
typedef struct {int refCount;} *GenericNode;
|
|
|
|
/* The Link macro does not do its own lock handling (see "lock.h") so it
|
|
must be invoked with an appropriate lock held or from within a critical
|
|
section. Locking is not required if "+= 1" is an atomic operation in
|
|
the target environment. */
|
|
|
|
#if IamNot a Primos
|
|
#define Link(p) (((p) is Empty) ? Empty : ((p)->refCount += 1, (p)))
|
|
#else
|
|
/* For debugging/testing link code, check for too many links. The funny
|
|
"(p)->refCount" is to ensure a compilation error if we try this on
|
|
a node that doesn't have a refernece count. */
|
|
|
|
#define TooManyLinks 30
|
|
|
|
#define Link(p) ((p)->refCount, LinkNode(p))
|
|
|
|
extern void far *LinkNode(void far *node);
|
|
#endif
|
|
|
|
/* Unlink a node: decrement the reference count, free the node if we're
|
|
the last referant. Return True if we really freed the beast. This
|
|
routine does its own lock handling, so it must not be invoked with
|
|
a lock held or from within a critical section. */
|
|
|
|
extern Boolean far Unlink(void far *node, LockType lock);
|
|
|
|
/* The following is an alternate version of Unlink -- it expects to be called
|
|
with a lock held (or within a critical section) -- it will decrement the
|
|
reference count, and return True if the node should be freed (it will not
|
|
actuall perform the free). */
|
|
|
|
extern Boolean far UnlinkNoFree(void far *node);
|
|
|
|
/* Find a node on a list: search a linked list for an entry, if found return
|
|
a Link to the node. A sample call would be:
|
|
|
|
p = FindOnList(connectionEndLocalHashBuckets[index],
|
|
myConnectionId, connectionId, nextByLocalInfo,
|
|
AdspLock);
|
|
|
|
"connectionEndLocalHashBuckets[index]" is the head of the list to walk.
|
|
"myConnectionId" is the value in the node that we're looking for.
|
|
"connectionId" is the field name within the node to look for the value.
|
|
"nextByLocalInfo" is the field name within the node that we should use
|
|
as the "next link."
|
|
"AdspLock" is the lock to grab durring the operation.
|
|
|
|
A simpler example would be:
|
|
|
|
p = FindOnList(connectionListenerList, refNum,
|
|
connectionListenerRefNum, next, AdspLock);
|
|
|
|
The routine FindNodeOnList() really implements this macro. It's called
|
|
as follows:
|
|
|
|
p = FindNodeOnList(head, value, valueSize, field,
|
|
fieldSize, next, lock);
|
|
|
|
"head" is the head of the list to walk.
|
|
"value" is the value in the node that we're looking for.
|
|
"valueSize" is the size (in bytes) of value we're looking for; used
|
|
only to verify a match with "fieldSize."
|
|
"field" is the address of the target field (the one that should contain
|
|
"value") within the "head" node ("field - head" will yield
|
|
the offset of this field within all nodes).
|
|
"fieldSize" is the size (in bytes) of the field.
|
|
"next" is the address of the "next" field (the one to walk) within the
|
|
"head" node ("next - head" will yield the offset of this field
|
|
within all nodes).
|
|
"lock" is the lock type to use.
|
|
|
|
This routine handles its own locking so it must not be called while
|
|
a lock is held or from within a CriticalSection().
|
|
*/
|
|
|
|
#define FindOnList(head, value, field, next, lock) \
|
|
(((head) is Empty) ? Empty : \
|
|
FindNodeOnList(head, &(value), sizeof(value), \
|
|
&((head)->field), sizeof((head)->field), \
|
|
&((head)->next), lock))
|
|
|
|
extern void *FindNodeOnList(void *head, void *value, long valueSize,
|
|
void *field, long fieldSize, void *next,
|
|
LockType lock);
|
|
|
|
/* Remove a node from a list: find a given node of a linked list, remove it
|
|
from the next chain, return the removed node (probably as passed in),
|
|
Unlink() the node, return Empty is the node is not on the list. An example
|
|
would be:
|
|
|
|
p = RemoveFromList(connectionListenerList,
|
|
currentListenerInfo, next, AdspLock);
|
|
|
|
The routine RemoveNodeFromList() really implements this macro. It's called
|
|
as follows:
|
|
|
|
p = RemoveNodeFromList(head, node, nextOffset, lock);
|
|
|
|
"head" is the address of the head of the list to walk.
|
|
"node" is the node to remove.
|
|
"next" is the address of the "next" field (the one to walk) within the
|
|
"head" node ("next - *head" will yield the offset of this field
|
|
within all nodes).
|
|
"lock" to take during the operation.
|
|
|
|
This routine handles its own locking so it must not be called while
|
|
a lock is held or from within a CriticalSection().
|
|
*/
|
|
|
|
#define RemoveFromList(head, node, next, lock) \
|
|
(((head) is Empty) ? Empty : \
|
|
RemoveNodeFromList(&(head), node, &((head)->next), lock))
|
|
|
|
extern void *RemoveNodeFromList(void **head, void *node,
|
|
void *next, LockType lock);
|
|
|
|
/* This version does not Unlink and does not use locks (it's up to the
|
|
caller). */
|
|
|
|
#define RemoveFromListNoUnlink(head, node, next) \
|
|
(((head) is Empty) ? Empty : \
|
|
RemoveNodeFromListNoUnlink(&(head), node, &((head)->next)))
|
|
|
|
extern void *RemoveNodeFromListNoUnlink(void **head, void *node, void *next);
|