diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-08-09 15:30:51 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-08-09 15:30:51 -0400 |
commit | 6760a4d4029121981bf3ec24847ddfbacecc070d (patch) | |
tree | feb33208524b430e32fefd2c11158235ba1306a6 /src/include | |
parent | 028a0c5a2913f18c954845cc014786912f39fa30 (diff) | |
download | postgresql-6760a4d4029121981bf3ec24847ddfbacecc070d.tar.gz |
Documentation improvement and minor code cleanups for the latch facility.
Improve the documentation around weak-memory-ordering risks, and do a pass
of general editorialization on the comments in the latch code. Make the
Windows latch code more like the Unix latch code where feasible; in
particular provide the same Assert checks in both implementations.
Fix poorly-placed WaitLatch call in syncrep.c.
This patch resolves, for the moment, concerns around weak-memory-ordering
bugs in latch-related code: we have documented the restrictions and checked
that existing calls meet them. In 9.2 I hope that we will install suitable
memory barrier instructions in SetLatch/ResetLatch, so that their callers
don't need to be quite so careful.
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/storage/latch.h | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 03ec07119b..4da28566a6 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -3,6 +3,66 @@ * latch.h * Routines for interprocess latches * + * A latch is a boolean variable, with operations that let processes sleep + * until it is set. A latch can be set from another process, or a signal + * handler within the same process. + * + * The latch interface is a reliable replacement for the common pattern of + * using pg_usleep() or select() to wait until a signal arrives, where the + * signal handler sets a flag variable. Because on some platforms an + * incoming signal doesn't interrupt sleep, and even on platforms where it + * does there is a race condition if the signal arrives just before + * entering the sleep, the common pattern must periodically wake up and + * poll the flag variable. The pselect() system call was invented to solve + * this problem, but it is not portable enough. Latches are designed to + * overcome these limitations, allowing you to sleep without polling and + * ensuring quick response to signals from other processes. + * + * There are two kinds of latches: local and shared. A local latch is + * initialized by InitLatch, and can only be set from the same process. + * A local latch can be used to wait for a signal to arrive, by calling + * SetLatch in the signal handler. A shared latch resides in shared memory, + * and must be initialized at postmaster startup by InitSharedLatch. Before + * a shared latch can be waited on, it must be associated with a process + * with OwnLatch. Only the process owning the latch can wait on it, but any + * process can set it. + * + * There are three basic operations on a latch: + * + * SetLatch - Sets the latch + * ResetLatch - Clears the latch, allowing it to be set again + * WaitLatch - Waits for the latch to become set + * + * WaitLatch includes a provision for timeouts (which should hopefully not + * be necessary once the code is fully latch-ified). + * See unix_latch.c for detailed specifications for the exported functions. + * + * The correct pattern to wait for event(s) is: + * + * for (;;) + * { + * ResetLatch(); + * if (work to do) + * Do Stuff(); + * WaitLatch(); + * } + * + * It's important to reset the latch *before* checking if there's work to + * do. Otherwise, if someone sets the latch between the check and the + * ResetLatch call, you will miss it and Wait will incorrectly block. + * + * To wake up the waiter, you must first set a global flag or something + * else that the wait loop tests in the "if (work to do)" part, and call + * SetLatch *after* that. SetLatch is designed to return quickly if the + * latch is already set. + * + * Presently, when using a shared latch for interprocess signalling, the + * flag variable(s) set by senders and inspected by the wait loop must + * be protected by spinlocks or LWLocks, else it is possible to miss events + * on machines with weak memory ordering (such as PPC). This restriction + * will be lifted in future by inserting suitable memory barriers into + * SetLatch and ResetLatch. + * * * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -44,16 +104,17 @@ extern int WaitLatchOrSocket(volatile Latch *latch, pgsocket sock, extern void SetLatch(volatile Latch *latch); extern void ResetLatch(volatile Latch *latch); -#define TestLatch(latch) (((volatile Latch *) latch)->is_set) +/* beware of memory ordering issues if you use this macro! */ +#define TestLatch(latch) (((volatile Latch *) (latch))->is_set) /* - * Unix implementation uses SIGUSR1 for inter-process signaling, Win32 doesn't - * need this. + * Unix implementation uses SIGUSR1 for inter-process signaling. + * Win32 doesn't need this. */ #ifndef WIN32 extern void latch_sigusr1_handler(void); #else -#define latch_sigusr1_handler() +#define latch_sigusr1_handler() ((void) 0) #endif #endif /* LATCH_H */ |