/* (-lgl * Coherent 386 release 4.2 * Copyright (c) 1982, 1993 by Mark Williams Company. * All rights reserved. May not be copied without permission. * For copying permission and licensing info, write licensing@mwc.com -lgl) */ #ifndef __SYS_KSYNCH_H__ #define __SYS_KSYNCH_H__ /* * Support for basic locks. */ #include <common/ccompat.h> #if _DDI_DKI #include <kernel/__bool.h> #include <kernel/__pl.h> #include <kernel/_lock.h> #include <kernel/_sv.h> #include <kernel/x86lock.h> /* * We can provide a greater level of error checking/reporting if we know we * are running on a uniprocessor. Use this feature-test macro to control * compilation of code for uniprocessors. * * Note that many of the traditional simplifying assumptions about * uniprocessor systems may not apply if basic-lock acquisition can schedule * interrupt contexts (ie, if the system is designed such that interrupts * need not be turned off). Such as system would behave effectively like a * multiprocessor, although most of the extra checking could still be valid * with information gained from the interrupt-handler scheduling system. */ #define _UNIPROCESSOR 1 /* * For greater scalability, a "ticket lock" should be preferred over a basic * test-and-set or test-and-test-and-set spin lock, since it guarantees * FIFO ordering and reduces the level of memory contention (important for * multiprocessor shared-memory cache performance). See the paper cited at the * top of this file for more details. * * However, ticket locks take slightly more memory and are slightly slower * that basic test-and-set spin locks, so we only use them in situations * where we expect them to be needed. */ #if 0 /* _UNIPROCESSOR */ #define _TICKET_LOCK 1 #endif /* * Even if ticket locks are used, in the absence of a fetch-and-increment * atomic operation a basic test-and-set style lock must be used to control * the "ticket gate", so the style of test-and-set lock used will always have * consequences. A simple test-and-set spin lock reduces delay, while a * test-and-test-and-set spin reduces contention. */ #define __TEST_AND_TEST__ 1 /* * Information structure used for holding debugging information about * lock structures. */ struct lock_info { __CONST__ char * lk_name; /* name for statistics gathering */ int lk_flags; /* must be zero */ int lk_pad; }; typedef struct lock_info lkinfo_t; /* * No lock statistics structure is currently defined, but we reserve the name. * * For the other lock structures, we publish only their names, and leave the * types incomplete. */ typedef __VOID__ lkstat_t; typedef __lock_t lock_t; typedef __sv_t sv_t; typedef struct sleep_lock sleep_t; typedef struct readwrite_lock rwlock_t; __EXTERN_C_BEGIN__ /* Basic lock functions */ __pl_t LOCK __PROTO ((lock_t * _lockp, __pl_t _pl)); lock_t * LOCK_ALLOC __PROTO ((__lkhier_t _hierarchy, __pl_t _min_pl, lkinfo_t * _lkinfop, int _flag)); void LOCK_DEALLOC __PROTO ((lock_t * _lockp)); __pl_t TRYLOCK __PROTO ((lock_t * _lockp, __pl_t _pl)); void UNLOCK __PROTO ((lock_t * _lockp, __pl_t _pl)); /* Synchronization variable functions */ sv_t * SV_ALLOC __PROTO ((int _flag)); void SV_BROADCAST __PROTO ((sv_t * _svp, int _flags)); void SV_DEALLOC __PROTO ((sv_t * _svp)); void SV_SIGNAL __PROTO ((sv_t * _svp, int _flags)); void SV_WAIT __PROTO ((sv_t * _svp, int _priority, lock_t * _lkp)); __bool_t SV_WAIT_SIG __PROTO ((sv_t * _svp, int _priority, lock_t * _lkp)); /* Sleep locks */ sleep_t * SLEEP_ALLOC __PROTO ((int _arg, lkinfo_t * _lkinfop, int _flag)); void SLEEP_DEALLOC __PROTO ((sleep_t * _lockp)); void SLEEP_LOCK __PROTO ((sleep_t * _lockp, int _priority)); __bool_t SLEEP_LOCKAVAIL __PROTO ((sleep_t * _lockp)); __bool_t SLEEP_LOCKOWNED __PROTO ((sleep_t * _lockp)); __bool_t SLEEP_LOCK_SIG __PROTO ((sleep_t * _lockp, int _priority)); __bool_t SLEEP_TRYLOCK __PROTO ((sleep_t * _lockp)); void SLEEP_UNLOCK __PROTO ((sleep_t * _lockp)); /* Read/write locks */ rwlock_t * RW_ALLOC __PROTO ((__lkhier_t _hierarchy, __pl_t _min_pl, lkinfo_t * _lkinfop, int _flag)); void RW_DEALLOC __PROTO ((rwlock_t * _lockp)); __pl_t RW_RDLOCK __PROTO ((rwlock_t * _lockp, __pl_t _pl)); __pl_t RW_TRYRDLOCK __PROTO ((rwlock_t * _lockp, __pl_t _pl)); __pl_t RW_TRYWRLOCK __PROTO ((rwlock_t * _lockp, __pl_t _pl)); void RW_UNLOCK __PROTO ((rwlock_t * _lockp, __pl_t _pl)); __pl_t RW_WRLOCK __PROTO ((rwlock_t * _lockp, __pl_t _pl)); /* For internal self-checking */ void LOCK_DISPATCH __PROTO ((void)); __EXTERN_C_END__ #endif /* _DDI_DKI */ /* * This type is used in the internal COHERENT source as a form of sleep lock. * It is used in a structure which cannot alter because the configuration * mechanism for COHERENT in some cases involves hot-patching the kernel. */ typedef struct { unsigned char _lock [2]; unsigned short _flags; char * _lastlock; } __DUMB_GATE [1], * __DUMB_GATE_P; /* * Flags: * __GATE_COUNT causes this gate to feed into a per-process count of * locks held. When a system call returns to user level, this count is * required to be zero. */ #define __GATE_COUNT 1 #define __GATE_FLAGS(g) ((g)->_flags) #if TRACER #define __GATE_DECLARE(name) { { { 0, 0 }, 0, NULL, NULL } } #define __GATE_INIT(g, name, flags) \ ((g)->_lock [1] = (g)->_lock [0] = 0, (g)->_flags = (flags)) #define __GATE_LOCKED(gate) ((gate)->_lock [0]) #define __GATE_LOCK_COUNT(g) ((g)->_count) #define __GATE_LOCK_OWNER(g) ((g)->_lastlock) #else /* if ! defined (TRACER) */ #define __GATE_DECLARE(name) { { { 0, 0 } } } #define __GATE_INIT(g, name, flags) \ ((g)->_lock [1] = (g)->_lock [0] = 0, (g)->_flags = (flags)) #define __GATE_LOCKED(g) ((g)->_lock [0]) #endif /* ! defined (TRACER) */ __EXTERN_C_BEGIN__ void __GATE_LOCK __PROTO ((__DUMB_GATE_P g, __CONST__ char * reason)); void __GATE_UNLOCK __PROTO ((__DUMB_GATE_P g)); void __GATE_TO_INTERRUPT __PROTO ((__DUMB_GATE_P g)); __EXTERN_C_END__ #endif /* ! defined (__SYS_KSYNCH_H__) */