aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/ipc/s_lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/ipc/s_lock.c')
-rw-r--r--src/backend/storage/ipc/s_lock.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/backend/storage/ipc/s_lock.c b/src/backend/storage/ipc/s_lock.c
new file mode 100644
index 00000000000..3cbe796fc59
--- /dev/null
+++ b/src/backend/storage/ipc/s_lock.c
@@ -0,0 +1,440 @@
+/*-------------------------------------------------------------------------
+ *
+ * s_lock.c--
+ * This file contains the implementation (if any) for spinlocks.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/s_lock.c,v 1.1.1.1 1996/07/09 06:21:54 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * DESCRIPTION
+ * The following code fragment should be written (in assembly
+ * language) on machines that have a native test-and-set instruction:
+ *
+ * void
+ * S_LOCK(char_address)
+ * char *char_address;
+ * {
+ * while (test_and_set(char_address))
+ * ;
+ * }
+ *
+ * If this is not done, POSTGRES will default to using System V
+ * semaphores (and take a large performance hit -- around 40% of
+ * its time on a DS5000/240 is spent in semop(3)...).
+ *
+ * NOTES
+ * AIX has a test-and-set but the recommended interface is the cs(3)
+ * system call. This provides an 8-instruction (plus system call
+ * overhead) uninterruptible compare-and-set operation. True
+ * spinlocks might be faster but using cs(3) still speeds up the
+ * regression test suite by about 25%. I don't have an assembler
+ * manual for POWER in any case.
+ *
+ */
+#ifdef WIN32
+#include <windows.h>
+#endif /* WIN32 */
+#include "storage/ipc.h"
+
+
+#if defined(HAS_TEST_AND_SET)
+
+#if defined (PORTNAME_next)
+/*
+ * NEXTSTEP (mach)
+ * slock_t is defined as a struct mutex.
+ */
+void
+S_LOCK(slock_t *lock)
+{
+ mutex_lock(lock);
+}
+void
+S_UNLOCK(slock_t *lock)
+{
+ mutex_unlock(lock);
+}
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ mutex_init(lock);
+}
+
+ /* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */
+int
+ S_LOCK_FREE(slock_t *lock)
+{
+ /* For Mach, we have to delve inside the entrails of `struct
+mutex'. Ick! */
+ return (lock->lock == 0);
+}
+
+#endif /* PORTNAME_next */
+
+
+
+#if defined(PORTNAME_irix5)
+/*
+ * SGI IRIX 5
+ * slock_t is defined as a struct abilock_t, which has a single unsigned long
+ * member.
+ *
+ * This stuff may be supplemented in the future with Masato Kataoka's MIPS-II
+ * assembly from his NECEWS SVR4 port, but we probably ought to retain this
+ * for the R3000 chips out there.
+ */
+void
+S_LOCK(slock_t *lock)
+{
+ /* spin_lock(lock); */
+ while (!acquire_lock(lock))
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ (void)release_lock(lock);
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ (void)init_lock(lock);
+}
+
+/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */
+int
+S_LOCK_FREE(slock_t *lock)
+{
+ return(stat_lock(lock)==UNLOCKED);
+}
+
+#endif /* PORTNAME_irix5 */
+
+
+/*
+ * OSF/1 (Alpha AXP)
+ *
+ * Note that slock_t on the Alpha AXP is msemaphore instead of char
+ * (see storage/ipc.h).
+ */
+
+#if defined(PORTNAME_alpha)
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (msem_lock(lock, MSEM_IF_NOWAIT) < 0)
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ (void) msem_unlock(lock, 0);
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ (void) msem_init(lock, MSEM_UNLOCKED);
+}
+
+int
+S_LOCK_FREE(slock_t *lock)
+{
+ return(lock->msem_state ? 0 : 1);
+}
+
+#endif /* PORTNAME_alpha */
+
+/*
+ * Solaris 2
+ */
+
+#if defined(PORTNAME_sparc_solaris)
+
+/* defined in port/.../tas.s */
+extern int tas(slock_t *lock);
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (tas(lock))
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ *lock = 0;
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ S_UNLOCK(lock);
+}
+
+#endif /* PORTNAME_sparc_solaris */
+
+/*
+ * AIX (POWER)
+ *
+ * Note that slock_t on POWER/POWER2/PowerPC is int instead of char
+ * (see storage/ipc.h).
+ */
+
+#if defined(PORTNAME_aix)
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (cs((int *) lock, 0, 1))
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ *lock = 0;
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ S_UNLOCK(lock);
+}
+
+#endif /* PORTNAME_aix */
+
+/*
+ * HP-UX (PA-RISC)
+ *
+ * Note that slock_t on PA-RISC is a structure instead of char
+ * (see storage/ipc.h).
+ */
+
+#if defined(PORTNAME_hpux)
+
+/* defined in port/.../tas.s */
+extern int tas(slock_t *lock);
+
+/*
+* a "set" slock_t has a single word cleared. a "clear" slock_t has
+* all words set to non-zero.
+*/
+static slock_t clear_lock = { -1, -1, -1, -1 };
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (tas(lock))
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ *lock = clear_lock; /* struct assignment */
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ S_UNLOCK(lock);
+}
+
+int
+S_LOCK_FREE(slock_t *lock)
+{
+ register int *lock_word = (int *) (((long) lock + 15) & ~15);
+
+ return(*lock_word != 0);
+}
+
+#endif /* PORTNAME_hpux */
+
+/*
+ * sun3
+ */
+
+#if (defined(sun) && ! defined(sparc))
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (tas(lock));
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ *lock = 0;
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ S_UNLOCK(lock);
+}
+
+static int
+tas_dummy()
+{
+ asm("LLA0:");
+ asm(" .data");
+ asm(" .text");
+ asm("|#PROC# 04");
+ asm(" .globl _tas");
+ asm("_tas:");
+ asm("|#PROLOGUE# 1");
+ asm(" movel sp@(0x4),a0");
+ asm(" tas a0@");
+ asm(" beq LLA1");
+ asm(" moveq #-128,d0");
+ asm(" rts");
+ asm("LLA1:");
+ asm(" moveq #0,d0");
+ asm(" rts");
+ asm(" .data");
+}
+
+#endif
+
+/*
+ * SPARC (SunOS 4)
+ */
+
+#if defined(PORTNAME_sparc)
+
+/* if we're using -ansi w/ gcc, use __asm__ instead of asm */
+#if defined(__STRICT_ANSI__)
+#define asm(x) __asm__(x)
+#endif
+
+static int
+tas_dummy()
+{
+ asm(".seg \"data\"");
+ asm(".seg \"text\"");
+ asm(".global _tas");
+ asm("_tas:");
+
+ /*
+ * Sparc atomic test and set (sparc calls it "atomic load-store")
+ */
+
+ asm("ldstub [%r8], %r8");
+
+ /*
+ * Did test and set actually do the set?
+ */
+
+ asm("tst %r8");
+
+ asm("be,a ReturnZero");
+
+ /*
+ * otherwise, just return.
+ */
+
+ asm("clr %r8");
+ asm("mov 0x1, %r8");
+ asm("ReturnZero:");
+ asm("retl");
+ asm("nop");
+}
+
+void
+S_LOCK(unsigned char *addr)
+{
+ while (tas(addr));
+}
+
+
+/*
+ * addr should be as in the above S_LOCK routine
+ */
+void
+S_UNLOCK(unsigned char *addr)
+{
+ *addr = 0;
+}
+
+void
+S_INIT_LOCK(unsigned char *addr)
+{
+ *addr = 0;
+}
+
+#endif /* PORTNAME_sparc */
+
+/*
+ * Linux and friends
+ */
+
+#if defined(PORTNAME_linux) || defined(PORTNAME_BSD44_derived)
+
+int
+tas(slock_t *m)
+{
+ slock_t res;
+ __asm__("xchgb %0,%1":"=q" (res),"=m" (*m):"0" (0x1));
+ return(res);
+}
+
+void
+S_LOCK(slock_t *lock)
+{
+ while (tas(lock))
+ ;
+}
+
+void
+S_UNLOCK(slock_t *lock)
+{
+ *lock = 0;
+}
+
+void
+S_INIT_LOCK(slock_t *lock)
+{
+ S_UNLOCK(lock);
+}
+
+#endif /* PORTNAME_linux || PORTNAME_BSD44_derived */
+
+
+#endif /* HAS_TEST_AND_SET */
+
+
+#ifdef WIN32
+void
+S_LOCK(HANDLE *lock)
+{
+ int x = 0;
+ x = x / x;
+}
+
+void
+S_UNLOCK(HANDLE *lock)
+{
+ int x = 0;
+ x = x / x;
+}
+
+void
+S_INIT_LOCK(HANDLE *lock)
+{
+ int x = 0;
+ x = x / x;
+}
+#endif /*WIN32*/