37
37
Bool (*MXUserMX_IsLockedByCurThreadRec)(const struct MX_MutexRec *lock) = NULL;
41
*-----------------------------------------------------------------------------
43
* MXUserInternalSingleton --
45
* A "singleton" function for the MXUser internal recursive lock.
47
* Internal MXUser recursive locks have no statistics gathering or
48
* tracking abilities. They need to used with care and rarely.
52
* !NULL A pointer to an initialized MXRecLock
57
*-----------------------------------------------------------------------------
61
MXUserInternalSingleton(Atomic_Ptr *storage) // IN:
63
MXRecLock *lock = (MXRecLock *) Atomic_ReadPtr(storage);
65
if (UNLIKELY(lock == NULL)) {
66
MXRecLock *newLock = Util_SafeMalloc(sizeof(MXRecLock));
68
if (MXRecLockInit(newLock)) {
69
lock = (MXRecLock *) Atomic_ReadIfEqualWritePtr(storage, NULL,
73
MXRecLockDestroy(newLock);
76
lock = Atomic_ReadPtr(storage);
80
lock = Atomic_ReadPtr(storage); // maybe another thread succeeded
88
#define MXUSER_SYNDROME
89
#if defined(MXUSER_SYNDROME)
91
*-----------------------------------------------------------------------------
95
* Generate the syndrome bits for this MXUser library.
97
* Each MXUser library has unique syndrome bits enabling the run time
98
* detection of locks created with one copy of the MXUser library and
99
* passed to another copy of the MXUser library.
101
* The syndrome bits are important as they prevent incompatible versions
102
* of the MXUser library from trashing each other.
104
* The bits are generated by using a source of bits that is external to
105
* a program and its libraries. This way no code or data based scheme
106
* can be spoofed or aliased.
114
*-----------------------------------------------------------------------------
121
static Atomic_uint32 syndromeMem; // implicitly zero -- mbellon
123
syndrome = Atomic_Read(&syndromeMem);
129
* Do not assume that the source of bits from the host OS are sane.
130
* Perhaps its random bits service is not working or always returns
131
* zero or something is misconfigured. Only perform a small number
132
* of retries attempting to appropriate the required bits.
136
/* Only changes syndrome on success. No need to check for errors */
137
Random_Crypto(sizeof syndrome, &syndrome);
145
* If the source was unable to provide the appropriate bits, switch
151
syndrome = GetTickCount();
153
syndrome = time(NULL) & 0xFFFFFFFF;
158
* Protect against a total failure.
165
/* blind write; if racing one thread or the other will do */
166
Atomic_ReadIfEqualWrite(&syndromeMem, 0, syndrome);
168
syndrome = Atomic_Read(&syndromeMem);
179
*-----------------------------------------------------------------------------
181
* MXUserGetSignature --
183
* Return a signature appropriate for the specified object type.
191
*-----------------------------------------------------------------------------
195
MXUserGetSignature(MXUserObjectType objectType) // IN:
199
ASSERT((objectType >= 0) && (objectType < 16) &&
200
(objectType != MXUSER_TYPE_NEVER_USE));
202
#if defined(MXUSER_SYNDROME)
204
* Use a random syndrome combined with a unique bit pattern mapping
205
* of objectType to bits in a nibble. The random portion of the signature
206
* can be used to catch multiple copies of lib/lock that are "leaking"
207
* locks between them (which may be incompatible due to internal changes).
210
signature = (MXUserSyndrome() & 0x0FFFFFFF) | (objectType << 28);
213
* Map the abstract objectType back to the bit patterns used in older
214
* versions of lib/lock. This provides absolute compatibility with
215
* these older libraries.
218
switch (objectType) {
220
signature = 0x57524B4C;
223
case MXUSER_TYPE_REC:
224
signature = 0x43524B4C;
227
case MXUSER_TYPE_RANK:
228
signature = 0x4E4B5241;
231
case MXUSER_TYPE_EXCL:
232
signature = 0x58454B4C;
235
case MXUSER_TYPE_SEMA:
236
signature = 0x414D4553;
239
case MXUSER_TYPE_CONDVAR:
240
signature = 0x444E4F43;
243
case MXUSER_TYPE_BARRIER:
244
signature = 0x52524142;
248
Panic("%s: unknown objectType %d\n", __FUNCTION__, objectType);
259
*-----------------------------------------------------------------------------
261
* MXUserDumpAndPanic --
263
* Dump a lock, print a message and die
271
*-----------------------------------------------------------------------------
275
MXUserDumpAndPanic(MXUserHeader *header, // IN:
276
const char *fmt, // IN:
282
ASSERT((header != NULL) && (header->dumpFunc != NULL));
284
(*header->dumpFunc)(header);
287
msg = Str_SafeVasprintf(NULL, fmt, ap);
295
*---------------------------------------------------------------------
297
* MXUser_SetInPanic --
298
* Notify the locking system that a panic is occurring.
300
* This is the "out of the monitor" - userland - implementation. The "in
301
* the monitor" implementation lives in mutex.c.
304
* Set the internal "in a panic" global variable.
309
*---------------------------------------------------------------------
313
MXUser_SetInPanic(void)
320
*---------------------------------------------------------------------
323
* Is the caller in the midst of a panic?
325
* This is the "out of the monitor" - userland - implementation. The "in
326
* the monitor" implementation lives in mutex.c.
335
*---------------------------------------------------------------------
346
*-----------------------------------------------------------------------------
348
* MXUserInstallMxHooks --
350
* The MX facility may notify the MXUser facility that it is place and
351
* that MXUser should check with it. This function should be called from
360
*-----------------------------------------------------------------------------
364
MXUserInstallMxHooks(void (*theLockListFunc)(void),
365
MX_Rank (*theRankFunc)(void),
366
void (*theLockFunc)(struct MX_MutexRec *lock),
367
void (*theUnlockFunc)(struct MX_MutexRec *lock),
368
Bool (*theTryLockFunc)(struct MX_MutexRec *lock),
369
Bool (*theIsLockedFunc)(const struct MX_MutexRec *lock))
372
* This function can be called more than once but the second and later
373
* invocations must be attempting to install the same hook functions as
374
* the first invocation.
377
if ((MXUserMxLockLister == NULL) &&
378
(MXUserMxCheckRank == NULL) &&
379
(MXUserMX_LockRec == NULL) &&
380
(MXUserMX_UnlockRec == NULL) &&
381
(MXUserMX_TryLockRec == NULL) &&
382
(MXUserMX_IsLockedByCurThreadRec == NULL)) {
383
MXUserMxLockLister = theLockListFunc;
384
MXUserMxCheckRank = theRankFunc;
385
MXUserMX_LockRec = theLockFunc;
386
MXUserMX_UnlockRec = theUnlockFunc;
387
MXUserMX_TryLockRec = theTryLockFunc;
388
MXUserMX_IsLockedByCurThreadRec = theIsLockedFunc;
390
ASSERT((MXUserMxLockLister == theLockListFunc) &&
391
(MXUserMxCheckRank == theRankFunc) &&
392
(MXUserMX_LockRec == theLockFunc) &&
393
(MXUserMX_UnlockRec == theUnlockFunc) &&
394
(MXUserMX_TryLockRec == theTryLockFunc) &&
395
(MXUserMX_IsLockedByCurThreadRec == theIsLockedFunc)
40
400
#if defined(MXUSER_DEBUG)
41
401
#define MXUSER_MAX_LOCKS_PER_THREAD (2 * MXUSER_MAX_REC_DEPTH)
45
MXUserHeader *lockArray[MXUSER_MAX_LOCKS_PER_THREAD];
403
typedef struct MXUserPerThread {
404
struct MXUserPerThread *next;
406
MXUserHeader *lockArray[MXUSER_MAX_LOCKS_PER_THREAD];
46
407
} MXUserPerThread;
409
static Atomic_Ptr perThreadLockMem;
410
static MXUserPerThread *perThreadFreeList = NULL;
48
412
static Atomic_Ptr hashTableMem;
52
416
*-----------------------------------------------------------------------------
418
* MXUserAllocPerThread --
420
* Allocate a perThread structure.
422
* Memory is allocated for the specified thread as necessary. Use a
423
* victim cache in front of malloc to provide a slight performance
424
* advantage. The lock here is equivalent to the lock buried inside
425
* malloc but no complex calculations are necessary to perform an
426
* allocation most of the time.
428
* The maximum size of the list will be roughly the maximum number of
429
* threads having taken locks at the same time - a bounded number less
430
* than or equal to the maximum of threads created.
436
* Memory may be allocated.
438
*-----------------------------------------------------------------------------
441
static MXUserPerThread *
442
MXUserAllocPerThread(void)
444
MXUserPerThread *perThread;
445
MXRecLock *perThreadLock = MXUserInternalSingleton(&perThreadLockMem);
447
ASSERT(perThreadLock);
449
MXRecLockAcquire(perThreadLock);
451
if (perThreadFreeList == NULL) {
452
perThread = Util_SafeMalloc(sizeof *perThread);
454
perThread = perThreadFreeList;
455
perThreadFreeList = perThread->next;
458
MXRecLockRelease(perThreadLock);
462
memset(perThread, 0, sizeof *perThread); // ensure all zeros
469
*-----------------------------------------------------------------------------
471
* MXUserFreePerThread --
473
* Free a perThread structure.
475
* The structure is placed on the free list -- for "later".
483
*-----------------------------------------------------------------------------
487
MXUserFreePerThread(MXUserPerThread *perThread) // IN:
489
MXRecLock *perThreadLock;
492
ASSERT(perThread->next == NULL);
494
perThreadLock = MXUserInternalSingleton(&perThreadLockMem);
495
ASSERT(perThreadLock);
497
MXRecLockAcquire(perThreadLock);
498
perThread->next = perThreadFreeList;
499
perThreadFreeList = perThread;
500
MXRecLockRelease(perThreadLock);
505
*-----------------------------------------------------------------------------
54
507
* MXUserGetPerThread --
56
509
* Return a pointer to the per thread data for the specified thread.
416
863
MXUserTryAcquireForceFail = func;
868
*-----------------------------------------------------------------------------
870
* MXUserValidateHeader --
872
* Validate an MXUser object header
876
* Panic All is NOT well
879
* Always entertaining...
881
*-----------------------------------------------------------------------------
885
MXUserValidateHeader(MXUserHeader *header, // IN:
886
MXUserObjectType objectType) // IN:
888
uint32 expected = MXUserGetSignature(objectType);
890
if (header->signature != expected) {
891
MXUserDumpAndPanic(header,
892
"%s: signature failure! expected 0x%X observed 0x%X\n",
893
__FUNCTION__, expected, header->signature);
896
if (header->serialNumber == 0) {
897
MXUserDumpAndPanic(header, "%s: Invalid serial number!", __FUNCTION__);
422
*-----------------------------------------------------------------------------
424
* MXUserInternalSingleton --
426
* A "singleton" function for the MXUser internal recursive lock.
428
* Internal MXUser recursive locks have no statistics gathering or
429
* tracking abilities. They need to used with care and rarely.
433
* !NULL A pointer to an initialized MXRecLock
438
*-----------------------------------------------------------------------------
442
MXUserInternalSingleton(Atomic_Ptr *storage) // IN:
444
MXRecLock *lock = (MXRecLock *) Atomic_ReadPtr(storage);
446
if (UNLIKELY(lock == NULL)) {
447
MXRecLock *newLock = Util_SafeMalloc(sizeof(MXRecLock));
449
if (MXRecLockInit(newLock)) {
450
lock = (MXRecLock *) Atomic_ReadIfEqualWritePtr(storage, NULL,
454
MXRecLockDestroy(newLock);
457
lock = Atomic_ReadPtr(storage);
461
lock = Atomic_ReadPtr(storage); // maybe another thread succeeded
470
*-----------------------------------------------------------------------------
472
* MXUserDumpAndPanic --
474
* Dump a lock, print a message and die
482
*-----------------------------------------------------------------------------
486
MXUserDumpAndPanic(MXUserHeader *header, // IN:
487
const char *fmt, // IN:
493
ASSERT((header != NULL) && (header->dumpFunc != NULL));
495
(*header->dumpFunc)(header);
498
msg = Str_SafeVasprintf(NULL, fmt, ap);
506
*---------------------------------------------------------------------
508
* MXUser_SetInPanic --
509
* Notify the locking system that a panic is occurring.
511
* This is the "out of the monitor" - userland - implementation. The "in
512
* the monitor" implementation lives in mutex.c.
515
* Set the internal "in a panic" global variable.
520
*---------------------------------------------------------------------
524
MXUser_SetInPanic(void)
531
*---------------------------------------------------------------------
534
* Is the caller in the midst of a panic?
536
* This is the "out of the monitor" - userland - implementation. The "in
537
* the monitor" implementation lives in mutex.c.
546
*---------------------------------------------------------------------
557
*-----------------------------------------------------------------------------
559
* MXUserInstallMxHooks --
561
* The MX facility may notify the MXUser facility that it is place and
562
* that MXUser should check with it. This function should be called from
571
*-----------------------------------------------------------------------------
575
MXUserInstallMxHooks(void (*theLockListFunc)(void),
576
MX_Rank (*theRankFunc)(void),
577
void (*theLockFunc)(struct MX_MutexRec *lock),
578
void (*theUnlockFunc)(struct MX_MutexRec *lock),
579
Bool (*theTryLockFunc)(struct MX_MutexRec *lock),
580
Bool (*theIsLockedFunc)(const struct MX_MutexRec *lock))
583
* This function can be called more than once but the second and later
584
* invocations must be attempting to install the same hook functions as
585
* the first invocation.
588
if ((MXUserMxLockLister == NULL) &&
589
(MXUserMxCheckRank == NULL) &&
590
(MXUserMX_LockRec == NULL) &&
591
(MXUserMX_UnlockRec == NULL) &&
592
(MXUserMX_TryLockRec == NULL) &&
593
(MXUserMX_IsLockedByCurThreadRec == NULL)) {
594
MXUserMxLockLister = theLockListFunc;
595
MXUserMxCheckRank = theRankFunc;
596
MXUserMX_LockRec = theLockFunc;
597
MXUserMX_UnlockRec = theUnlockFunc;
598
MXUserMX_TryLockRec = theTryLockFunc;
599
MXUserMX_IsLockedByCurThreadRec = theIsLockedFunc;
601
ASSERT((MXUserMxLockLister == theLockListFunc) &&
602
(MXUserMxCheckRank == theRankFunc) &&
603
(MXUserMX_LockRec == theLockFunc) &&
604
(MXUserMX_UnlockRec == theUnlockFunc) &&
605
(MXUserMX_TryLockRec == theTryLockFunc) &&
606
(MXUserMX_IsLockedByCurThreadRec == theIsLockedFunc)