1 /*
2   +----------------------------------------------------------------------+
3   | APCu                                                                 |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2013 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Joe Watkins <joe.watkins@live.co.uk>                        |
16   +----------------------------------------------------------------------+
17  */
18 
19 #ifndef APC_LOCK_H
20 #define APC_LOCK_H
21 
22 /*
23  APCu works most efficiently where there is access to native read/write locks
24  If the current system has native rwlocks present they will be used, if they are
25 	not present, APCu will emulate their behavior with standard mutex.
26  While APCu is emulating read/write locks, reads and writes are exclusive,
27 	additionally the write lock prefers readers, as is the default behaviour of
28 	the majority of Posix rwlock implementations
29 */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include "apc.h"
36 
37 #ifndef PHP_WIN32
38 # ifndef __USE_UNIX98
39 #  define __USE_UNIX98
40 # endif
41 # include "pthread.h"
42 # ifndef APC_SPIN_LOCK
43 #   ifndef APC_FCNTL_LOCK
44 #       ifdef APC_NATIVE_RWLOCK
45 		typedef pthread_rwlock_t apc_lock_t;
46 #		define APC_LOCK_SHARED
47 #       else
48 		typedef pthread_mutex_t apc_lock_t;
49 #		define APC_LOCK_RECURSIVE
50 #       endif
51 #   else
52 		typedef int apc_lock_t;
53 #		define APC_LOCK_FILE
54 #   endif
55 # else
56 # define APC_LOCK_NICE 1
57 typedef struct {
58 	unsigned long state;
59 } apc_lock_t;
60 # endif
61 #else
62 /* XXX kernel lock mode only for now, compatible through all the wins, add more ifdefs for others */
63 # include "apc_windows_srwlock_kernel.h"
64 typedef apc_windows_cs_rwlock_t apc_lock_t;
65 # define APC_LOCK_SHARED
66 #endif
67 
68 /* {{{ functions */
69 /*
70   The following functions should be called once per process:
71 	apc_lock_init initializes attributes suitable for all locks
72 	apc_lock_cleanup destroys those attributes
73   This saves us from having to create and destroy attributes for
74   every lock we use at runtime */
75 PHP_APCU_API zend_bool apc_lock_init();
76 PHP_APCU_API void      apc_lock_cleanup();
77 /*
78   The following functions should be self explanitory:
79 */
80 PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock);
81 PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock);
82 PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock);
83 PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock);
84 PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock);
85 PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock); /* }}} */
86 
87 /* {{{ generic locking macros */
88 #define CREATE_LOCK(lock)     apc_lock_create(lock)
89 #define DESTROY_LOCK(lock)    apc_lock_destroy(lock)
90 #define WLOCK(lock)           apc_lock_wlock(lock)
91 #define WUNLOCK(lock)         { apc_lock_wunlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
92 #define RLOCK(lock)           apc_lock_rlock(lock)
93 #define RUNLOCK(lock)         { apc_lock_runlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
94 /* }}} */
95 
96 /* atomic operations */
97 #ifdef PHP_WIN32
98 # ifdef _WIN64
99 #  define ATOMIC_INC(a) InterlockedIncrement64(&a)
100 #  define ATOMIC_DEC(a) InterlockedDecrement64(&a)
101 #  define ATOMIC_ADD(a, b) (InterlockedExchangeAdd64(&a, b) + b)
102 #  define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange64(&a, new, old) == old)
103 # else
104 #  define ATOMIC_INC(a) InterlockedIncrement(&a)
105 #  define ATOMIC_DEC(a) InterlockedDecrement(&a)
106 #  define ATOMIC_ADD(a, b) (InterlockedExchangeAdd(&a, b) + b)
107 #  define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange(&a, new, old) == old)
108 # endif
109 #else
110 # define ATOMIC_INC(a) __sync_add_and_fetch(&a, 1)
111 # define ATOMIC_DEC(a) __sync_sub_and_fetch(&a, 1)
112 # define ATOMIC_ADD(a, b) __sync_add_and_fetch(&a, b)
113 # define ATOMIC_CAS(a, old, new) __sync_bool_compare_and_swap(&a, old, new)
114 #endif
115 
116 #endif
117