1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996-2002
* Sleepycat Software. All rights reserved.
*
* $Id: mutex.h,v 1.1.1.1.14.3 2004/11/01 18:50:40 hansp Exp $
*/
#ifndef _DB_MUTEX_H_
#define _DB_MUTEX_H_
/*
* Some of the Berkeley DB ports require single-threading at various
* places in the code. In those cases, these #defines will be set.
*/
#define DB_BEGIN_SINGLE_THREAD
#define DB_END_SINGLE_THREAD
/*********************************************************************
* POSIX.1 pthreads interface.
*********************************************************************/
#ifdef HAVE_MUTEX_PTHREADS
#include <pthread.h>
#define MUTEX_FIELDS \
pthread_mutex_t mutex; /* Mutex. */ \
pthread_cond_t cond; /* Condition variable. */
#endif
/*********************************************************************
* Solaris lwp threads interface.
*
* !!!
* We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of
* which are available), for two reasons. First, the Solaris C library
* includes versions of the both UI and POSIX thread mutex interfaces, but
* they are broken in that they don't support inter-process locking, and
* there's no way to detect it, e.g., calls to configure the mutexes for
* inter-process locking succeed without error. So, we use LWP mutexes so
* that we don't fail in fairly undetectable ways because the application
* wasn't linked with the appropriate threads library. Second, there were
* bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library
* before loading the libthread/libpthread threads libraries (e.g., by using
* dlopen to load the DB library), the pwrite64 interface would be translated
* into a call to pwrite and DB would drop core.
*********************************************************************/
#ifdef HAVE_MUTEX_SOLARIS_LWP
/*
* XXX
* Don't change <synch.h> to <sys/lwp.h> -- although lwp.h is listed in the
* Solaris manual page as the correct include to use, it causes the Solaris
* compiler on SunOS 2.6 to fail.
*/
#include <synch.h>
#define MUTEX_FIELDS \
lwp_mutex_t mutex; /* Mutex. */ \
lwp_cond_t cond; /* Condition variable. */
#endif
/*********************************************************************
* Solaris/Unixware threads interface.
*********************************************************************/
#ifdef HAVE_MUTEX_UI_THREADS
#include <thread.h>
#include <synch.h>
#define MUTEX_FIELDS \
mutex_t mutex; /* Mutex. */ \
cond_t cond; /* Condition variable. */
#endif
/*********************************************************************
* AIX C library functions.
*********************************************************************/
#ifdef HAVE_MUTEX_AIX_CHECK_LOCK
#include <sys/atomic_op.h>
typedef int tsl_t;
#define MUTEX_ALIGN sizeof(int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) 0
#define MUTEX_SET(x) (!_check_lock(x, 0, 1))
#define MUTEX_UNSET(x) _clear_lock(x, 0)
#endif
#endif
/*********************************************************************
* General C library functions (msemaphore).
*
* !!!
* Check for HPPA as a special case, because it requires unusual alignment,
* and doesn't support semaphores in malloc(3) or shmget(2) memory.
*
* !!!
* Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single
* process makes two msem_lock() calls in a row, the second one returns an
* error. We depend on the fact that we can lock against ourselves in the
* locking subsystem, where we set up a mutex so that we can block ourselves.
* Tested on OSF1 v4.0.
*********************************************************************/
#ifdef HAVE_MUTEX_HPPA_MSEM_INIT
#define MUTEX_NO_MALLOC_LOCKS
#define MUTEX_NO_SHMGET_LOCKS
#define MUTEX_ALIGN 16
#endif
#if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT)
#include <sys/mman.h>
typedef msemaphore tsl_t;
#ifndef MUTEX_ALIGN
#define MUTEX_ALIGN sizeof(int)
#endif
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) (msem_init(x, MSEM_UNLOCKED) <= (msemaphore *)0)
#define MUTEX_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT))
#define MUTEX_UNSET(x) msem_unlock(x, 0)
#endif
#endif
/*********************************************************************
* Plan 9 library functions.
*********************************************************************/
#ifdef HAVE_MUTEX_PLAN9
typedef Lock tsl_t;
#define MUTEX_ALIGN sizeof(int)
#define MUTEX_INIT(x) (memset(x, 0, sizeof(Lock)), 0)
#define MUTEX_SET(x) canlock(x)
#define MUTEX_UNSET(x) unlock(x)
#endif
/*********************************************************************
* Reliant UNIX C library functions.
*********************************************************************/
#ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN
#include <ulocks.h>
typedef spinlock_t tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) (initspin(x, 1), 0)
#define MUTEX_SET(x) (cspinlock(x) == 0)
#define MUTEX_UNSET(x) spinunlock(x)
#endif
#endif
/*********************************************************************
* General C library functions (POSIX 1003.1 sema_XXX).
*
* !!!
* Never selected by autoconfig in this release (semaphore calls are known
* to not work in Solaris 5.5).
*********************************************************************/
#ifdef HAVE_MUTEX_SEMA_INIT
#include <synch.h>
typedef sema_t tsl_t;
#define MUTEX_ALIGN sizeof(int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_DESTROY(x) sema_destroy(x)
#define MUTEX_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0)
#define MUTEX_SET(x) (sema_wait(x) == 0)
#define MUTEX_UNSET(x) sema_post(x)
#endif
#endif
/*********************************************************************
* SGI C library functions.
*********************************************************************/
#ifdef HAVE_MUTEX_SGI_INIT_LOCK
#include <abi_mutex.h>
typedef abilock_t tsl_t;
#define MUTEX_ALIGN sizeof(int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) (init_lock(x) != 0)
#define MUTEX_SET(x) (!acquire_lock(x))
#define MUTEX_UNSET(x) release_lock(x)
#endif
#endif
/*********************************************************************
* Solaris C library functions.
*
* !!!
* These are undocumented functions, but they're the only ones that work
* correctly as far as we know.
*********************************************************************/
#ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY
#include <sys/machlock.h>
typedef lock_t tsl_t;
#define MUTEX_ALIGN sizeof(int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) 0
#define MUTEX_SET(x) _lock_try(x)
#define MUTEX_UNSET(x) _lock_clear(x)
#endif
#endif
/*********************************************************************
* VMS.
*********************************************************************/
#ifdef HAVE_MUTEX_VMS
#include <sys/mman.h>;
#include <builtins.h>
typedef unsigned char tsl_t;
#define MUTEX_ALIGN sizeof(unsigned int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#ifdef __ALPHA
#define MUTEX_SET(tsl) (!__TESTBITSSI(tsl, 0))
#else /* __VAX */
#define MUTEX_SET(tsl) (!(int)_BBSSI(0, tsl))
#endif
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* VxWorks
* Use basic binary semaphores in VxWorks, as we currently do not need
* any special features. We do need the ability to single-thread the
* entire system, however, because VxWorks doesn't support the open(2)
* flag O_EXCL, the mechanism we normally use to single thread access
* when we're first looking for a DB environment.
*********************************************************************/
#ifdef HAVE_MUTEX_VXWORKS
#include "taskLib.h"
typedef SEM_ID tsl_t;
#define MUTEX_ALIGN sizeof(unsigned int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_SET(tsl) (semTake((*tsl), WAIT_FOREVER) == OK)
#define MUTEX_UNSET(tsl) (semGive((*tsl)))
#define MUTEX_INIT(tsl) \
((*(tsl) = semBCreate(SEM_Q_FIFO, SEM_FULL)) == NULL)
#define MUTEX_DESTROY(tsl) semDelete(*tsl)
#endif
/*
* Use the taskLock() mutex to eliminate a race where two tasks are
* trying to initialize the global lock at the same time.
*/
#undef DB_BEGIN_SINGLE_THREAD
#define DB_BEGIN_SINGLE_THREAD \
do { \
if (DB_GLOBAL(db_global_init)) \
(void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \
else { \
taskLock(); \
if (DB_GLOBAL(db_global_init)) { \
taskUnlock(); \
(void)semTake(DB_GLOBAL(db_global_lock), \
WAIT_FOREVER); \
continue; \
} \
DB_GLOBAL(db_global_lock) = \
semBCreate(SEM_Q_FIFO, SEM_EMPTY); \
if (DB_GLOBAL(db_global_lock) != NULL) \
DB_GLOBAL(db_global_init) = 1; \
taskUnlock(); \
} \
} while (DB_GLOBAL(db_global_init) == 0)
#undef DB_END_SINGLE_THREAD
#define DB_END_SINGLE_THREAD (void)semGive(DB_GLOBAL(db_global_lock))
#endif
/*********************************************************************
* Win16
*
* Win16 spinlocks are simple because we cannot possibly be preempted.
*
* !!!
* We should simplify this by always returning a no-need-to-lock lock
* when we initialize the mutex.
*********************************************************************/
#ifdef HAVE_MUTEX_WIN16
typedef unsigned int tsl_t;
#define MUTEX_ALIGN sizeof(unsigned int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) 0
#define MUTEX_SET(tsl) (*(tsl) = 1)
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#endif
#endif
/*********************************************************************
* Win32
*********************************************************************/
#ifdef HAVE_MUTEX_WIN32
#define MUTEX_FIELDS \
LONG tas; \
LONG nwaiters; \
u_int32_t id; /* ID used for creating events */ \
#if defined(LOAD_ACTUAL_MUTEX_CODE)
#define MUTEX_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1))
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* 68K/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/68K, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile("tas %1; \n \
seq %0" \
: "=dm" (__r), "=m" (*__l) \
: "1" (*__l) \
); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* ALPHA/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY
typedef u_int32_t tsl_t;
#define MUTEX_ALIGN 4
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/alpha. Should return 0 if could not acquire the lock, 1 if
* lock was acquired properly.
*/
#ifdef __GNUC__
static inline int
MUTEX_SET(tsl_t *tsl) {
register tsl_t *__l = tsl;
register tsl_t __r;
asm volatile(
"1: ldl_l %0,%2\n"
" blbs %0,2f\n"
" or $31,1,%0\n"
" stl_c %0,%1\n"
" beq %0,3f\n"
" mb\n"
" br 3f\n"
"2: xor %0,%0\n"
"3:"
: "=&r"(__r), "=m"(*__l) : "1"(*__l) : "memory");
return __r;
}
/*
* Unset mutex. Judging by Alpha Architecture Handbook, the mb instruction
* might be necessary before unlocking
*/
static inline int
MUTEX_UNSET(tsl_t *tsl) {
asm volatile(" mb\n");
return *tsl = 0;
}
#endif
#ifdef __DECC
#include <alpha/builtins.h>
#define MUTEX_SET(tsl) (__LOCK_LONG_RETRY((tsl), 1) != 0)
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#endif
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* ARM/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_ARM_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For arm/gcc, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
int __r; \
asm volatile("swpb %0, %1, [%2]" \
: "=r" (__r) \
: "0" (1), "r" (tsl) \
: "memory" \
); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(volatile tsl_t *)(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* HPPA/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY
typedef u_int32_t tsl_t;
#define MUTEX_ALIGN 16
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* The PA-RISC has a "load and clear" instead of a "test and set" instruction.
* The 32-bit word used by that instruction must be 16-byte aligned. We could
* use the "aligned" attribute in GCC but that doesn't work for stack variables.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile("ldcws 0(%1),%0" : "=r" (__r) : "r" (__l)); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = -1)
#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
#endif
#endif
/*********************************************************************
* IA64/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/ia64, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
long __r; \
asm volatile("xchg1 %0=%1,%3" : "=r"(__r), "=m"(*__l) : "1"(*__l), "r"(1));\
__r ^ 1; \
})
/*
* Store through a "volatile" pointer so we get a store with "release"
* semantics.
*/
#define MUTEX_UNSET(tsl) (*(volatile unsigned char *)(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* PowerPC/gcc assembly.
*********************************************************************/
#if defined(HAVE_MUTEX_PPC_GENERIC_GCC_ASSEMBLY) || \
(HAVE_MUTEX_PPC_APPLE_GCC_ASSEMBLY)
typedef u_int32_t tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* The PowerPC does a sort of pseudo-atomic locking. You set up a
* 'reservation' on a chunk of memory containing a mutex by loading the
* mutex value with LWARX. If the mutex has an 'unlocked' (arbitrary)
* value, you then try storing into it with STWCX. If no other process or
* thread broke your 'reservation' by modifying the memory containing the
* mutex, then the STCWX succeeds; otherwise it fails and you try to get
* a reservation again.
*
* While mutexes are explicitly 4 bytes, a 'reservation' applies to an
* entire cache line, normally 32 bytes, aligned naturally. If the mutex
* lives near data that gets changed a lot, there's a chance that you'll
* see more broken reservations than you might otherwise. The only
* situation in which this might be a problem is if one processor is
* beating on a variable in the same cache block as the mutex while another
* processor tries to acquire the mutex. That's bad news regardless
* because of the way it bashes caches, but if you can't guarantee that a
* mutex will reside in a relatively quiescent cache line, you might
* consider padding the mutex to force it to live in a cache line by
* itself. No, you aren't guaranteed that cache lines are 32 bytes. Some
* embedded processors use 16-byte cache lines, while some 64-bit
* processors use 128-bit cache lines. But assuming a 32-byte cache line
* won't get you into trouble for now.
*
* If mutex locking is a bottleneck, then you can speed it up by adding a
* regular LWZ load before the LWARX load, so that you can test for the
* common case of a locked mutex without wasting cycles making a reservation.
*
* 'set' mutexes have the value 1, like on Intel; the returned value from
* MUTEX_SET() is 1 if the mutex previously had its low bit clear, 0 otherwise.
*
* Mutexes on Mac OS X work the same way as the standard PowerPC version, but
* the assembler syntax is subtly different -- the standard PowerPC version
* assembles but doesn't work correctly. This version makes (unnecessary?)
* use of a stupid linker trick: __db_mutex_tas_dummy is never called, but the
* ___db_mutex_set label is used as a function name.
*/
#ifdef HAVE_MUTEX_PPC_APPLE_GCC_ASSEMBLY
extern int __db_mutex_set __P((volatile tsl_t *));
void
__db_mutex_tas_dummy()
{
__asm__ __volatile__(" \n\
.globl ___db_mutex_set \n\
___db_mutex_set: \n\
lwarx r5,0,r3 \n\
cmpwi r5,0 \n\
bne fail \n\
addi r5,r5,1 \n\
stwcx. r5,0,r3 \n\
beq success \n\
fail: \n\
li r3,0 \n\
blr \n\
success: \n\
li r3,1 \n\
blr");
}
#define MUTEX_SET(tsl) __db_mutex_set(tsl)
#endif
#ifdef HAVE_MUTEX_PPC_GENERIC_GCC_ASSEMBLY
#define MUTEX_SET(tsl) ({ \
int __one = 1; \
int __r; \
tsl_t *__l = (tsl); \
asm volatile (" \
0: \
lwarx %0,0,%1; \
cmpwi %0,0; \
bne 1f; \
stwcx. %2,0,%1; \
bne- 0b; \
isync; \
1:" \
: "=&r" (__r) \
: "r" (__l), "r" (__one)); \
!(__r & 1); \
})
#endif
#define MUTEX_UNSET(tsl) ({ \
asm volatile("lwsync # MUTEX_UNSET ":::"memory"); \
(*(tsl) = 0); \
})
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* S/390 32-bit assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_S390_GCC_ASSEMBLY
typedef int tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/S390, 0 is clear, 1 is set.
*/
static inline int
MUTEX_SET(tsl_t *tsl) { \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile( \
" la 1,%1\n" \
" lhi 0,1\n" \
" l %0,%1\n" \
"0: cs %0,0,0(1)\n" \
" jl 0b" \
: "=&d" (__r), "+m" (*__l) \
: : "0", "1", "cc"); \
return !__r; \
}
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* SCO/cc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* UnixWare has threads in libthread, but OpenServer doesn't (yet).
*
* For cc/x86, 0 is clear, 1 is set.
*/
#if defined(__USLC__)
asm int
_tsl_set(void *tsl)
{
%mem tsl
movl tsl, %ecx
movl $1, %eax
lock
xchgb (%ecx),%al
xorl $1,%eax
}
#endif
#define MUTEX_SET(tsl) _tsl_set(tsl)
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* Sparc/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
*
* The ldstub instruction takes the location specified by its first argument
* (a register containing a memory address) and loads its contents into its
* second argument (a register) and atomically sets the contents the location
* specified by its first argument to a byte of 1s. (The value in the second
* argument is never read, but only overwritten.)
*
* The stbar is needed for v8, and is implemented as membar #sync on v9,
* so is functional there as well. For v7, stbar may generate an illegal
* instruction and we have no way to tell what we're running on. Some
* operating systems notice and skip this instruction in the fault handler.
*
* For gcc/sparc, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
register tsl_t __r; \
__asm__ volatile \
("ldstub [%1],%0; stbar" \
: "=r"( __r) : "r" (__l)); \
!__r; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* UTS/cc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY
typedef int tsl_t;
#define MUTEX_ALIGN sizeof(int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
#define MUTEX_INIT(x) 0
#define MUTEX_SET(x) (!uts_lock(x, 1))
#define MUTEX_UNSET(x) (*(x) = 0)
#endif
#endif
/*********************************************************************
* MIPS/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_MIPS_GCC_ASSEMBLY
typedef unsigned int tsl_t;
#define MUTEX_ALIGN sizeof(unsigned int)
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/MIPS;
*/
#define MUTEX_SET(tsl) ({ \
tsl_t tmp, res; \
register tsl_t *__l = (tsl); \
__asm__ __volatile__( \
".set\tnoreorder\t\t# test_and_set_bit\n" \
"1:\tll\t%0, %1\n\t" \
"ori\t%2, %0, 1\n\t" \
"sc\t%2, %1\n\t" \
"beqz\t%2, 1b\n\t" \
" andi\t%2, %0, 1\n\t" \
"sync\n\t" \
".set\treorder" \
: "=&r" (tmp), "=m" (*__l), "=&r" (res) \
: "m" (*__l) \
: "memory"); \
(res ^ 1) & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* x86/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/x86, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile("movl $1,%%eax; lock; xchgb %1,%%al; xorl $1,%%eax"\
: "=&a" (__r), "=m" (*__l) \
: "1" (*__l) \
); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* x86_64/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_X86_64_GCC_ASSEMBLY
typedef unsigned char tsl_t;
#ifdef LOAD_ACTUAL_MUTEX_CODE
/*
* For gcc/x86-64, 0 is clear, 1 is set.
*/
#define MUTEX_SET(tsl) ({ \
register tsl_t *__l = (tsl); \
int __r; \
asm volatile("movq $1,%%rax; lock; xchgb %1,%%al; xorq $1,%%rax"\
: "=&a" (__r), "=m" (*__l) \
: "1" (*__l) \
); \
__r & 1; \
})
#define MUTEX_UNSET(tsl) (*(tsl) = 0)
#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
#endif
#endif
/*********************************************************************
* alphalinux/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_ALPHA_LINUX_ASSEMBLY
typedef unsigned long int tsl_t;
#define MUTEX_ALIGN 8
#endif
/*********************************************************************
* sparc32linux/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_SPARC32_LINUX_ASSEMBLY
typedef unsigned char tsl_t;
#endif
/*********************************************************************
* sparc64linux/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_SPARC64_LINUX_ASSEMBLY
typedef unsigned char tsl_t;
#endif
/*********************************************************************
* s390linux/gcc assembly.
*********************************************************************/
#ifdef HAVE_MUTEX_S390_LINUX_ASSEMBLY
typedef volatile int tsl_t;
#endif
/*
* Mutex alignment defaults to one byte.
*
* !!!
* Various systems require different alignments for mutexes (the worst we've
* seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed
* to return reasonable alignment, all other mutex users must ensure proper
* alignment locally.
*/
#ifndef MUTEX_ALIGN
#define MUTEX_ALIGN 1
#endif
/*
* Mutex destruction defaults to a no-op.
*/
#ifdef LOAD_ACTUAL_MUTEX_CODE
#ifndef MUTEX_DESTROY
#define MUTEX_DESTROY(x)
#endif
#endif
/*
* !!!
* These defines are separated into the u_int8_t flags stored in the
* mutex below, and the 32 bit flags passed to __db_mutex_setup.
* But they must co-exist and not overlap. Flags to __db_mutex_setup are:
*
* MUTEX_ALLOC - Use when the mutex to initialize needs to be allocated.
* The 'ptr' arg to __db_mutex_setup should be a DB_MUTEX ** whenever
* you use this flag. If this flag is not set, the 'ptr' arg is
* a DB_MUTEX *.
* MUTEX_NO_RECORD - Explicitly do not record the mutex in the region.
* Otherwise the mutex will be recorded by default. If you set
* this you need to understand why you don't need it recorded. The
* *only* ones not recorded are those that are part of region structures
* that only get destroyed when the regions are destroyed.
* MUTEX_NO_RLOCK - Explicitly do not lock the given region otherwise
* the region will be locked by default.
* MUTEX_SELF_BLOCK - Set if self blocking mutex.
* MUTEX_THREAD - Set if mutex is a thread-only mutex.
*/
#define MUTEX_IGNORE 0x001 /* Ignore, no lock required. */
#define MUTEX_INITED 0x002 /* Mutex is successfully initialized */
#define MUTEX_MPOOL 0x004 /* Allocated from mpool. */
#define MUTEX_SELF_BLOCK 0x008 /* Must block self. */
/* Flags only, may be larger than 0xff. */
#define MUTEX_ALLOC 0x00000100 /* Allocate and init a mutex */
#define MUTEX_NO_RECORD 0x00000200 /* Do not record lock */
#define MUTEX_NO_RLOCK 0x00000400 /* Do not acquire region lock */
#define MUTEX_THREAD 0x00000800 /* Thread-only mutex. */
/* Mutex. */
struct __mutex_t {
#ifdef HAVE_MUTEX_THREADS
#ifdef MUTEX_FIELDS
MUTEX_FIELDS
#else
tsl_t tas; /* Test and set. */
#endif
u_int32_t spins; /* Spins before block. */
u_int32_t locked; /* !0 if locked. */
#else
u_int32_t off; /* Byte offset to lock. */
u_int32_t pid; /* Lock holder: 0 or process pid. */
#endif
u_int32_t mutex_set_wait; /* Granted after wait. */
u_int32_t mutex_set_nowait; /* Granted without waiting. */
u_int32_t mutex_set_spin; /* Granted without spinning. */
u_int32_t mutex_set_spins; /* Total number of spins. */
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
roff_t reg_off; /* Shared lock info offset. */
#endif
u_int8_t flags; /* MUTEX_XXX */
};
/* Redirect calls to the correct functions. */
#ifdef HAVE_MUTEX_THREADS
#if defined(HAVE_MUTEX_PTHREADS) || \
defined(HAVE_MUTEX_SOLARIS_LWP) || \
defined(HAVE_MUTEX_UI_THREADS)
#define __db_mutex_init_int(a, b, c, d) __db_pthread_mutex_init(a, b, d)
#define __db_mutex_lock(a, b) __db_pthread_mutex_lock(a, b)
#define __db_mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b)
#define __db_mutex_destroy(a) __db_pthread_mutex_destroy(a)
#elif defined(HAVE_MUTEX_WIN32)
#define __db_mutex_init_int(a, b, c, d) __db_win32_mutex_init(a, b, d)
#define __db_mutex_lock(a, b) __db_win32_mutex_lock(a, b)
#define __db_mutex_unlock(a, b) __db_win32_mutex_unlock(a, b)
#define __db_mutex_destroy(a) __db_win32_mutex_destroy(a)
#else
#define __db_mutex_init_int(a, b, c, d) __db_tas_mutex_init(a, b, d)
#define __db_mutex_lock(a, b) __db_tas_mutex_lock(a, b)
#define __db_mutex_unlock(a, b) __db_tas_mutex_unlock(a, b)
#define __db_mutex_destroy(a) __db_tas_mutex_destroy(a)
#endif
#else
#define __db_mutex_init_int(a, b, c, d) __db_fcntl_mutex_init(a, b, c)
#define __db_mutex_lock(a, b) __db_fcntl_mutex_lock(a, b)
#define __db_mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b)
#define __db_mutex_destroy(a) __db_fcntl_mutex_destroy(a)
#endif
/* Redirect system resource calls to correct functions */
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
#define __db_maintinit(a, b, c) __db_shreg_maintinit(a, b, c)
#define __db_shlocks_clear(a, b, c) __db_shreg_locks_clear(a, b, c)
#define __db_shlocks_destroy(a, b) __db_shreg_locks_destroy(a, b)
#define __db_mutex_init(a, b, c, d, e, f) \
__db_shreg_mutex_init(a, b, c, d, e, f)
#else
#define __db_maintinit(a, b, c)
#define __db_shlocks_clear(a, b, c)
#define __db_shlocks_destroy(a, b)
#define __db_mutex_init(a, b, c, d, e, f) __db_mutex_init_int(a, b, c, d)
#endif
/*
* Lock/unlock a mutex. If the mutex was marked as uninteresting, the thread
* of control can proceed without it.
*
* If the lock is for threads-only, then it was optionally not allocated and
* file handles aren't necessary, as threaded applications aren't supported by
* fcntl(2) locking.
*/
#ifdef DIAGNOSTIC
/*
* XXX
* We want to switch threads as often as possible. Yield every time
* we get a mutex to ensure contention.
*/
#define MUTEX_LOCK(dbenv, mp) \
if (!F_ISSET((mp), MUTEX_IGNORE)) \
DB_ASSERT(__db_mutex_lock(dbenv, mp) == 0); \
if (F_ISSET(dbenv, DB_ENV_YIELDCPU)) \
__os_yield(NULL, 1);
#else
#define MUTEX_LOCK(dbenv, mp) \
if (!F_ISSET((mp), MUTEX_IGNORE)) \
(void)__db_mutex_lock(dbenv, mp);
#endif
#define MUTEX_UNLOCK(dbenv, mp) \
if (!F_ISSET((mp), MUTEX_IGNORE)) \
(void)__db_mutex_unlock(dbenv, mp);
#define MUTEX_THREAD_LOCK(dbenv, mp) \
if (mp != NULL) \
MUTEX_LOCK(dbenv, mp)
#define MUTEX_THREAD_UNLOCK(dbenv, mp) \
if (mp != NULL) \
MUTEX_UNLOCK(dbenv, mp)
/*
* We use a single file descriptor for fcntl(2) locking, and (generally) the
* object's offset in a shared region as the byte that we're locking. So,
* there's a (remote) possibility that two objects might have the same offsets
* such that the locks could conflict, resulting in deadlock. To avoid this
* possibility, we offset the region offset by a small integer value, using a
* different offset for each subsystem's locks. Since all region objects are
* suitably aligned, the offset guarantees that we don't collide with another
* region's objects.
*/
#define DB_FCNTL_OFF_GEN 0 /* Everything else. */
#define DB_FCNTL_OFF_LOCK 1 /* Lock subsystem offset. */
#define DB_FCNTL_OFF_MPOOL 2 /* Mpool subsystem offset. */
#ifdef HAVE_MUTEX_SYSTEM_RESOURCES
/*
* When the underlying mutexes require library (most likely heap) or system
* resources, we have to clean up when we discard mutexes (for the library
* resources) and both when discarding mutexes and after application failure
* (for the mutexes requiring system resources). This violates the rule that
* we never look at a shared region after application failure, but we've no
* other choice. In those cases, the #define HAVE_MUTEX_SYSTEM_RESOURCES is
* set.
*
* To support mutex release after application failure, allocate thread-handle
* mutexes in shared memory instead of in the heap. The number of slots we
* allocate for this purpose isn't configurable, but this tends to be an issue
* only on embedded systems where we don't expect large server applications.
*/
#define DB_MAX_HANDLES 100 /* Mutex slots for handles. */
#endif
#endif /* !_DB_MUTEX_H_ */
|