├── CREDITS ├── LICENSE ├── README.md ├── config.m4 ├── config.w32 ├── package.xml ├── php_sync.h ├── sync.c └── tests ├── 001.phpt ├── 002.phpt ├── 003.phpt ├── 004.phpt ├── 005.phpt ├── 006.phpt ├── 007.phpt ├── 008.phpt ├── 009.phpt ├── 010.phpt ├── 011.phpt ├── 012.phpt ├── 013.phpt ├── 014.phpt ├── 015.phpt └── 016.phpt /CREDITS: -------------------------------------------------------------------------------- 1 | sync 2 | CubicleSoft 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2014 CubicleSoft 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CubicleSoft PHP Extension: Synchronization Objects (sync) 2 | ========================================================== 3 | 4 | The 'sync' extension introduces synchronization objects into PHP. Named and unnamed Mutex, Semaphore, Event, Reader-Writer, and named Shared Memory objects provide OS-level synchronization mechanisms on both *NIX (POSIX shared memory and pthread shared memory synchronization required) and Windows platforms. The extension comes with a test suite that integrates cleanly into 'make test'. 5 | 6 | The 'sync' extension is a direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp 7 | 8 | This extension uses the liberal MIT open source license. And, of course, it sits on GitHub for all of that pull request and issue tracker goodness to easily submit changes and ideas respectively. 9 | 10 | Details 11 | ------- 12 | 13 | An exception may be thrown from the constructors if the target object can't be created for some reason. 14 | 15 | All synchronization objects are attempted to be unlocked cleanly within PHP itself. The exception is if an object's $autounlock option is initialized to false. If PHP terminates a script and doesn't unlock the object, it can leave the object in an unpredictable state. 16 | 17 | NOTE: When using "named" objects, the initialization must be identical for a given name and have a specific purpose. Reusing named objects for other purposes is not a good idea and will probably result in breaking both applications. However, different object types can share the same name (e.g. a Mutex and an Event object can have the same name). 18 | 19 | ```` 20 | void SyncMutex::__construct([string $name = null]) 21 | Constructs a named or unnamed mutex object. 22 | 23 | bool SyncMutex::lock([int $wait = -1]) 24 | Locks a mutex object. $wait is in milliseconds. 25 | 26 | bool SyncMutex::unlock([bool $all = false]) 27 | Unlocks a mutex object. 28 | 29 | 30 | void SyncSemaphore::__construct([string $name = null, [int $initialval = 1, [bool $autounlock = true]]]) 31 | Constructs a named or unnamed semaphore object. Don't set $autounlock to false unless you really know what you are doing. 32 | 33 | bool SyncSemaphore::lock([int $wait = -1]) 34 | Locks a semaphore object. $wait is in milliseconds. 35 | 36 | bool SyncSemaphore::unlock([int &$prevcount]) 37 | Unlocks a semaphore object. 38 | 39 | 40 | void SyncEvent::__construct([string $name = null, [bool $manual = false], [bool $prefire = false]]) 41 | Constructs a named or unnamed event object. 42 | 43 | bool SyncEvent::wait([int $wait = -1]) 44 | Waits for an event object to fire. $wait is in milliseconds. 45 | 46 | bool SyncEvent::fire() 47 | Lets a thread through that is waiting. Lets multiple threads through that are waiting if the event object is 'manual'. 48 | 49 | bool SyncEvent::reset() 50 | Resets the event object state. Only use when the event object is 'manual'. 51 | 52 | 53 | void SyncReaderWriter::__construct([string $name = null, [bool $autounlock = true]]) 54 | Constructs a named or unnamed reader-writer object. Don't set $autounlock to false unless you really know what you are doing. 55 | 56 | bool SyncReaderWriter::readlock([int $wait = -1]) 57 | Read locks a reader-writer object. $wait is in milliseconds. 58 | 59 | bool SyncReaderWriter::writelock([int $wait = -1]) 60 | Write locks a reader-writer object. $wait is in milliseconds. 61 | 62 | bool SyncReaderWriter::readunlock() 63 | Read unlocks a reader-writer object. 64 | 65 | bool SyncReaderWriter::writeunlock() 66 | Write unlocks a reader-writer object. 67 | 68 | 69 | void SyncSharedMemory::__construct(string $name, int $size) 70 | Constructs a named shared memory object. 71 | 72 | bool SyncSharedMemory::first() 73 | Returns whether or not this shared memory segment is the first time accessed (i.e. not initialized). 74 | 75 | int SyncSharedMemory::size() 76 | Returns the shared memory size. 77 | 78 | int SyncSharedMemory::write(string $string, [int $start = 0]) 79 | Copies data to shared memory. 80 | 81 | string SyncSharedMemory::read([int $start = 0, [int $length = null]]) 82 | Copies data from shared memory. 83 | ```` 84 | 85 | Usage Examples 86 | -------------- 87 | 88 | Example Mutex usage: 89 | 90 | ```php 91 | $mutex = new SyncMutex(); 92 | 93 | $mutex->lock(); 94 | ... 95 | $mutex->unlock(); 96 | 97 | 98 | $mutex2 = new SyncMutex("UniqueName"); 99 | 100 | if (!$mutex2->lock(3000)) 101 | { 102 | echo "Unable to lock mutex."; 103 | 104 | exit(); 105 | } 106 | 107 | ... 108 | 109 | $mutex2->unlock(); 110 | ``` 111 | 112 | Example Semaphore usage: 113 | 114 | ```php 115 | $semaphore = new SyncSemaphore("LimitedResource_2_clients", 2); 116 | 117 | if (!$semaphore->lock(3000)) 118 | { 119 | echo "Unable to lock semaphore."; 120 | 121 | exit(); 122 | } 123 | 124 | ... 125 | 126 | $semaphore->unlock(); 127 | ``` 128 | 129 | Example Event usage: 130 | 131 | ```php 132 | // In a web application: 133 | $event = new SyncEvent("GetAppReport"); 134 | $event->fire(); 135 | 136 | // In a cron job: 137 | $event = new SyncEvent("GetAppReport"); 138 | $event->wait(); 139 | ``` 140 | 141 | Example Reader-Writer usage: 142 | 143 | ```php 144 | $readwrite = new SyncReaderWriter("FileCacheLock"); 145 | $readwrite->readlock(); 146 | ... 147 | $readwrite->readunlock(); 148 | 149 | $readwrite->writelock(); 150 | ... 151 | $readwrite->writeunlock(); 152 | ``` 153 | 154 | Example Shared Memory usage: 155 | 156 | ```php 157 | // You will probably need to protect shared memory with other synchronization objects. 158 | // Shared memory goes away when the last reference to it disappears. 159 | $mem = new SyncSharedMemory("AppReportName", 1024); 160 | if ($mem->first()) 161 | { 162 | // Do first time initialization work here. 163 | } 164 | 165 | $result = $mem->write(json_encode(array("name" => "my_report.txt"))); 166 | ``` -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension sync 3 | 4 | PHP_ARG_ENABLE(sync, whether to enable synchronization object support (--enable-sync), 5 | [ --enable-sync Enable synchronization object support]) 6 | 7 | if test "$PHP_SYNC" != "no"; then 8 | dnl # Check for shm_open() support. 9 | AC_MSG_CHECKING([for shm_open in -pthread -lrt]) 10 | 11 | SAVED_LIBS="$LIBS" 12 | LIBS="$LIBS -pthread -lrt" 13 | 14 | AC_TRY_LINK([ 15 | #include 16 | #include 17 | ], [ 18 | int fp = shm_open("", O_RDWR | O_CREAT | O_EXCL, 0666); 19 | ], [ 20 | have_shm_open=yes 21 | AC_MSG_RESULT([yes]) 22 | 23 | PHP_ADD_LIBRARY(rt,,SYNC_SHARED_LIBADD) 24 | PHP_SUBST(SYNC_SHARED_LIBADD) 25 | ], [ 26 | AC_MSG_RESULT([no (attempting fallback)]) 27 | 28 | dnl # Fallback attempt to link without -lrt. 29 | AC_MSG_CHECKING([for shm_open in -pthread]) 30 | 31 | LIBS="$SAVED_LIBS -pthread" 32 | 33 | AC_TRY_LINK([ 34 | #include 35 | #include 36 | ], [ 37 | int fp = shm_open("", O_RDWR | O_CREAT | O_EXCL, 0666); 38 | ], [ 39 | have_shm_open=yes 40 | AC_MSG_RESULT([yes]) 41 | ], [ 42 | AC_MSG_ERROR([shm_open() is not available on this platform]) 43 | ]) 44 | ]) 45 | 46 | dnl # Finish defining the basic extension support. 47 | AC_DEFINE(HAVE_SYNC, 1, [Whether you have synchronization object support]) 48 | PHP_NEW_EXTENSION(sync, sync.c, $ext_shared) 49 | fi 50 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | ARG_ENABLE("sync", "enable synchronization object support", "no"); 5 | 6 | if (PHP_SYNC != "no") { 7 | EXTENSION("sync", "sync.c"); 8 | } 9 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | sync 4 | pecl.php.net 5 | Named and unnamed synchronization objects 6 | The 'sync' extension introduces synchronization objects into PHP. Named and unnamed Mutex, Semaphore, Event, Reader-Writer, and named Shared Memory objects provide OS-level synchronization mechanisms on both *NIX (POSIX shared memory and pthread shared memory synchronization required) and Windows platforms. This extension is a direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp 7 | 8 | Thomas Hruska 9 | cubic 10 | cubic@php.net 11 | yes 12 | 13 | 2023-06-28 14 | 15 | 16 | 1.1.3 17 | 1.1.0 18 | 19 | 20 | stable 21 | stable 22 | 23 | MIT License 24 | 25 | - Fixed Mac OSX support. 26 | - Fixed PHP 8.2 nullability issues. 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 | 5.3.0 59 | 60 | 61 | 1.4.0 62 | 63 | 64 | 65 | sync 66 | 67 | 68 | -------------------------------------------------------------------------------- /php_sync.h: -------------------------------------------------------------------------------- 1 | /* 2 | Direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp 3 | This source file is under the MIT license. 4 | (C) 2016 CubicleSoft. All rights reserved. 5 | */ 6 | 7 | /* $Id$ */ 8 | 9 | #ifndef PHP_SYNC_H 10 | #define PHP_SYNC_H 11 | 12 | extern zend_module_entry sync_module_entry; 13 | #define phpext_sync_ptr &sync_module_entry 14 | 15 | #define PHP_SYNC_VERSION "1.1.3" 16 | 17 | #ifdef PHP_WIN32 18 | # define PHP_SYNC_API __declspec(dllexport) 19 | #elif defined(__GNUC__) && __GNUC__ >= 4 20 | # define PHP_SYNC_API __attribute__ ((visibility("default"))) 21 | #else 22 | # define PHP_SYNC_API 23 | #endif 24 | 25 | #ifdef ZTS 26 | #include "TSRM.h" 27 | #endif 28 | 29 | #ifdef PHP_WIN32 30 | #include 31 | #else 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #ifdef __APPLE__ 43 | #include 44 | #include 45 | #ifndef SHM_NAME_MAX 46 | # define SHM_NAME_MAX 31 47 | #endif 48 | #else 49 | #ifndef SHM_NAME_MAX 50 | # define SHM_NAME_MAX 255 51 | #endif 52 | #endif 53 | 54 | #endif 55 | 56 | PHP_MINIT_FUNCTION(sync); 57 | PHP_MSHUTDOWN_FUNCTION(sync); 58 | PHP_MINFO_FUNCTION(sync); 59 | 60 | #if defined(PHP_WIN32) 61 | typedef DWORD sync_ThreadIDType; 62 | #else 63 | typedef pthread_t sync_ThreadIDType; 64 | #endif 65 | 66 | #if PHP_MAJOR_VERSION >= 7 67 | #define PHP_SYNC_PHP_5_zend_object_std 68 | #define PHP_SYNC_PHP_7_zend_object_std zend_object std; 69 | #else 70 | #define PHP_SYNC_PHP_5_zend_object_std zend_object std; 71 | #define PHP_SYNC_PHP_7_zend_object_std 72 | #endif 73 | 74 | /* Generic structures */ 75 | #if defined(PHP_WIN32) 76 | 77 | /* Nothing for Windows at the moment. */ 78 | 79 | #else 80 | 81 | /* Some platforms are broken even for unnamed semaphores (e.g. Mac OSX). */ 82 | /* This allows for implementing all semaphores directly, bypassing POSIX semaphores. */ 83 | typedef struct _sync_UnixSemaphoreWrapper { 84 | pthread_mutex_t *MxMutex; 85 | volatile uint32_t *MxCount; 86 | volatile uint32_t *MxMax; 87 | pthread_cond_t *MxCond; 88 | } sync_UnixSemaphoreWrapper; 89 | 90 | /* Implements a more efficient (and portable) event object interface than trying to use semaphores. */ 91 | typedef struct _sync_UnixEventWrapper { 92 | pthread_mutex_t *MxMutex; 93 | volatile char *MxManual; 94 | volatile char *MxSignaled; 95 | volatile uint32_t *MxWaiting; 96 | pthread_cond_t *MxCond; 97 | } sync_UnixEventWrapper; 98 | 99 | #endif 100 | 101 | 102 | /* Mutex */ 103 | typedef struct _sync_Mutex_object { 104 | PHP_SYNC_PHP_5_zend_object_std 105 | 106 | #if defined(PHP_WIN32) 107 | CRITICAL_SECTION MxWinCritSection; 108 | 109 | HANDLE MxWinMutex; 110 | #else 111 | pthread_mutex_t MxPthreadCritSection; 112 | 113 | int MxNamed; 114 | char *MxMem; 115 | sync_UnixSemaphoreWrapper MxPthreadMutex; 116 | 117 | #endif 118 | 119 | volatile sync_ThreadIDType MxOwnerID; 120 | volatile unsigned int MxCount; 121 | 122 | PHP_SYNC_PHP_7_zend_object_std 123 | } sync_Mutex_object; 124 | 125 | 126 | /* Semaphore */ 127 | typedef struct _sync_Semaphore_object { 128 | PHP_SYNC_PHP_5_zend_object_std 129 | 130 | #if defined(PHP_WIN32) 131 | HANDLE MxWinSemaphore; 132 | #else 133 | int MxNamed; 134 | char *MxMem; 135 | sync_UnixSemaphoreWrapper MxPthreadSemaphore; 136 | #endif 137 | 138 | int MxAutoUnlock; 139 | volatile unsigned int MxCount; 140 | 141 | PHP_SYNC_PHP_7_zend_object_std 142 | } sync_Semaphore_object; 143 | 144 | 145 | /* Event */ 146 | typedef struct _sync_Event_object { 147 | PHP_SYNC_PHP_5_zend_object_std 148 | 149 | #if defined(PHP_WIN32) 150 | HANDLE MxWinWaitEvent; 151 | #else 152 | int MxNamed; 153 | char *MxMem; 154 | sync_UnixEventWrapper MxPthreadEvent; 155 | #endif 156 | 157 | PHP_SYNC_PHP_7_zend_object_std 158 | } sync_Event_object; 159 | 160 | 161 | /* Reader-Writer */ 162 | typedef struct _sync_ReaderWriter_object { 163 | PHP_SYNC_PHP_5_zend_object_std 164 | 165 | #if defined(PHP_WIN32) 166 | HANDLE MxWinRSemMutex, MxWinRSemaphore, MxWinRWaitEvent, MxWinWWaitMutex; 167 | #else 168 | int MxNamed; 169 | char *MxMem; 170 | sync_UnixSemaphoreWrapper MxPthreadRCountMutex; 171 | volatile uint32_t *MxRCount; 172 | sync_UnixEventWrapper MxPthreadRWaitEvent; 173 | sync_UnixSemaphoreWrapper MxPthreadWWaitMutex; 174 | #endif 175 | 176 | int MxAutoUnlock; 177 | volatile unsigned int MxReadLocks, MxWriteLock; 178 | 179 | PHP_SYNC_PHP_7_zend_object_std 180 | } sync_ReaderWriter_object; 181 | 182 | 183 | /* Named shared memory */ 184 | typedef struct _sync_SharedMemory_object { 185 | PHP_SYNC_PHP_5_zend_object_std 186 | 187 | int MxFirst; 188 | size_t MxSize; 189 | char *MxMem; 190 | 191 | #if defined(PHP_WIN32) 192 | HANDLE MxFile; 193 | #else 194 | char *MxMemInternal; 195 | #endif 196 | 197 | PHP_SYNC_PHP_7_zend_object_std 198 | } sync_SharedMemory_object; 199 | 200 | 201 | #endif /* PHP_SYNC_H */ 202 | 203 | 204 | /* 205 | * Local variables: 206 | * tab-width: 4 207 | * c-basic-offset: 4 208 | * End: 209 | * vim600: noet sw=4 ts=4 fdm=marker 210 | * vim<600: noet sw=4 ts=4 211 | */ 212 | -------------------------------------------------------------------------------- /sync.c: -------------------------------------------------------------------------------- 1 | /* 2 | Direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp 3 | This source file is under the MIT license. 4 | (C) 2016 CubicleSoft. All rights reserved. 5 | */ 6 | 7 | /* $Id$ */ 8 | 9 | #ifdef HAVE_CONFIG_H 10 | #include "config.h" 11 | #endif 12 | 13 | #include "php.h" 14 | #include "php_ini.h" 15 | #include "zend_exceptions.h" 16 | #include "ext/standard/info.h" 17 | #if defined(PHP_WIN32) && PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 4 18 | #include "win32/php_stdint.h" 19 | #else 20 | #include 21 | #endif 22 | 23 | /* Macros. Oh joy. */ 24 | #if PHP_MAJOR_VERSION >= 7 25 | #include "zend_portability.h" 26 | #endif 27 | 28 | #include "php_sync.h" 29 | #define PORTABLE_default_zend_object_name std 30 | 31 | /* PHP_FE_END not defined in PHP < 5.3.7 */ 32 | #ifndef PHP_FE_END 33 | #define PHP_FE_END {NULL, NULL, NULL} 34 | #endif 35 | 36 | /* For PHP 8 */ 37 | #ifndef TSRMLS_D 38 | #define TSRMLS_D void 39 | #define TSRMLS_DC 40 | #define TSRMLS_C 41 | #define TSRMLS_CC 42 | #define TSRMLS_FETCH() 43 | #endif 44 | 45 | /* {{{ sync_module_entry 46 | */ 47 | zend_module_entry sync_module_entry = { 48 | #if ZEND_MODULE_API_NO >= 20010901 49 | STANDARD_MODULE_HEADER, 50 | #endif 51 | "sync", 52 | NULL, 53 | PHP_MINIT(sync), 54 | PHP_MSHUTDOWN(sync), 55 | NULL, 56 | NULL, 57 | PHP_MINFO(sync), 58 | #if ZEND_MODULE_API_NO >= 20010901 59 | PHP_SYNC_VERSION, 60 | #endif 61 | STANDARD_MODULE_PROPERTIES 62 | }; 63 | /* }}} */ 64 | 65 | #ifdef COMPILE_DL_SYNC 66 | ZEND_GET_MODULE(sync) 67 | #endif 68 | 69 | #ifndef INFINITE 70 | # define INFINITE 0xFFFFFFFF 71 | #endif 72 | 73 | 74 | /* Define some generic functions used several places. */ 75 | #if defined(PHP_WIN32) 76 | 77 | /* Windows. */ 78 | sync_ThreadIDType sync_GetCurrentThreadID() 79 | { 80 | return GetCurrentThreadId(); 81 | } 82 | 83 | uint64_t sync_GetUnixMicrosecondTime() 84 | { 85 | FILETIME TempTime; 86 | ULARGE_INTEGER TempTime2; 87 | uint64_t Result; 88 | 89 | GetSystemTimeAsFileTime(&TempTime); 90 | TempTime2.HighPart = TempTime.dwHighDateTime; 91 | TempTime2.LowPart = TempTime.dwLowDateTime; 92 | Result = TempTime2.QuadPart; 93 | 94 | Result = (Result / 10) - (uint64_t)11644473600000000ULL; 95 | 96 | return Result; 97 | } 98 | 99 | #else 100 | 101 | /* POSIX pthreads. */ 102 | sync_ThreadIDType sync_GetCurrentThreadID() 103 | { 104 | return pthread_self(); 105 | } 106 | 107 | uint64_t sync_GetUnixMicrosecondTime() 108 | { 109 | struct timeval TempTime; 110 | 111 | if (gettimeofday(&TempTime, NULL)) return 0; 112 | 113 | return (uint64_t)((uint64_t)TempTime.tv_sec * (uint64_t)1000000 + (uint64_t)TempTime.tv_usec); 114 | } 115 | 116 | /* Dear Apple: You hire plenty of developers, so please fix your OS. */ 117 | int sync_CSGX__ClockGetTimeRealtime(struct timespec *ts) 118 | { 119 | #ifdef __APPLE__ 120 | clock_serv_t cclock; 121 | mach_timespec_t mts; 122 | 123 | if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock) != KERN_SUCCESS) return -1; 124 | if (clock_get_time(cclock, &mts) != KERN_SUCCESS) return -1; 125 | if (mach_port_deallocate(mach_task_self(), cclock) != KERN_SUCCESS) return -1; 126 | 127 | ts->tv_sec = mts.tv_sec; 128 | ts->tv_nsec = mts.tv_nsec; 129 | 130 | return 0; 131 | #else 132 | return clock_gettime(CLOCK_REALTIME, ts); 133 | #endif 134 | } 135 | 136 | size_t sync_GetUnixSystemAlignmentSize() 137 | { 138 | struct { 139 | int MxInt; 140 | } x; 141 | 142 | struct { 143 | int MxInt; 144 | char MxChar; 145 | } y; 146 | 147 | return sizeof(y) - sizeof(x); 148 | } 149 | 150 | size_t sync_AlignUnixSize(size_t Size) 151 | { 152 | size_t AlignSize = sync_GetUnixSystemAlignmentSize(); 153 | 154 | if (Size % AlignSize) Size += AlignSize - (Size % AlignSize); 155 | 156 | return Size; 157 | } 158 | 159 | int sync_InitUnixNamedMem(char **ResultMem, size_t *StartPos, const char *Prefix, const char *Name, size_t Size) 160 | { 161 | int Result = -1; 162 | *ResultMem = NULL; 163 | *StartPos = (Name != NULL ? sync_AlignUnixSize(1) + sync_AlignUnixSize(sizeof(pthread_mutex_t)) + sync_AlignUnixSize(sizeof(uint32_t)) : 0); 164 | 165 | /* First byte indicates initialization status (0 = completely uninitialized, 1 = first mutex initialized, 2 = ready). */ 166 | /* Next few bytes are a shared mutex object. */ 167 | /* Size bytes follow for whatever. */ 168 | Size += *StartPos; 169 | Size = sync_AlignUnixSize(Size); 170 | 171 | if (Name == NULL) 172 | { 173 | *ResultMem = (char *)ecalloc(1, Size); 174 | 175 | Result = 0; 176 | } 177 | else 178 | { 179 | /* Deal with really small name limits with a pseudo-hash. */ 180 | char Name2[SHM_NAME_MAX], Nums[50]; 181 | size_t x, x2 = 0, y = strlen(Prefix), z = 0; 182 | 183 | memset(Name2, 0, sizeof(Name2)); 184 | 185 | for (x = 0; x < y; x++) 186 | { 187 | Name2[x2] = (char)(((unsigned int)(unsigned char)Name2[x2]) * 37 + ((unsigned int)(unsigned char)Prefix[x])); 188 | x2++; 189 | 190 | if (x2 == sizeof(Name2) - 1) 191 | { 192 | x2 = 1; 193 | z++; 194 | } 195 | } 196 | 197 | sprintf(Nums, "-%u-%u-", (unsigned int)sync_GetUnixSystemAlignmentSize(), (unsigned int)Size); 198 | 199 | y = strlen(Nums); 200 | for (x = 0; x < y; x++) 201 | { 202 | Name2[x2] = (char)(((unsigned int)(unsigned char)Name2[x2]) * 37 + ((unsigned int)(unsigned char)Nums[x])); 203 | x2++; 204 | 205 | if (x2 == sizeof(Name2) - 1) 206 | { 207 | x2 = 1; 208 | z++; 209 | } 210 | } 211 | 212 | y = strlen(Name); 213 | for (x = 0; x < y; x++) 214 | { 215 | Name2[x2] = (char)(((unsigned int)(unsigned char)Name2[x2]) * 37 + ((unsigned int)(unsigned char)Name[x])); 216 | x2++; 217 | 218 | if (x2 == sizeof(Name2) - 1) 219 | { 220 | x2 = 1; 221 | z++; 222 | } 223 | } 224 | 225 | /* Normalize the alphabet if it looped. */ 226 | if (z) 227 | { 228 | unsigned char TempChr; 229 | y = (z > 1 ? sizeof(Name2) - 1 : x2); 230 | for (x = 1; x < y; x++) 231 | { 232 | TempChr = ((unsigned char)Name2[x]) & 0x3F; 233 | 234 | if (TempChr < 10) TempChr += '0'; 235 | else if (TempChr < 36) TempChr = TempChr - 10 + 'A'; 236 | else if (TempChr < 62) TempChr = TempChr - 36 + 'a'; 237 | else if (TempChr == 62) TempChr = '_'; 238 | else TempChr = '-'; 239 | 240 | Name2[x] = (char)TempChr; 241 | } 242 | } 243 | 244 | for (x = 1; x < sizeof(Name2) && Name2[x]; x++) 245 | { 246 | if (Name2[x] == '\\' || Name2[x] == '/') Name2[x] = '_'; 247 | } 248 | 249 | pthread_mutex_t *MutexPtr; 250 | uint32_t *RefCountPtr; 251 | 252 | /* Attempt to create the named shared memory object. */ 253 | mode_t PrevMask = umask(0); 254 | int fp = shm_open(Name2, O_RDWR | O_CREAT | O_EXCL, 0666); 255 | if (fp > -1) 256 | { 257 | /* Ignore platform errors (for now). */ 258 | while (ftruncate(fp, Size) < 0 && errno == EINTR) 259 | { 260 | } 261 | 262 | *ResultMem = (char *)mmap(NULL, Size, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0); 263 | if ((*ResultMem) == MAP_FAILED) *ResultMem = NULL; 264 | else 265 | { 266 | pthread_mutexattr_t MutexAttr; 267 | 268 | pthread_mutexattr_init(&MutexAttr); 269 | pthread_mutexattr_setpshared(&MutexAttr, PTHREAD_PROCESS_SHARED); 270 | 271 | MutexPtr = (pthread_mutex_t *)((*ResultMem) + sync_AlignUnixSize(1)); 272 | RefCountPtr = (uint32_t *)((*ResultMem) + sync_AlignUnixSize(1) + sync_AlignUnixSize(sizeof(pthread_mutex_t))); 273 | 274 | pthread_mutex_init(MutexPtr, &MutexAttr); 275 | pthread_mutex_lock(MutexPtr); 276 | 277 | (*ResultMem)[0] = '\x01'; 278 | RefCountPtr[0] = 1; 279 | 280 | Result = 0; 281 | } 282 | 283 | close(fp); 284 | } 285 | else 286 | { 287 | /* Attempt to open the named shared memory object. */ 288 | fp = shm_open(Name2, O_RDWR, 0666); 289 | if (fp > -1) 290 | { 291 | /* Ignore platform errors (for now). */ 292 | while (ftruncate(fp, Size) < 0 && errno == EINTR) 293 | { 294 | } 295 | 296 | *ResultMem = (char *)mmap(NULL, Size, PROT_READ | PROT_WRITE, MAP_SHARED, fp, 0); 297 | if (*ResultMem == MAP_FAILED) ResultMem = NULL; 298 | else 299 | { 300 | /* Wait until the space is fully initialized. */ 301 | if ((*ResultMem)[0] == '\x00') 302 | { 303 | while ((*ResultMem)[0] == '\x00') 304 | { 305 | usleep(2000); 306 | } 307 | } 308 | 309 | char *MemPtr = (*ResultMem) + sync_AlignUnixSize(1); 310 | MutexPtr = (pthread_mutex_t *)(MemPtr); 311 | MemPtr += sync_AlignUnixSize(sizeof(pthread_mutex_t)); 312 | 313 | RefCountPtr = (uint32_t *)(MemPtr); 314 | MemPtr += sync_AlignUnixSize(sizeof(uint32_t)); 315 | 316 | pthread_mutex_lock(MutexPtr); 317 | 318 | if (RefCountPtr[0]) Result = 1; 319 | else 320 | { 321 | /* If this is the first reference, reset the RAM to 0's for platform consistency to force a rebuild of the object. */ 322 | memset(MemPtr, 0, Size); 323 | 324 | Result = 0; 325 | } 326 | 327 | RefCountPtr[0]++; 328 | 329 | pthread_mutex_unlock(MutexPtr); 330 | } 331 | 332 | close(fp); 333 | } 334 | } 335 | 336 | umask(PrevMask); 337 | } 338 | 339 | return Result; 340 | } 341 | 342 | void sync_UnixNamedMemReady(char *MemPtr) 343 | { 344 | pthread_mutex_unlock((pthread_mutex_t *)(MemPtr + sync_AlignUnixSize(1))); 345 | } 346 | 347 | void sync_UnmapUnixNamedMem(char *MemPtr, size_t Size) 348 | { 349 | pthread_mutex_t *MutexPtr; 350 | uint32_t *RefCountPtr; 351 | 352 | char *MemPtr2 = MemPtr + sync_AlignUnixSize(1); 353 | MutexPtr = (pthread_mutex_t *)(MemPtr2); 354 | MemPtr2 += sync_AlignUnixSize(sizeof(pthread_mutex_t)); 355 | 356 | RefCountPtr = (uint32_t *)(MemPtr2); 357 | 358 | pthread_mutex_lock(MutexPtr); 359 | if (RefCountPtr[0]) RefCountPtr[0]--; 360 | pthread_mutex_unlock(MutexPtr); 361 | 362 | munmap(MemPtr, sync_AlignUnixSize(1) + sync_AlignUnixSize(sizeof(pthread_mutex_t)) + sync_AlignUnixSize(sizeof(uint32_t)) + Size); 363 | } 364 | 365 | /* Basic *NIX Semaphore functions. */ 366 | size_t sync_GetUnixSemaphoreSize() 367 | { 368 | return sync_AlignUnixSize(sizeof(pthread_mutex_t)) + sync_AlignUnixSize(sizeof(uint32_t)) + sync_AlignUnixSize(sizeof(uint32_t)) + sync_AlignUnixSize(sizeof(pthread_cond_t)); 369 | } 370 | 371 | void sync_GetUnixSemaphore(sync_UnixSemaphoreWrapper *Result, char *Mem) 372 | { 373 | Result->MxMutex = (pthread_mutex_t *)(Mem); 374 | Mem += sync_AlignUnixSize(sizeof(pthread_mutex_t)); 375 | 376 | Result->MxCount = (uint32_t *)(Mem); 377 | Mem += sync_AlignUnixSize(sizeof(uint32_t)); 378 | 379 | Result->MxMax = (uint32_t *)(Mem); 380 | Mem += sync_AlignUnixSize(sizeof(uint32_t)); 381 | 382 | Result->MxCond = (pthread_cond_t *)(Mem); 383 | } 384 | 385 | void sync_InitUnixSemaphore(sync_UnixSemaphoreWrapper *UnixSemaphore, int Shared, uint32_t Start, uint32_t Max) 386 | { 387 | pthread_mutexattr_t MutexAttr; 388 | pthread_condattr_t CondAttr; 389 | 390 | pthread_mutexattr_init(&MutexAttr); 391 | pthread_condattr_init(&CondAttr); 392 | 393 | if (Shared) 394 | { 395 | pthread_mutexattr_setpshared(&MutexAttr, PTHREAD_PROCESS_SHARED); 396 | pthread_condattr_setpshared(&CondAttr, PTHREAD_PROCESS_SHARED); 397 | } 398 | 399 | pthread_mutex_init(UnixSemaphore->MxMutex, &MutexAttr); 400 | if (Start > Max) Start = Max; 401 | UnixSemaphore->MxCount[0] = Start; 402 | UnixSemaphore->MxMax[0] = Max; 403 | pthread_cond_init(UnixSemaphore->MxCond, &CondAttr); 404 | 405 | pthread_condattr_destroy(&CondAttr); 406 | pthread_mutexattr_destroy(&MutexAttr); 407 | } 408 | 409 | int sync_WaitForUnixSemaphore(sync_UnixSemaphoreWrapper *UnixSemaphore, uint32_t Wait) 410 | { 411 | if (Wait == 0) 412 | { 413 | /* Avoid the scenario of deadlock on the semaphore itself for 0 wait. */ 414 | if (pthread_mutex_trylock(UnixSemaphore->MxMutex) != 0) return 0; 415 | } 416 | else 417 | { 418 | if (pthread_mutex_lock(UnixSemaphore->MxMutex) != 0) return 0; 419 | } 420 | 421 | int Result = 0; 422 | 423 | if (UnixSemaphore->MxCount[0]) 424 | { 425 | UnixSemaphore->MxCount[0]--; 426 | 427 | Result = 1; 428 | } 429 | else if (Wait == INFINITE) 430 | { 431 | int Result2; 432 | do 433 | { 434 | Result2 = pthread_cond_wait(UnixSemaphore->MxCond, UnixSemaphore->MxMutex); 435 | if (Result2 != 0) break; 436 | } while (!UnixSemaphore->MxCount[0]); 437 | 438 | if (Result2 == 0) 439 | { 440 | UnixSemaphore->MxCount[0]--; 441 | 442 | Result = 1; 443 | } 444 | } 445 | else if (Wait == 0) 446 | { 447 | /* Failed to obtain lock. Nothing to do. */ 448 | } 449 | else 450 | { 451 | struct timespec TempTime; 452 | 453 | if (sync_CSGX__ClockGetTimeRealtime(&TempTime) == -1) return 0; 454 | TempTime.tv_sec += Wait / 1000; 455 | TempTime.tv_nsec += (Wait % 1000) * 1000000; 456 | TempTime.tv_sec += TempTime.tv_nsec / 1000000000; 457 | TempTime.tv_nsec = TempTime.tv_nsec % 1000000000; 458 | 459 | int Result2; 460 | do 461 | { 462 | /* Some platforms have pthread_cond_timedwait() but not pthread_mutex_timedlock() or sem_timedwait() (e.g. Mac OSX). */ 463 | Result2 = pthread_cond_timedwait(UnixSemaphore->MxCond, UnixSemaphore->MxMutex, &TempTime); 464 | if (Result2 != 0) break; 465 | } while (!UnixSemaphore->MxCount[0]); 466 | 467 | if (Result2 == 0) 468 | { 469 | UnixSemaphore->MxCount[0]--; 470 | 471 | Result = 1; 472 | } 473 | } 474 | 475 | pthread_mutex_unlock(UnixSemaphore->MxMutex); 476 | 477 | return Result; 478 | } 479 | 480 | int sync_ReleaseUnixSemaphore(sync_UnixSemaphoreWrapper *UnixSemaphore, uint32_t *PrevVal) 481 | { 482 | if (pthread_mutex_lock(UnixSemaphore->MxMutex) != 0) return 0; 483 | 484 | if (PrevVal != NULL) *PrevVal = UnixSemaphore->MxCount[0]; 485 | UnixSemaphore->MxCount[0]++; 486 | if (UnixSemaphore->MxCount[0] > UnixSemaphore->MxMax[0]) UnixSemaphore->MxCount[0] = UnixSemaphore->MxMax[0]; 487 | 488 | /* Let a waiting thread have at it. */ 489 | pthread_cond_signal(UnixSemaphore->MxCond); 490 | 491 | pthread_mutex_unlock(UnixSemaphore->MxMutex); 492 | 493 | return 1; 494 | } 495 | 496 | void sync_FreeUnixSemaphore(sync_UnixSemaphoreWrapper *UnixSemaphore) 497 | { 498 | pthread_mutex_destroy(UnixSemaphore->MxMutex); 499 | pthread_cond_destroy(UnixSemaphore->MxCond); 500 | } 501 | 502 | /* Basic *NIX Event functions. */ 503 | size_t sync_GetUnixEventSize() 504 | { 505 | return sync_AlignUnixSize(sizeof(pthread_mutex_t)) + sync_AlignUnixSize(2) + sync_AlignUnixSize(sizeof(uint32_t)) + sync_AlignUnixSize(sizeof(pthread_cond_t)); 506 | } 507 | 508 | void sync_GetUnixEvent(sync_UnixEventWrapper *Result, char *Mem) 509 | { 510 | Result->MxMutex = (pthread_mutex_t *)(Mem); 511 | Mem += sync_AlignUnixSize(sizeof(pthread_mutex_t)); 512 | 513 | Result->MxManual = Mem; 514 | Result->MxSignaled = Mem + 1; 515 | Mem += sync_AlignUnixSize(2); 516 | 517 | Result->MxWaiting = (uint32_t *)(Mem); 518 | Mem += sync_AlignUnixSize(sizeof(uint32_t)); 519 | 520 | Result->MxCond = (pthread_cond_t *)(Mem); 521 | } 522 | 523 | void sync_InitUnixEvent(sync_UnixEventWrapper *UnixEvent, int Shared, int Manual, int Signaled) 524 | { 525 | pthread_mutexattr_t MutexAttr; 526 | pthread_condattr_t CondAttr; 527 | 528 | pthread_mutexattr_init(&MutexAttr); 529 | pthread_condattr_init(&CondAttr); 530 | 531 | if (Shared) 532 | { 533 | pthread_mutexattr_setpshared(&MutexAttr, PTHREAD_PROCESS_SHARED); 534 | pthread_condattr_setpshared(&CondAttr, PTHREAD_PROCESS_SHARED); 535 | } 536 | 537 | pthread_mutex_init(UnixEvent->MxMutex, &MutexAttr); 538 | UnixEvent->MxManual[0] = (Manual ? '\x01' : '\x00'); 539 | UnixEvent->MxSignaled[0] = (Signaled ? '\x01' : '\x00'); 540 | UnixEvent->MxWaiting[0] = 0; 541 | pthread_cond_init(UnixEvent->MxCond, &CondAttr); 542 | 543 | pthread_condattr_destroy(&CondAttr); 544 | pthread_mutexattr_destroy(&MutexAttr); 545 | } 546 | 547 | int sync_WaitForUnixEvent(sync_UnixEventWrapper *UnixEvent, uint32_t Wait) 548 | { 549 | if (Wait == 0) 550 | { 551 | /* Avoid the scenario of deadlock on the semaphore itself for 0 wait. */ 552 | if (pthread_mutex_trylock(UnixEvent->MxMutex) != 0) return 0; 553 | } 554 | else 555 | { 556 | if (pthread_mutex_lock(UnixEvent->MxMutex) != 0) return 0; 557 | } 558 | 559 | int Result = 0; 560 | 561 | /* Avoid a potential starvation issue by only allowing signaled manual events OR if there are no other waiting threads. */ 562 | if (UnixEvent->MxSignaled[0] != '\x00' && (UnixEvent->MxManual[0] != '\x00' || !UnixEvent->MxWaiting[0])) 563 | { 564 | /* Reset auto events. */ 565 | if (UnixEvent->MxManual[0] == '\x00') UnixEvent->MxSignaled[0] = '\x00'; 566 | 567 | Result = 1; 568 | } 569 | else if (Wait == INFINITE) 570 | { 571 | UnixEvent->MxWaiting[0]++; 572 | 573 | int Result2; 574 | do 575 | { 576 | Result2 = pthread_cond_wait(UnixEvent->MxCond, UnixEvent->MxMutex); 577 | if (Result2 != 0) break; 578 | } while (UnixEvent->MxSignaled[0] == '\x00'); 579 | 580 | UnixEvent->MxWaiting[0]--; 581 | 582 | if (Result2 == 0) 583 | { 584 | /* Reset auto events. */ 585 | if (UnixEvent->MxManual[0] == '\x00') UnixEvent->MxSignaled[0] = '\x00'; 586 | 587 | Result = 1; 588 | } 589 | } 590 | else if (Wait == 0) 591 | { 592 | /* Failed to obtain lock. Nothing to do. */ 593 | } 594 | else 595 | { 596 | struct timespec TempTime; 597 | 598 | if (sync_CSGX__ClockGetTimeRealtime(&TempTime) == -1) 599 | { 600 | pthread_mutex_unlock(UnixEvent->MxMutex); 601 | 602 | return 0; 603 | } 604 | 605 | TempTime.tv_sec += Wait / 1000; 606 | TempTime.tv_nsec += (Wait % 1000) * 1000000; 607 | TempTime.tv_sec += TempTime.tv_nsec / 1000000000; 608 | TempTime.tv_nsec = TempTime.tv_nsec % 1000000000; 609 | 610 | UnixEvent->MxWaiting[0]++; 611 | 612 | int Result2; 613 | do 614 | { 615 | /* Some platforms have pthread_cond_timedwait() but not pthread_mutex_timedlock() or sem_timedwait() (e.g. Mac OSX). */ 616 | Result2 = pthread_cond_timedwait(UnixEvent->MxCond, UnixEvent->MxMutex, &TempTime); 617 | if (Result2 != 0) break; 618 | } while (UnixEvent->MxSignaled[0] == '\x00'); 619 | 620 | UnixEvent->MxWaiting[0]--; 621 | 622 | if (Result2 == 0) 623 | { 624 | /* Reset auto events. */ 625 | if (UnixEvent->MxManual[0] == '\x00') UnixEvent->MxSignaled[0] = '\x00'; 626 | 627 | Result = 1; 628 | } 629 | } 630 | 631 | pthread_mutex_unlock(UnixEvent->MxMutex); 632 | 633 | return Result; 634 | } 635 | 636 | int sync_FireUnixEvent(sync_UnixEventWrapper *UnixEvent) 637 | { 638 | if (pthread_mutex_lock(UnixEvent->MxMutex) != 0) return 0; 639 | 640 | UnixEvent->MxSignaled[0] = '\x01'; 641 | 642 | /* Let all waiting threads through for manual events, otherwise just one waiting thread (if any). */ 643 | if (UnixEvent->MxManual[0] != '\x00') pthread_cond_broadcast(UnixEvent->MxCond); 644 | else pthread_cond_signal(UnixEvent->MxCond); 645 | 646 | pthread_mutex_unlock(UnixEvent->MxMutex); 647 | 648 | return 1; 649 | } 650 | 651 | /* Only call for manual events. */ 652 | int sync_ResetUnixEvent(sync_UnixEventWrapper *UnixEvent) 653 | { 654 | if (UnixEvent->MxManual[0] == '\x00') return 0; 655 | if (pthread_mutex_lock(UnixEvent->MxMutex) != 0) return 0; 656 | 657 | UnixEvent->MxSignaled[0] = '\x00'; 658 | 659 | pthread_mutex_unlock(UnixEvent->MxMutex); 660 | 661 | return 1; 662 | } 663 | 664 | void sync_FreeUnixEvent(sync_UnixEventWrapper *UnixEvent) 665 | { 666 | pthread_mutex_destroy(UnixEvent->MxMutex); 667 | pthread_cond_destroy(UnixEvent->MxCond); 668 | } 669 | 670 | #endif 671 | 672 | 673 | /* {{{ PHP 5 and 7 crossover compatibility defines and functions */ 674 | #if PHP_MAJOR_VERSION >= 7 675 | 676 | #define PORTABLE_new_zend_object_func(funcname) zend_object *funcname(zend_class_entry *ce) 677 | #define PORTABLE_new_zend_object_return_var 678 | #define PORTABLE_new_zend_object_return_var_ref NULL 679 | #define PORTABLE_allocate_zend_object(size, ce) ecalloc(1, (size) + zend_object_properties_size(ce)); 680 | #define PORTABLE_new_zend_object_return(std) return (std) 681 | 682 | void PORTABLE_InitZendObject(void *obj, zend_object *std, void *unused1, void *FreeFunc, zend_object_handlers *Handlers, zend_class_entry *ce TSRMLS_DC) 683 | { 684 | /* Initialize Zend. */ 685 | zend_object_std_init(std, ce TSRMLS_CC); 686 | object_properties_init(std, ce); 687 | 688 | /* Initialize destructor callback. */ 689 | std->handlers = Handlers; 690 | } 691 | 692 | typedef zend_long PORTABLE_ZPP_ARG_long; 693 | typedef size_t PORTABLE_ZPP_ARG_size; 694 | typedef zval * PORTABLE_ZPP_ARG_zval_ref; 695 | #define PORTABLE_ZPP_ARG_zval_ref_deref(var) var 696 | 697 | static inline void *PHP_7_zend_object_to_object(zend_object *std) 698 | { 699 | return (void *)((char *)std - std->handlers->offset); 700 | } 701 | 702 | #define PORTABLE_zend_object_store_get_object() PHP_7_zend_object_to_object(Z_OBJ_P(getThis())) 703 | 704 | #define PORTABLE_free_zend_object_func(funcname) void funcname(zend_object *object) 705 | #define PORTABLE_free_zend_object_get_object(object) PHP_7_zend_object_to_object(object) 706 | #define PORTABLE_free_zend_object_free_object(obj) zend_object_std_dtor(&obj->std); 707 | 708 | #define PORTABLE_RETURN_STRINGL(str, len) RETURN_STRINGL(str, len) 709 | 710 | #else 711 | 712 | #define PORTABLE_new_zend_object_func(funcname) zend_object_value funcname(zend_class_entry *ce TSRMLS_DC) 713 | #define PORTABLE_new_zend_object_return_var zend_object_value retval 714 | #define PORTABLE_new_zend_object_return_var_ref &retval 715 | #define PORTABLE_new_zend_object_return(std) return retval 716 | #define PORTABLE_allocate_zend_object(size, ce) ecalloc(1, (size)); 717 | 718 | void PORTABLE_InitZendObject(void *obj, zend_object *std, zend_object_value *retval, zend_objects_free_object_storage_t FreeFunc, zend_object_handlers *Handlers, zend_class_entry *ce TSRMLS_DC) 719 | { 720 | #if PHP_VERSION_ID < 50399 721 | zval *tmp; 722 | #endif 723 | 724 | /* Initialize Zend. */ 725 | zend_object_std_init(std, ce TSRMLS_CC); 726 | #if PHP_VERSION_ID < 50399 727 | zend_hash_copy(std->properties, &ce->default_properties, (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *)); 728 | #else 729 | object_properties_init(std, ce); 730 | #endif 731 | 732 | /* Initialize destructor callback. */ 733 | retval->handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, FreeFunc, NULL TSRMLS_CC); 734 | retval->handlers = Handlers; 735 | } 736 | 737 | typedef long PORTABLE_ZPP_ARG_long; 738 | typedef int PORTABLE_ZPP_ARG_size; 739 | typedef zval ** PORTABLE_ZPP_ARG_zval_ref; 740 | #define PORTABLE_ZPP_ARG_zval_ref_deref(var) *var 741 | 742 | #define PORTABLE_zend_object_store_get_object() zend_object_store_get_object(getThis() TSRMLS_CC) 743 | 744 | #define PORTABLE_free_zend_object_func(funcname) void funcname(void *object TSRMLS_DC) 745 | #define PORTABLE_free_zend_object_get_object(object) object; 746 | #define PORTABLE_free_zend_object_free_object(obj) zend_object_std_dtor(&obj->std TSRMLS_CC); efree(obj); 747 | 748 | #define PORTABLE_RETURN_STRINGL(str, len) RETURN_STRINGL(str, len, 1) 749 | 750 | #endif 751 | /* }}} */ 752 | 753 | 754 | /* Mutex */ 755 | PHP_SYNC_API zend_class_entry *sync_Mutex_ce; 756 | static zend_object_handlers sync_Mutex_object_handlers; 757 | 758 | PORTABLE_free_zend_object_func(sync_Mutex_free_object); 759 | 760 | /* {{{ Initialize internal Mutex structure. */ 761 | PORTABLE_new_zend_object_func(sync_Mutex_create_object) 762 | { 763 | PORTABLE_new_zend_object_return_var; 764 | sync_Mutex_object *obj; 765 | 766 | /* Create the object. */ 767 | obj = (sync_Mutex_object *)PORTABLE_allocate_zend_object(sizeof(sync_Mutex_object), ce); 768 | 769 | PORTABLE_InitZendObject(obj, &obj->std, PORTABLE_new_zend_object_return_var_ref, sync_Mutex_free_object, &sync_Mutex_object_handlers, ce TSRMLS_CC); 770 | 771 | /* Initialize Mutex information. */ 772 | #if defined(PHP_WIN32) 773 | obj->MxWinMutex = NULL; 774 | InitializeCriticalSection(&obj->MxWinCritSection); 775 | #else 776 | obj->MxNamed = 0; 777 | obj->MxMem = NULL; 778 | pthread_mutex_init(&obj->MxPthreadCritSection, NULL); 779 | #endif 780 | obj->MxOwnerID = 0; 781 | obj->MxCount = 0; 782 | 783 | PORTABLE_new_zend_object_return(&obj->std); 784 | } 785 | /* }}} */ 786 | 787 | /* {{{ Unlocks a mutex. */ 788 | int sync_Mutex_unlock_internal(sync_Mutex_object *obj, int all) 789 | { 790 | #if defined(PHP_WIN32) 791 | 792 | EnterCriticalSection(&obj->MxWinCritSection); 793 | 794 | /* Make sure the mutex exists and make sure it is owned by the calling thread. */ 795 | if (obj->MxWinMutex == NULL || obj->MxOwnerID != sync_GetCurrentThreadID()) 796 | { 797 | LeaveCriticalSection(&obj->MxWinCritSection); 798 | 799 | return 0; 800 | } 801 | 802 | if (all) obj->MxCount = 1; 803 | 804 | obj->MxCount--; 805 | if (!obj->MxCount) 806 | { 807 | obj->MxOwnerID = 0; 808 | 809 | /* Release the mutex. */ 810 | ReleaseMutex(obj->MxWinMutex); 811 | } 812 | 813 | LeaveCriticalSection(&obj->MxWinCritSection); 814 | 815 | #else 816 | 817 | if (pthread_mutex_lock(&obj->MxPthreadCritSection) != 0) return 0; 818 | 819 | /* Make sure the mutex exists and make sure it is owned by the calling thread. */ 820 | if (obj->MxMem == NULL || obj->MxOwnerID != sync_GetCurrentThreadID()) 821 | { 822 | pthread_mutex_unlock(&obj->MxPthreadCritSection); 823 | 824 | return 0; 825 | } 826 | 827 | if (all) obj->MxCount = 1; 828 | 829 | obj->MxCount--; 830 | if (!obj->MxCount) 831 | { 832 | obj->MxOwnerID = 0; 833 | 834 | /* Release the mutex. */ 835 | sync_ReleaseUnixSemaphore(&obj->MxPthreadMutex, NULL); 836 | } 837 | 838 | pthread_mutex_unlock(&obj->MxPthreadCritSection); 839 | 840 | #endif 841 | 842 | return 1; 843 | } 844 | /* }}} */ 845 | 846 | /* {{{ Free internal Mutex structure. */ 847 | PORTABLE_free_zend_object_func(sync_Mutex_free_object) 848 | { 849 | sync_Mutex_object *obj = (sync_Mutex_object *)PORTABLE_free_zend_object_get_object(object); 850 | 851 | sync_Mutex_unlock_internal(obj, 1); 852 | 853 | #if defined(PHP_WIN32) 854 | if (obj->MxWinMutex != NULL) CloseHandle(obj->MxWinMutex); 855 | DeleteCriticalSection(&obj->MxWinCritSection); 856 | #else 857 | if (obj->MxMem != NULL) 858 | { 859 | if (obj->MxNamed) sync_UnmapUnixNamedMem(obj->MxMem, sync_GetUnixSemaphoreSize()); 860 | else 861 | { 862 | sync_FreeUnixSemaphore(&obj->MxPthreadMutex); 863 | 864 | efree(obj->MxMem); 865 | } 866 | } 867 | 868 | pthread_mutex_destroy(&obj->MxPthreadCritSection); 869 | #endif 870 | 871 | PORTABLE_free_zend_object_free_object(obj); 872 | } 873 | /* }}} */ 874 | 875 | /* {{{ proto void Sync_Mutex::__construct([string $name = null]) 876 | Constructs a named or unnamed mutex object. */ 877 | PHP_METHOD(sync_Mutex, __construct) 878 | { 879 | char *name = NULL; 880 | PORTABLE_ZPP_ARG_size name_len; 881 | sync_Mutex_object *obj; 882 | #if defined(PHP_WIN32) 883 | SECURITY_ATTRIBUTES SecAttr; 884 | #else 885 | size_t Pos, TempSize; 886 | #endif 887 | 888 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &name_len) == FAILURE) return; 889 | 890 | obj = (sync_Mutex_object *)PORTABLE_zend_object_store_get_object(); 891 | 892 | if (name_len < 1) name = NULL; 893 | 894 | #if defined(PHP_WIN32) 895 | 896 | SecAttr.nLength = sizeof(SecAttr); 897 | SecAttr.lpSecurityDescriptor = NULL; 898 | SecAttr.bInheritHandle = TRUE; 899 | 900 | obj->MxWinMutex = CreateMutexA(&SecAttr, FALSE, name); 901 | if (obj->MxWinMutex == NULL) 902 | { 903 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Mutex could not be created", 0 TSRMLS_CC); 904 | return; 905 | } 906 | 907 | #else 908 | 909 | TempSize = sync_GetUnixSemaphoreSize(); 910 | obj->MxNamed = (name != NULL ? 1 : 0); 911 | int Result = sync_InitUnixNamedMem(&obj->MxMem, &Pos, "/Sync_Mutex", name, TempSize); 912 | 913 | if (Result < 0) 914 | { 915 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Mutex could not be created", 0 TSRMLS_CC); 916 | 917 | return; 918 | } 919 | 920 | sync_GetUnixSemaphore(&obj->MxPthreadMutex, obj->MxMem + Pos); 921 | 922 | /* Handle the first time this mutex has been opened. */ 923 | if (Result == 0) 924 | { 925 | sync_InitUnixSemaphore(&obj->MxPthreadMutex, obj->MxNamed, 1, 1); 926 | 927 | if (obj->MxNamed) sync_UnixNamedMemReady(obj->MxMem); 928 | } 929 | 930 | #endif 931 | } 932 | /* }}} */ 933 | 934 | /* {{{ proto bool Sync_Mutex::lock([int $wait = -1]) 935 | Locks a mutex object. */ 936 | PHP_METHOD(sync_Mutex, lock) 937 | { 938 | PORTABLE_ZPP_ARG_long wait = -1; 939 | sync_Mutex_object *obj; 940 | #if defined(PHP_WIN32) 941 | DWORD Result; 942 | #else 943 | #endif 944 | 945 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &wait) == FAILURE) return; 946 | 947 | obj = (sync_Mutex_object *)PORTABLE_zend_object_store_get_object(); 948 | 949 | #if defined(PHP_WIN32) 950 | 951 | EnterCriticalSection(&obj->MxWinCritSection); 952 | 953 | /* Check to see if this is already owned by the calling thread. */ 954 | if (obj->MxOwnerID == sync_GetCurrentThreadID()) 955 | { 956 | obj->MxCount++; 957 | LeaveCriticalSection(&obj->MxWinCritSection); 958 | 959 | RETURN_TRUE; 960 | } 961 | 962 | LeaveCriticalSection(&obj->MxWinCritSection); 963 | 964 | /* Acquire the mutex. */ 965 | Result = WaitForSingleObject(obj->MxWinMutex, (DWORD)(wait > -1 ? wait : INFINITE)); 966 | if (Result != WAIT_OBJECT_0) RETURN_FALSE; 967 | 968 | EnterCriticalSection(&obj->MxWinCritSection); 969 | obj->MxOwnerID = sync_GetCurrentThreadID(); 970 | obj->MxCount = 1; 971 | LeaveCriticalSection(&obj->MxWinCritSection); 972 | 973 | #else 974 | 975 | if (pthread_mutex_lock(&obj->MxPthreadCritSection) != 0) 976 | { 977 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Unable to acquire mutex critical section", 0 TSRMLS_CC); 978 | 979 | RETURN_FALSE; 980 | } 981 | 982 | /* Check to see if this mutex is already owned by the calling thread. */ 983 | if (obj->MxOwnerID == sync_GetCurrentThreadID()) 984 | { 985 | obj->MxCount++; 986 | pthread_mutex_unlock(&obj->MxPthreadCritSection); 987 | 988 | RETURN_TRUE; 989 | } 990 | 991 | pthread_mutex_unlock(&obj->MxPthreadCritSection); 992 | 993 | if (!sync_WaitForUnixSemaphore(&obj->MxPthreadMutex, (uint32_t)(wait > -1 ? wait : INFINITE))) RETURN_FALSE; 994 | 995 | pthread_mutex_lock(&obj->MxPthreadCritSection); 996 | obj->MxOwnerID = sync_GetCurrentThreadID(); 997 | obj->MxCount = 1; 998 | pthread_mutex_unlock(&obj->MxPthreadCritSection); 999 | 1000 | #endif 1001 | 1002 | RETURN_TRUE; 1003 | } 1004 | /* }}} */ 1005 | 1006 | /* {{{ proto bool Sync_Mutex::unlock([bool $all = false]) 1007 | Unlocks a mutex object. */ 1008 | PHP_METHOD(sync_Mutex, unlock) 1009 | { 1010 | PORTABLE_ZPP_ARG_long all = 0; 1011 | sync_Mutex_object *obj; 1012 | 1013 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &all) == FAILURE) return; 1014 | 1015 | obj = (sync_Mutex_object *)PORTABLE_zend_object_store_get_object(); 1016 | 1017 | if (!sync_Mutex_unlock_internal(obj, all)) RETURN_FALSE; 1018 | 1019 | RETURN_TRUE; 1020 | } 1021 | /* }}} */ 1022 | 1023 | 1024 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_mutex___construct, 0, 0, 0) 1025 | ZEND_ARG_INFO(0, name) 1026 | ZEND_END_ARG_INFO() 1027 | 1028 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_mutex_lock, 0, 0, 0) 1029 | ZEND_ARG_INFO(0, wait) 1030 | ZEND_END_ARG_INFO() 1031 | 1032 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_mutex_unlock, 0, 0, 0) 1033 | ZEND_ARG_INFO(0, all) 1034 | ZEND_END_ARG_INFO() 1035 | 1036 | static const zend_function_entry sync_Mutex_methods[] = { 1037 | PHP_ME(sync_Mutex, __construct, arginfo_sync_mutex___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 1038 | PHP_ME(sync_Mutex, lock, arginfo_sync_mutex_lock, ZEND_ACC_PUBLIC) 1039 | PHP_ME(sync_Mutex, unlock, arginfo_sync_mutex_unlock, ZEND_ACC_PUBLIC) 1040 | PHP_FE_END 1041 | }; 1042 | 1043 | 1044 | 1045 | /* Semaphore */ 1046 | PHP_SYNC_API zend_class_entry *sync_Semaphore_ce; 1047 | static zend_object_handlers sync_Semaphore_object_handlers; 1048 | 1049 | PORTABLE_free_zend_object_func(sync_Semaphore_free_object); 1050 | 1051 | /* {{{ Initialize internal Semaphore structure. */ 1052 | PORTABLE_new_zend_object_func(sync_Semaphore_create_object) 1053 | { 1054 | PORTABLE_new_zend_object_return_var; 1055 | sync_Semaphore_object *obj; 1056 | 1057 | /* Create the object. */ 1058 | obj = (sync_Semaphore_object *)PORTABLE_allocate_zend_object(sizeof(sync_Semaphore_object), ce); 1059 | 1060 | PORTABLE_InitZendObject(obj, &obj->std, PORTABLE_new_zend_object_return_var_ref, sync_Semaphore_free_object, &sync_Semaphore_object_handlers, ce TSRMLS_CC); 1061 | 1062 | /* Initialize Semaphore information. */ 1063 | #if defined(PHP_WIN32) 1064 | obj->MxWinSemaphore = NULL; 1065 | #else 1066 | obj->MxNamed = 0; 1067 | obj->MxMem = NULL; 1068 | #endif 1069 | obj->MxAutoUnlock = 0; 1070 | obj->MxCount = 0; 1071 | 1072 | PORTABLE_new_zend_object_return(&obj->std); 1073 | } 1074 | /* }}} */ 1075 | 1076 | /* {{{ Free internal Semaphore structure. */ 1077 | PORTABLE_free_zend_object_func(sync_Semaphore_free_object) 1078 | { 1079 | sync_Semaphore_object *obj = (sync_Semaphore_object *)PORTABLE_free_zend_object_get_object(object); 1080 | 1081 | if (obj->MxAutoUnlock) 1082 | { 1083 | while (obj->MxCount) 1084 | { 1085 | #if defined(PHP_WIN32) 1086 | ReleaseSemaphore(obj->MxWinSemaphore, 1, NULL); 1087 | #else 1088 | sync_ReleaseUnixSemaphore(&obj->MxPthreadSemaphore, NULL); 1089 | #endif 1090 | 1091 | obj->MxCount--; 1092 | } 1093 | } 1094 | 1095 | #if defined(PHP_WIN32) 1096 | if (obj->MxWinSemaphore != NULL) CloseHandle(obj->MxWinSemaphore); 1097 | #else 1098 | if (obj->MxMem != NULL) 1099 | { 1100 | if (obj->MxNamed) sync_UnmapUnixNamedMem(obj->MxMem, sync_GetUnixSemaphoreSize()); 1101 | else 1102 | { 1103 | sync_FreeUnixSemaphore(&obj->MxPthreadSemaphore); 1104 | 1105 | efree(obj->MxMem); 1106 | } 1107 | } 1108 | #endif 1109 | 1110 | PORTABLE_free_zend_object_free_object(obj); 1111 | } 1112 | /* }}} */ 1113 | 1114 | /* {{{ proto void Sync_Semaphore::__construct([string $name = null, [int $initialval = 1, [bool $autounlock = true]]]) 1115 | Constructs a named or unnamed semaphore object. Don't set $autounlock to false unless you really know what you are doing. */ 1116 | PHP_METHOD(sync_Semaphore, __construct) 1117 | { 1118 | char *name = NULL; 1119 | PORTABLE_ZPP_ARG_size name_len; 1120 | PORTABLE_ZPP_ARG_long initialval = 1; 1121 | PORTABLE_ZPP_ARG_long autounlock = 1; 1122 | sync_Semaphore_object *obj; 1123 | #if defined(PHP_WIN32) 1124 | SECURITY_ATTRIBUTES SecAttr; 1125 | #else 1126 | size_t Pos, TempSize; 1127 | #endif 1128 | 1129 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!ll", &name, &name_len, &initialval, &autounlock) == FAILURE) return; 1130 | 1131 | obj = (sync_Semaphore_object *)PORTABLE_zend_object_store_get_object(); 1132 | 1133 | if (name_len < 1) name = NULL; 1134 | 1135 | obj->MxAutoUnlock = (autounlock ? 1 : 0); 1136 | 1137 | #if defined(PHP_WIN32) 1138 | 1139 | SecAttr.nLength = sizeof(SecAttr); 1140 | SecAttr.lpSecurityDescriptor = NULL; 1141 | SecAttr.bInheritHandle = TRUE; 1142 | 1143 | obj->MxWinSemaphore = CreateSemaphoreA(&SecAttr, (LONG)initialval, (LONG)initialval, name); 1144 | if (obj->MxWinSemaphore == NULL) 1145 | { 1146 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Semaphore could not be created", 0 TSRMLS_CC); 1147 | return; 1148 | } 1149 | 1150 | #else 1151 | 1152 | TempSize = sync_GetUnixSemaphoreSize(); 1153 | obj->MxNamed = (name != NULL ? 1 : 0); 1154 | int Result = sync_InitUnixNamedMem(&obj->MxMem, &Pos, "/Sync_Semaphore", name, TempSize); 1155 | 1156 | if (Result < 0) 1157 | { 1158 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Semaphore could not be created", 0 TSRMLS_CC); 1159 | 1160 | return; 1161 | } 1162 | 1163 | sync_GetUnixSemaphore(&obj->MxPthreadSemaphore, obj->MxMem + Pos); 1164 | 1165 | /* Handle the first time this semaphore has been opened. */ 1166 | if (Result == 0) 1167 | { 1168 | sync_InitUnixSemaphore(&obj->MxPthreadSemaphore, obj->MxNamed, (uint32_t)initialval, (uint32_t)initialval); 1169 | 1170 | if (obj->MxNamed) sync_UnixNamedMemReady(obj->MxMem); 1171 | } 1172 | 1173 | #endif 1174 | } 1175 | /* }}} */ 1176 | 1177 | /* {{{ proto bool Sync_Semaphore::lock([int $wait = -1]) 1178 | Locks a semaphore object. */ 1179 | PHP_METHOD(sync_Semaphore, lock) 1180 | { 1181 | PORTABLE_ZPP_ARG_long wait = -1; 1182 | sync_Semaphore_object *obj; 1183 | #if defined(PHP_WIN32) 1184 | DWORD Result; 1185 | #else 1186 | #endif 1187 | 1188 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &wait) == FAILURE) return; 1189 | 1190 | obj = (sync_Semaphore_object *)PORTABLE_zend_object_store_get_object(); 1191 | 1192 | #if defined(PHP_WIN32) 1193 | 1194 | Result = WaitForSingleObject(obj->MxWinSemaphore, (DWORD)(wait > -1 ? wait : INFINITE)); 1195 | if (Result != WAIT_OBJECT_0) RETURN_FALSE; 1196 | 1197 | #else 1198 | 1199 | if (!sync_WaitForUnixSemaphore(&obj->MxPthreadSemaphore, (uint32_t)(wait > -1 ? wait : INFINITE))) RETURN_FALSE; 1200 | 1201 | #endif 1202 | 1203 | if (obj->MxAutoUnlock) obj->MxCount++; 1204 | 1205 | RETURN_TRUE; 1206 | } 1207 | /* }}} */ 1208 | 1209 | /* {{{ proto bool Sync_Semaphore::unlock([int &$prevcount]) 1210 | Unlocks a semaphore object. */ 1211 | PHP_METHOD(sync_Semaphore, unlock) 1212 | { 1213 | PORTABLE_ZPP_ARG_zval_ref zprevcount = NULL; 1214 | sync_Semaphore_object *obj; 1215 | PORTABLE_ZPP_ARG_long count; 1216 | #if defined(PHP_WIN32) 1217 | LONG PrevCount; 1218 | #else 1219 | uint32_t PrevCount; 1220 | #endif 1221 | 1222 | #if PHP_MAJOR_VERSION >= 7 1223 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/", &zprevcount) == FAILURE) return; 1224 | #else 1225 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &zprevcount) == FAILURE) return; 1226 | #endif 1227 | 1228 | obj = (sync_Semaphore_object *)PORTABLE_zend_object_store_get_object(); 1229 | 1230 | #if defined(PHP_WIN32) 1231 | 1232 | if (!ReleaseSemaphore(obj->MxWinSemaphore, 1, &PrevCount)) RETURN_FALSE; 1233 | 1234 | #else 1235 | 1236 | sync_ReleaseUnixSemaphore(&obj->MxPthreadSemaphore, &PrevCount); 1237 | 1238 | #endif 1239 | 1240 | if (zprevcount != NULL) 1241 | { 1242 | count = (PORTABLE_ZPP_ARG_long)PrevCount; 1243 | 1244 | zval_dtor(PORTABLE_ZPP_ARG_zval_ref_deref(zprevcount)); 1245 | ZVAL_LONG(PORTABLE_ZPP_ARG_zval_ref_deref(zprevcount), count); 1246 | } 1247 | 1248 | if (obj->MxAutoUnlock) obj->MxCount--; 1249 | 1250 | RETURN_TRUE; 1251 | } 1252 | /* }}} */ 1253 | 1254 | 1255 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_semaphore___construct, 0, 0, 0) 1256 | ZEND_ARG_INFO(0, name) 1257 | ZEND_ARG_INFO(0, initialval) 1258 | ZEND_ARG_INFO(0, autounlock) 1259 | ZEND_END_ARG_INFO() 1260 | 1261 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_semaphore_lock, 0, 0, 0) 1262 | ZEND_ARG_INFO(0, wait) 1263 | ZEND_END_ARG_INFO() 1264 | 1265 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_semaphore_unlock, 0, 0, 0) 1266 | ZEND_ARG_INFO(1, prevcount) 1267 | ZEND_END_ARG_INFO() 1268 | 1269 | static const zend_function_entry sync_Semaphore_methods[] = { 1270 | PHP_ME(sync_Semaphore, __construct, arginfo_sync_semaphore___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 1271 | PHP_ME(sync_Semaphore, lock, arginfo_sync_semaphore_lock, ZEND_ACC_PUBLIC) 1272 | PHP_ME(sync_Semaphore, unlock, arginfo_sync_semaphore_unlock, ZEND_ACC_PUBLIC) 1273 | PHP_FE_END 1274 | }; 1275 | 1276 | 1277 | 1278 | /* Event */ 1279 | PHP_SYNC_API zend_class_entry *sync_Event_ce; 1280 | static zend_object_handlers sync_Event_object_handlers; 1281 | 1282 | PORTABLE_free_zend_object_func(sync_Event_free_object); 1283 | 1284 | /* {{{ Initialize internal Event structure. */ 1285 | PORTABLE_new_zend_object_func(sync_Event_create_object) 1286 | { 1287 | PORTABLE_new_zend_object_return_var; 1288 | sync_Event_object *obj; 1289 | 1290 | /* Create the object. */ 1291 | obj = (sync_Event_object *)PORTABLE_allocate_zend_object(sizeof(sync_Event_object), ce); 1292 | 1293 | PORTABLE_InitZendObject(obj, &obj->std, PORTABLE_new_zend_object_return_var_ref, sync_Event_free_object, &sync_Event_object_handlers, ce TSRMLS_CC); 1294 | 1295 | /* Initialize Event information. */ 1296 | #if defined(PHP_WIN32) 1297 | obj->MxWinWaitEvent = NULL; 1298 | #else 1299 | obj->MxNamed = 0; 1300 | obj->MxMem = NULL; 1301 | #endif 1302 | 1303 | PORTABLE_new_zend_object_return(&obj->std); 1304 | } 1305 | /* }}} */ 1306 | 1307 | /* {{{ Free internal Event structure. */ 1308 | PORTABLE_free_zend_object_func(sync_Event_free_object) 1309 | { 1310 | sync_Event_object *obj = (sync_Event_object *)PORTABLE_free_zend_object_get_object(object); 1311 | 1312 | #if defined(PHP_WIN32) 1313 | if (obj->MxWinWaitEvent != NULL) CloseHandle(obj->MxWinWaitEvent); 1314 | #else 1315 | if (obj->MxMem != NULL) 1316 | { 1317 | if (obj->MxNamed) sync_UnmapUnixNamedMem(obj->MxMem, sync_GetUnixEventSize()); 1318 | else 1319 | { 1320 | sync_FreeUnixEvent(&obj->MxPthreadEvent); 1321 | 1322 | efree(obj->MxMem); 1323 | } 1324 | } 1325 | #endif 1326 | 1327 | PORTABLE_free_zend_object_free_object(obj); 1328 | } 1329 | /* }}} */ 1330 | 1331 | /* {{{ proto void Sync_Event::__construct([string $name = null, [bool $manual = false, [bool $prefire = false]]]) 1332 | Constructs a named or unnamed event object. */ 1333 | PHP_METHOD(sync_Event, __construct) 1334 | { 1335 | char *name = NULL; 1336 | PORTABLE_ZPP_ARG_size name_len; 1337 | PORTABLE_ZPP_ARG_long manual = 0, prefire = 0; 1338 | sync_Event_object *obj; 1339 | #if defined(PHP_WIN32) 1340 | SECURITY_ATTRIBUTES SecAttr; 1341 | #else 1342 | size_t Pos, TempSize; 1343 | #endif 1344 | 1345 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!ll", &name, &name_len, &manual, &prefire) == FAILURE) return; 1346 | 1347 | obj = (sync_Event_object *)PORTABLE_zend_object_store_get_object(); 1348 | 1349 | if (name_len < 1) name = NULL; 1350 | 1351 | #if defined(PHP_WIN32) 1352 | 1353 | SecAttr.nLength = sizeof(SecAttr); 1354 | SecAttr.lpSecurityDescriptor = NULL; 1355 | SecAttr.bInheritHandle = TRUE; 1356 | 1357 | obj->MxWinWaitEvent = CreateEventA(&SecAttr, (BOOL)manual, (prefire ? TRUE : FALSE), name); 1358 | if (obj->MxWinWaitEvent == NULL) 1359 | { 1360 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Event object could not be created", 0 TSRMLS_CC); 1361 | return; 1362 | } 1363 | 1364 | #else 1365 | 1366 | TempSize = sync_GetUnixEventSize(); 1367 | obj->MxNamed = (name != NULL ? 1 : 0); 1368 | int Result = sync_InitUnixNamedMem(&obj->MxMem, &Pos, "/Sync_Event", name, TempSize); 1369 | 1370 | if (Result < 0) 1371 | { 1372 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Event object could not be created", 0 TSRMLS_CC); 1373 | 1374 | return; 1375 | } 1376 | 1377 | sync_GetUnixEvent(&obj->MxPthreadEvent, obj->MxMem + Pos); 1378 | 1379 | /* Handle the first time this event has been opened. */ 1380 | if (Result == 0) 1381 | { 1382 | sync_InitUnixEvent(&obj->MxPthreadEvent, obj->MxNamed, (manual ? 1 : 0), (prefire ? 1 : 0)); 1383 | 1384 | if (obj->MxNamed) sync_UnixNamedMemReady(obj->MxMem); 1385 | } 1386 | 1387 | #endif 1388 | } 1389 | /* }}} */ 1390 | 1391 | /* {{{ proto bool Sync_Event::wait([int $wait = -1]) 1392 | Waits for an event object to fire. */ 1393 | PHP_METHOD(sync_Event, wait) 1394 | { 1395 | PORTABLE_ZPP_ARG_long wait = -1; 1396 | sync_Event_object *obj; 1397 | #if defined(PHP_WIN32) 1398 | DWORD Result; 1399 | #endif 1400 | 1401 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &wait) == FAILURE) return; 1402 | 1403 | obj = (sync_Event_object *)PORTABLE_zend_object_store_get_object(); 1404 | 1405 | #if defined(PHP_WIN32) 1406 | 1407 | Result = WaitForSingleObject(obj->MxWinWaitEvent, (DWORD)(wait > -1 ? wait : INFINITE)); 1408 | if (Result != WAIT_OBJECT_0) RETURN_FALSE; 1409 | 1410 | #else 1411 | 1412 | if (!sync_WaitForUnixEvent(&obj->MxPthreadEvent, (uint32_t)(wait > -1 ? wait : INFINITE))) RETURN_FALSE; 1413 | 1414 | #endif 1415 | 1416 | RETURN_TRUE; 1417 | } 1418 | /* }}} */ 1419 | 1420 | /* {{{ proto bool Sync_Event::fire() 1421 | Lets a thread through that is waiting. Lets multiple threads through that are waiting if the event object is 'manual'. */ 1422 | PHP_METHOD(sync_Event, fire) 1423 | { 1424 | sync_Event_object *obj; 1425 | 1426 | obj = (sync_Event_object *)PORTABLE_zend_object_store_get_object(); 1427 | 1428 | #if defined(PHP_WIN32) 1429 | 1430 | if (!SetEvent(obj->MxWinWaitEvent)) RETURN_FALSE; 1431 | 1432 | #else 1433 | 1434 | if (!sync_FireUnixEvent(&obj->MxPthreadEvent)) RETURN_FALSE; 1435 | 1436 | #endif 1437 | 1438 | RETURN_TRUE; 1439 | } 1440 | /* }}} */ 1441 | 1442 | /* {{{ proto bool Sync_Event::reset() 1443 | Resets the event object state. Only use when the event object is 'manual'. */ 1444 | PHP_METHOD(sync_Event, reset) 1445 | { 1446 | sync_Event_object *obj; 1447 | 1448 | obj = (sync_Event_object *)PORTABLE_zend_object_store_get_object(); 1449 | 1450 | #if defined(PHP_WIN32) 1451 | 1452 | if (!ResetEvent(obj->MxWinWaitEvent)) RETURN_FALSE; 1453 | 1454 | #else 1455 | 1456 | if (!sync_ResetUnixEvent(&obj->MxPthreadEvent)) RETURN_FALSE; 1457 | 1458 | #endif 1459 | 1460 | RETURN_TRUE; 1461 | } 1462 | /* }}} */ 1463 | 1464 | 1465 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_event___construct, 0, 0, 0) 1466 | ZEND_ARG_INFO(0, name) 1467 | ZEND_ARG_INFO(0, manual) 1468 | ZEND_END_ARG_INFO() 1469 | 1470 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_event_wait, 0, 0, 0) 1471 | ZEND_ARG_INFO(0, wait) 1472 | ZEND_END_ARG_INFO() 1473 | 1474 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_event_fire, 0, 0, 0) 1475 | ZEND_END_ARG_INFO() 1476 | 1477 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_event_reset, 0, 0, 0) 1478 | ZEND_END_ARG_INFO() 1479 | 1480 | static const zend_function_entry sync_Event_methods[] = { 1481 | PHP_ME(sync_Event, __construct, arginfo_sync_event___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 1482 | PHP_ME(sync_Event, wait, arginfo_sync_event_wait, ZEND_ACC_PUBLIC) 1483 | PHP_ME(sync_Event, fire, arginfo_sync_event_fire, ZEND_ACC_PUBLIC) 1484 | PHP_ME(sync_Event, reset, arginfo_sync_event_reset, ZEND_ACC_PUBLIC) 1485 | PHP_FE_END 1486 | }; 1487 | 1488 | 1489 | 1490 | /* Reader-Writer */ 1491 | PHP_SYNC_API zend_class_entry *sync_ReaderWriter_ce; 1492 | static zend_object_handlers sync_ReaderWriter_object_handlers; 1493 | 1494 | PORTABLE_free_zend_object_func(sync_ReaderWriter_free_object); 1495 | 1496 | /* {{{ Initialize internal Reader-Writer structure. */ 1497 | PORTABLE_new_zend_object_func(sync_ReaderWriter_create_object) 1498 | { 1499 | PORTABLE_new_zend_object_return_var; 1500 | sync_ReaderWriter_object *obj; 1501 | 1502 | /* Create the object. */ 1503 | obj = (sync_ReaderWriter_object *)PORTABLE_allocate_zend_object(sizeof(sync_ReaderWriter_object), ce); 1504 | 1505 | PORTABLE_InitZendObject(obj, &obj->std, PORTABLE_new_zend_object_return_var_ref, sync_ReaderWriter_free_object, &sync_ReaderWriter_object_handlers, ce TSRMLS_CC); 1506 | 1507 | /* Initialize Reader-Writer information. */ 1508 | #if defined(PHP_WIN32) 1509 | obj->MxWinRSemMutex = NULL; 1510 | obj->MxWinRSemaphore = NULL; 1511 | obj->MxWinRWaitEvent = NULL; 1512 | obj->MxWinWWaitMutex = NULL; 1513 | #else 1514 | obj->MxNamed = 0; 1515 | obj->MxMem = NULL; 1516 | obj->MxRCount = NULL; 1517 | #endif 1518 | 1519 | obj->MxAutoUnlock = 1; 1520 | obj->MxReadLocks = 0; 1521 | obj->MxWriteLock = 0; 1522 | 1523 | PORTABLE_new_zend_object_return(&obj->std); 1524 | } 1525 | /* }}} */ 1526 | 1527 | /* {{{ Unlocks a read lock. */ 1528 | int sync_ReaderWriter_readunlock_internal(sync_ReaderWriter_object *obj) 1529 | { 1530 | #if defined(PHP_WIN32) 1531 | 1532 | DWORD Result; 1533 | LONG Val; 1534 | 1535 | if (obj->MxWinRSemMutex == NULL || obj->MxWinRSemaphore == NULL || obj->MxWinRWaitEvent == NULL) return 0; 1536 | 1537 | /* Acquire the semaphore mutex. */ 1538 | Result = WaitForSingleObject(obj->MxWinRSemMutex, INFINITE); 1539 | if (Result != WAIT_OBJECT_0) return 0; 1540 | 1541 | if (obj->MxReadLocks) obj->MxReadLocks--; 1542 | 1543 | /* Release the semaphore. */ 1544 | if (!ReleaseSemaphore(obj->MxWinRSemaphore, 1, &Val)) 1545 | { 1546 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1547 | 1548 | return 0; 1549 | } 1550 | 1551 | /* Update the event state. */ 1552 | if (Val == LONG_MAX - 1) 1553 | { 1554 | if (!SetEvent(obj->MxWinRWaitEvent)) 1555 | { 1556 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1557 | 1558 | return 0; 1559 | } 1560 | } 1561 | 1562 | /* Release the semaphore mutex. */ 1563 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1564 | 1565 | #else 1566 | 1567 | if (obj->MxMem == NULL) return 0; 1568 | 1569 | /* Acquire the counter mutex. */ 1570 | if (!sync_WaitForUnixSemaphore(&obj->MxPthreadRCountMutex, INFINITE)) return 0; 1571 | 1572 | if (obj->MxReadLocks) obj->MxReadLocks--; 1573 | 1574 | /* Decrease the number of readers. */ 1575 | if (obj->MxRCount[0]) obj->MxRCount[0]--; 1576 | else 1577 | { 1578 | sync_ReleaseUnixSemaphore(&obj->MxPthreadRCountMutex, NULL); 1579 | 1580 | return 0; 1581 | } 1582 | 1583 | /* Update the event state. */ 1584 | if (!obj->MxRCount[0] && !sync_FireUnixEvent(&obj->MxPthreadRWaitEvent)) 1585 | { 1586 | sync_ReleaseUnixSemaphore(&obj->MxPthreadRCountMutex, NULL); 1587 | 1588 | return 0; 1589 | } 1590 | 1591 | /* Release the counter mutex. */ 1592 | sync_ReleaseUnixSemaphore(&obj->MxPthreadRCountMutex, NULL); 1593 | 1594 | #endif 1595 | 1596 | return 1; 1597 | } 1598 | /* }}} */ 1599 | 1600 | /* {{{ Unlocks a write lock. */ 1601 | int sync_ReaderWriter_writeunlock_internal(sync_ReaderWriter_object *obj) 1602 | { 1603 | #if defined(PHP_WIN32) 1604 | 1605 | if (obj->MxWinWWaitMutex == NULL) return 0; 1606 | 1607 | obj->MxWriteLock = 0; 1608 | 1609 | /* Release the write lock. */ 1610 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1611 | 1612 | #else 1613 | 1614 | if (obj->MxMem == NULL) return 0; 1615 | 1616 | obj->MxWriteLock = 0; 1617 | 1618 | /* Release the write lock. */ 1619 | sync_ReleaseUnixSemaphore(&obj->MxPthreadWWaitMutex, NULL); 1620 | 1621 | #endif 1622 | 1623 | return 1; 1624 | } 1625 | /* }}} */ 1626 | 1627 | /* {{{ Free internal Reader-Writer structure. */ 1628 | PORTABLE_free_zend_object_func(sync_ReaderWriter_free_object) 1629 | { 1630 | sync_ReaderWriter_object *obj = (sync_ReaderWriter_object *)PORTABLE_free_zend_object_get_object(object); 1631 | 1632 | if (obj->MxAutoUnlock) 1633 | { 1634 | while (obj->MxReadLocks) sync_ReaderWriter_readunlock_internal(obj); 1635 | 1636 | if (obj->MxWriteLock) sync_ReaderWriter_writeunlock_internal(obj); 1637 | } 1638 | 1639 | #if defined(PHP_WIN32) 1640 | if (obj->MxWinWWaitMutex != NULL) CloseHandle(obj->MxWinWWaitMutex); 1641 | if (obj->MxWinRWaitEvent != NULL) CloseHandle(obj->MxWinRWaitEvent); 1642 | if (obj->MxWinRSemaphore != NULL) CloseHandle(obj->MxWinRSemaphore); 1643 | if (obj->MxWinRSemMutex != NULL) CloseHandle(obj->MxWinRSemMutex); 1644 | #else 1645 | if (obj->MxMem != NULL) 1646 | { 1647 | if (obj->MxNamed) sync_UnmapUnixNamedMem(obj->MxMem, sync_GetUnixSemaphoreSize() + sync_AlignUnixSize(sizeof(uint32_t)) + sync_GetUnixEventSize() + sync_GetUnixSemaphoreSize()); 1648 | else 1649 | { 1650 | sync_FreeUnixSemaphore(&obj->MxPthreadRCountMutex); 1651 | sync_FreeUnixEvent(&obj->MxPthreadRWaitEvent); 1652 | sync_FreeUnixSemaphore(&obj->MxPthreadWWaitMutex); 1653 | 1654 | efree(obj->MxMem); 1655 | } 1656 | } 1657 | #endif 1658 | 1659 | PORTABLE_free_zend_object_free_object(obj); 1660 | } 1661 | /* }}} */ 1662 | 1663 | /* {{{ proto void Sync_ReaderWriter::__construct([string $name = null, [bool $autounlock = true]]) 1664 | Constructs a named or unnamed reader-writer object. Don't set $autounlock to false unless you really know what you are doing. */ 1665 | PHP_METHOD(sync_ReaderWriter, __construct) 1666 | { 1667 | char *name = NULL; 1668 | PORTABLE_ZPP_ARG_size name_len; 1669 | PORTABLE_ZPP_ARG_long autounlock = 1; 1670 | sync_ReaderWriter_object *obj; 1671 | #if defined(PHP_WIN32) 1672 | char *name2; 1673 | SECURITY_ATTRIBUTES SecAttr; 1674 | #else 1675 | size_t Pos, TempSize; 1676 | #endif 1677 | 1678 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!l", &name, &name_len, &autounlock) == FAILURE) return; 1679 | 1680 | obj = (sync_ReaderWriter_object *)PORTABLE_zend_object_store_get_object(); 1681 | 1682 | if (name_len < 1) name = NULL; 1683 | 1684 | obj->MxAutoUnlock = (autounlock ? 1 : 0); 1685 | 1686 | #if defined(PHP_WIN32) 1687 | 1688 | if (name == NULL) name2 = NULL; 1689 | else name2 = emalloc(name_len + 20); 1690 | 1691 | SecAttr.nLength = sizeof(SecAttr); 1692 | SecAttr.lpSecurityDescriptor = NULL; 1693 | SecAttr.bInheritHandle = TRUE; 1694 | 1695 | /* Create the mutexes, semaphore, and event objects. */ 1696 | if (name2 != NULL) sprintf(name2, "%s-Sync_ReadWrite-0", name); 1697 | obj->MxWinRSemMutex = CreateSemaphoreA(&SecAttr, 1, 1, name2); 1698 | if (name2 != NULL) sprintf(name2, "%s-Sync_ReadWrite-1", name); 1699 | obj->MxWinRSemaphore = CreateSemaphoreA(&SecAttr, LONG_MAX, LONG_MAX, name2); 1700 | if (name2 != NULL) sprintf(name2, "%s-Sync_ReadWrite-2", name); 1701 | obj->MxWinRWaitEvent = CreateEventA(&SecAttr, TRUE, TRUE, name2); 1702 | if (name2 != NULL) sprintf(name2, "%s-Sync_ReadWrite-3", name); 1703 | obj->MxWinWWaitMutex = CreateSemaphoreA(&SecAttr, 1, 1, name2); 1704 | 1705 | if (name2 != NULL) efree(name2); 1706 | 1707 | if (obj->MxWinRSemMutex == NULL || obj->MxWinRSemaphore == NULL || obj->MxWinRWaitEvent == NULL || obj->MxWinWWaitMutex == NULL) 1708 | { 1709 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Reader-Writer object could not be created", 0 TSRMLS_CC); 1710 | 1711 | return; 1712 | } 1713 | 1714 | #else 1715 | 1716 | TempSize = sync_GetUnixSemaphoreSize() + sync_AlignUnixSize(sizeof(uint32_t)) + sync_GetUnixEventSize() + sync_GetUnixSemaphoreSize(); 1717 | obj->MxNamed = (name != NULL ? 1 : 0); 1718 | int Result = sync_InitUnixNamedMem(&obj->MxMem, &Pos, "/Sync_ReadWrite", name, TempSize); 1719 | 1720 | if (Result < 0) 1721 | { 1722 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Reader-Writer object could not be created", 0 TSRMLS_CC); 1723 | 1724 | return; 1725 | } 1726 | 1727 | /* Load the pointers. */ 1728 | char *MemPtr = obj->MxMem + Pos; 1729 | sync_GetUnixSemaphore(&obj->MxPthreadRCountMutex, MemPtr); 1730 | MemPtr += sync_GetUnixSemaphoreSize(); 1731 | 1732 | obj->MxRCount = (volatile uint32_t *)(MemPtr); 1733 | MemPtr += sync_AlignUnixSize(sizeof(uint32_t)); 1734 | 1735 | sync_GetUnixEvent(&obj->MxPthreadRWaitEvent, MemPtr); 1736 | MemPtr += sync_GetUnixEventSize(); 1737 | 1738 | sync_GetUnixSemaphore(&obj->MxPthreadWWaitMutex, MemPtr); 1739 | 1740 | /* Handle the first time this reader/writer lock has been opened. */ 1741 | if (Result == 0) 1742 | { 1743 | sync_InitUnixSemaphore(&obj->MxPthreadRCountMutex, obj->MxNamed, 1, 1); 1744 | obj->MxRCount[0] = 0; 1745 | sync_InitUnixEvent(&obj->MxPthreadRWaitEvent, obj->MxNamed, 1, 1); 1746 | sync_InitUnixSemaphore(&obj->MxPthreadWWaitMutex, obj->MxNamed, 1, 1); 1747 | 1748 | if (obj->MxNamed) sync_UnixNamedMemReady(obj->MxMem); 1749 | } 1750 | 1751 | #endif 1752 | } 1753 | /* }}} */ 1754 | 1755 | /* {{{ proto bool Sync_ReaderWriter::readlock([int $wait = -1]) 1756 | Read locks a reader-writer object. */ 1757 | PHP_METHOD(sync_ReaderWriter, readlock) 1758 | { 1759 | PORTABLE_ZPP_ARG_long wait = -1; 1760 | sync_ReaderWriter_object *obj; 1761 | uint32_t WaitAmt; 1762 | uint64_t StartTime, CurrTime; 1763 | #if defined(PHP_WIN32) 1764 | DWORD Result; 1765 | #endif 1766 | 1767 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &wait) == FAILURE) return; 1768 | 1769 | obj = (sync_ReaderWriter_object *)PORTABLE_zend_object_store_get_object(); 1770 | 1771 | WaitAmt = (uint32_t)(wait > -1 ? wait : INFINITE); 1772 | 1773 | /* Get current time in milliseconds. */ 1774 | StartTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1775 | 1776 | #if defined(PHP_WIN32) 1777 | 1778 | /* Acquire the write lock mutex. Guarantees that readers can't starve the writer. */ 1779 | Result = WaitForSingleObject(obj->MxWinWWaitMutex, WaitAmt); 1780 | if (Result != WAIT_OBJECT_0) RETURN_FALSE; 1781 | 1782 | /* Acquire the semaphore mutex. */ 1783 | CurrTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1784 | if (WaitAmt < CurrTime - StartTime) 1785 | { 1786 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1787 | 1788 | RETURN_FALSE; 1789 | } 1790 | Result = WaitForSingleObject(obj->MxWinRSemMutex, WaitAmt - (DWORD)(CurrTime - StartTime)); 1791 | if (Result != WAIT_OBJECT_0) 1792 | { 1793 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1794 | 1795 | RETURN_FALSE; 1796 | } 1797 | 1798 | /* Acquire the semaphore. */ 1799 | CurrTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1800 | if (WaitAmt < CurrTime - StartTime) 1801 | { 1802 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1803 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1804 | 1805 | RETURN_FALSE; 1806 | } 1807 | Result = WaitForSingleObject(obj->MxWinRSemaphore, WaitAmt - (DWORD)(CurrTime - StartTime)); 1808 | if (Result != WAIT_OBJECT_0) 1809 | { 1810 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1811 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1812 | 1813 | RETURN_FALSE; 1814 | } 1815 | 1816 | /* Update the event state. */ 1817 | if (!ResetEvent(obj->MxWinRWaitEvent)) 1818 | { 1819 | ReleaseSemaphore(obj->MxWinRSemaphore, 1, NULL); 1820 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1821 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1822 | 1823 | RETURN_FALSE; 1824 | } 1825 | 1826 | obj->MxReadLocks++; 1827 | 1828 | /* Release the mutexes. */ 1829 | ReleaseSemaphore(obj->MxWinRSemMutex, 1, NULL); 1830 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1831 | 1832 | #else 1833 | 1834 | /* Acquire the write lock mutex. Guarantees that readers can't starve the writer. */ 1835 | if (!sync_WaitForUnixSemaphore(&obj->MxPthreadWWaitMutex, WaitAmt)) RETURN_FALSE; 1836 | 1837 | /* Acquire the counter mutex. */ 1838 | CurrTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1839 | if (WaitAmt < CurrTime - StartTime || !sync_WaitForUnixSemaphore(&obj->MxPthreadRCountMutex, WaitAmt - (CurrTime - StartTime))) 1840 | { 1841 | sync_ReleaseUnixSemaphore(&obj->MxPthreadWWaitMutex, NULL); 1842 | 1843 | RETURN_FALSE; 1844 | } 1845 | 1846 | /* Update the event state. */ 1847 | if (!sync_ResetUnixEvent(&obj->MxPthreadRWaitEvent)) 1848 | { 1849 | sync_ReleaseUnixSemaphore(&obj->MxPthreadRCountMutex, NULL); 1850 | sync_ReleaseUnixSemaphore(&obj->MxPthreadWWaitMutex, NULL); 1851 | 1852 | RETURN_FALSE; 1853 | } 1854 | 1855 | /* Increment the number of readers. */ 1856 | obj->MxRCount[0]++; 1857 | 1858 | obj->MxReadLocks++; 1859 | 1860 | /* Release the mutexes. */ 1861 | sync_ReleaseUnixSemaphore(&obj->MxPthreadRCountMutex, NULL); 1862 | sync_ReleaseUnixSemaphore(&obj->MxPthreadWWaitMutex, NULL); 1863 | 1864 | #endif 1865 | 1866 | RETURN_TRUE; 1867 | } 1868 | /* }}} */ 1869 | 1870 | /* {{{ proto bool Sync_ReaderWriter::writelock([int $wait = -1]) 1871 | Write locks a reader-writer object. */ 1872 | PHP_METHOD(sync_ReaderWriter, writelock) 1873 | { 1874 | PORTABLE_ZPP_ARG_long wait = -1; 1875 | sync_ReaderWriter_object *obj; 1876 | uint32_t WaitAmt; 1877 | uint64_t StartTime, CurrTime; 1878 | #if defined(PHP_WIN32) 1879 | DWORD Result; 1880 | #else 1881 | #endif 1882 | 1883 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &wait) == FAILURE) return; 1884 | 1885 | obj = (sync_ReaderWriter_object *)PORTABLE_zend_object_store_get_object(); 1886 | 1887 | WaitAmt = (uint32_t)(wait > -1 ? wait : INFINITE); 1888 | 1889 | /* Get current time in milliseconds. */ 1890 | StartTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1891 | 1892 | #if defined(PHP_WIN32) 1893 | 1894 | /* Acquire the write lock mutex. */ 1895 | Result = WaitForSingleObject(obj->MxWinWWaitMutex, WaitAmt); 1896 | if (Result != WAIT_OBJECT_0) RETURN_FALSE; 1897 | 1898 | /* Wait for readers to reach zero. */ 1899 | CurrTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1900 | Result = WaitForSingleObject(obj->MxWinRWaitEvent, WaitAmt - (DWORD)(CurrTime - StartTime)); 1901 | if (Result != WAIT_OBJECT_0) 1902 | { 1903 | ReleaseSemaphore(obj->MxWinWWaitMutex, 1, NULL); 1904 | 1905 | RETURN_FALSE; 1906 | } 1907 | 1908 | #else 1909 | 1910 | /* Acquire the write lock mutex. */ 1911 | if (!sync_WaitForUnixSemaphore(&obj->MxPthreadWWaitMutex, WaitAmt)) RETURN_FALSE; 1912 | 1913 | /* Wait for readers to reach zero. */ 1914 | CurrTime = (WaitAmt == INFINITE ? 0 : sync_GetUnixMicrosecondTime() / 1000000); 1915 | if (WaitAmt < CurrTime - StartTime || !sync_WaitForUnixEvent(&obj->MxPthreadRWaitEvent, WaitAmt - (CurrTime - StartTime))) 1916 | { 1917 | sync_ReleaseUnixSemaphore(&obj->MxPthreadWWaitMutex, NULL); 1918 | 1919 | RETURN_FALSE; 1920 | } 1921 | 1922 | #endif 1923 | 1924 | obj->MxWriteLock = 1; 1925 | 1926 | RETURN_TRUE; 1927 | } 1928 | /* }}} */ 1929 | 1930 | /* {{{ proto bool Sync_ReaderWriter::readunlock() 1931 | Read unlocks a reader-writer object. */ 1932 | PHP_METHOD(sync_ReaderWriter, readunlock) 1933 | { 1934 | sync_ReaderWriter_object *obj; 1935 | 1936 | obj = (sync_ReaderWriter_object *)PORTABLE_zend_object_store_get_object(); 1937 | 1938 | if (!sync_ReaderWriter_readunlock_internal(obj)) RETURN_FALSE; 1939 | 1940 | RETURN_TRUE; 1941 | } 1942 | /* }}} */ 1943 | 1944 | /* {{{ proto bool Sync_ReaderWriter::writeunlock() 1945 | Write unlocks a reader-writer object. */ 1946 | PHP_METHOD(sync_ReaderWriter, writeunlock) 1947 | { 1948 | sync_ReaderWriter_object *obj; 1949 | 1950 | obj = (sync_ReaderWriter_object *)PORTABLE_zend_object_store_get_object(); 1951 | 1952 | if (!sync_ReaderWriter_writeunlock_internal(obj)) RETURN_FALSE; 1953 | 1954 | RETURN_TRUE; 1955 | } 1956 | /* }}} */ 1957 | 1958 | 1959 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_readerwriter___construct, 0, 0, 0) 1960 | ZEND_ARG_INFO(0, name) 1961 | ZEND_ARG_INFO(0, autounlock) 1962 | ZEND_END_ARG_INFO() 1963 | 1964 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_readerwriter_readlock, 0, 0, 0) 1965 | ZEND_ARG_INFO(0, wait) 1966 | ZEND_END_ARG_INFO() 1967 | 1968 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_readerwriter_writelock, 0, 0, 0) 1969 | ZEND_ARG_INFO(0, wait) 1970 | ZEND_END_ARG_INFO() 1971 | 1972 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_readerwriter_readunlock, 0, 0, 0) 1973 | ZEND_END_ARG_INFO() 1974 | 1975 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_readerwriter_writeunlock, 0, 0, 0) 1976 | ZEND_END_ARG_INFO() 1977 | 1978 | static const zend_function_entry sync_ReaderWriter_methods[] = { 1979 | PHP_ME(sync_ReaderWriter, __construct, arginfo_sync_readerwriter___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 1980 | PHP_ME(sync_ReaderWriter, readlock, arginfo_sync_readerwriter_readlock, ZEND_ACC_PUBLIC) 1981 | PHP_ME(sync_ReaderWriter, writelock, arginfo_sync_readerwriter_writelock, ZEND_ACC_PUBLIC) 1982 | PHP_ME(sync_ReaderWriter, readunlock, arginfo_sync_readerwriter_readunlock, ZEND_ACC_PUBLIC) 1983 | PHP_ME(sync_ReaderWriter, writeunlock, arginfo_sync_readerwriter_writeunlock, ZEND_ACC_PUBLIC) 1984 | PHP_FE_END 1985 | }; 1986 | 1987 | 1988 | 1989 | /* Shared Memory */ 1990 | PHP_SYNC_API zend_class_entry *sync_SharedMemory_ce; 1991 | static zend_object_handlers sync_SharedMemory_object_handlers; 1992 | 1993 | PORTABLE_free_zend_object_func(sync_SharedMemory_free_object); 1994 | 1995 | /* {{{ Initialize internal Shared Memory structure. */ 1996 | PORTABLE_new_zend_object_func(sync_SharedMemory_create_object) 1997 | { 1998 | PORTABLE_new_zend_object_return_var; 1999 | sync_SharedMemory_object *obj; 2000 | 2001 | /* Create the object. */ 2002 | obj = (sync_SharedMemory_object *)PORTABLE_allocate_zend_object(sizeof(sync_SharedMemory_object), ce); 2003 | 2004 | PORTABLE_InitZendObject(obj, &obj->std, PORTABLE_new_zend_object_return_var_ref, sync_SharedMemory_free_object, &sync_SharedMemory_object_handlers, ce TSRMLS_CC); 2005 | 2006 | /* Initialize Shared Memory information. */ 2007 | #if defined(PHP_WIN32) 2008 | obj->MxFile = NULL; 2009 | #else 2010 | obj->MxMemInternal = NULL; 2011 | #endif 2012 | 2013 | obj->MxFirst = 0; 2014 | obj->MxSize = 0; 2015 | obj->MxMem = NULL; 2016 | 2017 | PORTABLE_new_zend_object_return(&obj->std); 2018 | } 2019 | /* }}} */ 2020 | 2021 | /* {{{ Free internal Shared Memory structure. */ 2022 | PORTABLE_free_zend_object_func(sync_SharedMemory_free_object) 2023 | { 2024 | sync_SharedMemory_object *obj = (sync_SharedMemory_object *)PORTABLE_free_zend_object_get_object(object); 2025 | 2026 | #if defined(PHP_WIN32) 2027 | if (obj->MxMem != NULL) UnmapViewOfFile(obj->MxMem); 2028 | if (obj->MxFile != NULL) CloseHandle(obj->MxFile); 2029 | #else 2030 | if (obj->MxMemInternal != NULL) sync_UnmapUnixNamedMem(obj->MxMemInternal, obj->MxSize); 2031 | #endif 2032 | 2033 | PORTABLE_free_zend_object_free_object(obj); 2034 | } 2035 | /* }}} */ 2036 | 2037 | /* {{{ proto void Sync_SharedMemory::__construct(string $name, int $size) 2038 | Constructs a named shared memory object. */ 2039 | PHP_METHOD(sync_SharedMemory, __construct) 2040 | { 2041 | char *name; 2042 | PORTABLE_ZPP_ARG_size name_len; 2043 | PORTABLE_ZPP_ARG_long size; 2044 | sync_SharedMemory_object *obj; 2045 | #if defined(PHP_WIN32) 2046 | char *name2; 2047 | SECURITY_ATTRIBUTES SecAttr; 2048 | #else 2049 | size_t Pos, TempSize; 2050 | #endif 2051 | 2052 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &name, &name_len, &size) == FAILURE) return; 2053 | 2054 | if (name_len < 1) 2055 | { 2056 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "An invalid name was passed", 0 TSRMLS_CC); 2057 | 2058 | return; 2059 | } 2060 | 2061 | obj = (sync_SharedMemory_object *)PORTABLE_zend_object_store_get_object(); 2062 | 2063 | #if defined(PHP_WIN32) 2064 | 2065 | name2 = emalloc(name_len + 30); 2066 | 2067 | SecAttr.nLength = sizeof(SecAttr); 2068 | SecAttr.lpSecurityDescriptor = NULL; 2069 | SecAttr.bInheritHandle = TRUE; 2070 | 2071 | /* Create the file mapping object backed by the system page file. */ 2072 | sprintf(name2, "%s-%u-Sync_SharedMem", name, (unsigned int)size); 2073 | obj->MxFile = CreateFileMappingA(INVALID_HANDLE_VALUE, &SecAttr, PAGE_READWRITE, 0, (DWORD)size, name2); 2074 | if (obj->MxFile == NULL) 2075 | { 2076 | obj->MxFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, TRUE, name2); 2077 | 2078 | if (obj->MxFile == NULL) 2079 | { 2080 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Shared memory file mapping could not be created/opened", 0 TSRMLS_CC); 2081 | 2082 | return; 2083 | } 2084 | } 2085 | else if (GetLastError() != ERROR_ALREADY_EXISTS) 2086 | { 2087 | obj->MxFirst = 1; 2088 | } 2089 | 2090 | efree(name2); 2091 | 2092 | obj->MxMem = (char *)MapViewOfFile(obj->MxFile, FILE_MAP_ALL_ACCESS, 0, 0, (DWORD)size); 2093 | 2094 | if (obj->MxMem == NULL) 2095 | { 2096 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Shared memory segment could not be mapped", 0 TSRMLS_CC); 2097 | 2098 | return; 2099 | } 2100 | 2101 | obj->MxSize = (size_t)size; 2102 | 2103 | #else 2104 | 2105 | TempSize = (size_t)size; 2106 | int Result = sync_InitUnixNamedMem(&obj->MxMemInternal, &Pos, "/Sync_SharedMem", name, TempSize); 2107 | 2108 | if (Result < 0) 2109 | { 2110 | zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Shared memory object could not be created/opened", 0 TSRMLS_CC); 2111 | 2112 | return; 2113 | } 2114 | 2115 | /* Load the pointers. */ 2116 | obj->MxMem = obj->MxMemInternal + Pos; 2117 | obj->MxSize = (size_t)size; 2118 | 2119 | /* Handle the first time this named memory has been opened. */ 2120 | if (Result == 0) 2121 | { 2122 | sync_UnixNamedMemReady(obj->MxMemInternal); 2123 | 2124 | obj->MxFirst = 1; 2125 | } 2126 | 2127 | #endif 2128 | } 2129 | /* }}} */ 2130 | 2131 | /* {{{ proto bool Sync_SharedMemory::first() 2132 | Returns whether or not this shared memory segment is the first time accessed (i.e. not initialized). */ 2133 | PHP_METHOD(sync_SharedMemory, first) 2134 | { 2135 | sync_SharedMemory_object *obj; 2136 | 2137 | obj = (sync_SharedMemory_object *)PORTABLE_zend_object_store_get_object(); 2138 | 2139 | RETURN_BOOL(obj->MxFirst); 2140 | } 2141 | /* }}} */ 2142 | 2143 | /* {{{ proto int Sync_SharedMemory::size() 2144 | Returns the shared memory size. */ 2145 | PHP_METHOD(sync_SharedMemory, size) 2146 | { 2147 | sync_SharedMemory_object *obj; 2148 | 2149 | obj = (sync_SharedMemory_object *)PORTABLE_zend_object_store_get_object(); 2150 | 2151 | RETURN_LONG((PORTABLE_ZPP_ARG_long)obj->MxSize); 2152 | } 2153 | /* }}} */ 2154 | 2155 | /* {{{ proto int Sync_SharedMemory::write(string $string, [int $start = 0]) 2156 | Copies data to shared memory. */ 2157 | PHP_METHOD(sync_SharedMemory, write) 2158 | { 2159 | char *str; 2160 | PORTABLE_ZPP_ARG_size str_len; 2161 | PORTABLE_ZPP_ARG_long start = 0, maxval; 2162 | sync_SharedMemory_object *obj; 2163 | 2164 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &start) == FAILURE) return; 2165 | 2166 | obj = (sync_SharedMemory_object *)PORTABLE_zend_object_store_get_object(); 2167 | maxval = (PORTABLE_ZPP_ARG_long)obj->MxSize; 2168 | 2169 | if (start < 0) start += maxval; 2170 | if (start < 0) start = 0; 2171 | if (start > maxval) start = maxval; 2172 | 2173 | if (start + str_len > maxval) str_len = maxval - start; 2174 | 2175 | memcpy(obj->MxMem + (size_t)start, str, str_len); 2176 | 2177 | RETURN_LONG((PORTABLE_ZPP_ARG_long)str_len); 2178 | } 2179 | /* }}} */ 2180 | 2181 | /* {{{ proto string Sync_SharedMemory::read([int $start = 0, [int $length = null]]) 2182 | Copies data from shared memory. */ 2183 | PHP_METHOD(sync_SharedMemory, read) 2184 | { 2185 | PORTABLE_ZPP_ARG_long start = 0; 2186 | PORTABLE_ZPP_ARG_long length, maxval; 2187 | sync_SharedMemory_object *obj; 2188 | 2189 | obj = (sync_SharedMemory_object *)PORTABLE_zend_object_store_get_object(); 2190 | maxval = (PORTABLE_ZPP_ARG_long)obj->MxSize; 2191 | length = maxval; 2192 | 2193 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &start, &length) == FAILURE) return; 2194 | 2195 | if (start < 0) start += maxval; 2196 | if (start < 0) start = 0; 2197 | if (start > maxval) start = maxval; 2198 | 2199 | if (length < 0) length += maxval - start; 2200 | if (length < 0) length = 0; 2201 | if (start + length > maxval) length = maxval - start; 2202 | 2203 | PORTABLE_RETURN_STRINGL(obj->MxMem + start, length); 2204 | } 2205 | /* }}} */ 2206 | 2207 | 2208 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_sharedmemory___construct, 0, 0, 2) 2209 | ZEND_ARG_INFO(0, name) 2210 | ZEND_ARG_INFO(0, size) 2211 | ZEND_END_ARG_INFO() 2212 | 2213 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_sharedmemory_first, 0, 0, 0) 2214 | ZEND_END_ARG_INFO() 2215 | 2216 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_sharedmemory_size, 0, 0, 0) 2217 | ZEND_END_ARG_INFO() 2218 | 2219 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_sharedmemory_write, 0, 0, 1) 2220 | ZEND_ARG_INFO(0, string) 2221 | ZEND_ARG_INFO(0, start) 2222 | ZEND_END_ARG_INFO() 2223 | 2224 | ZEND_BEGIN_ARG_INFO_EX(arginfo_sync_sharedmemory_read, 0, 0, 0) 2225 | ZEND_ARG_INFO(0, start) 2226 | ZEND_ARG_INFO(0, length) 2227 | ZEND_END_ARG_INFO() 2228 | 2229 | static const zend_function_entry sync_SharedMemory_methods[] = { 2230 | PHP_ME(sync_SharedMemory, __construct, arginfo_sync_sharedmemory___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 2231 | PHP_ME(sync_SharedMemory, first, arginfo_sync_sharedmemory_first, ZEND_ACC_PUBLIC) 2232 | PHP_ME(sync_SharedMemory, size, arginfo_sync_sharedmemory_size, ZEND_ACC_PUBLIC) 2233 | PHP_ME(sync_SharedMemory, write, arginfo_sync_sharedmemory_write, ZEND_ACC_PUBLIC) 2234 | PHP_ME(sync_SharedMemory, read, arginfo_sync_sharedmemory_read, ZEND_ACC_PUBLIC) 2235 | PHP_FE_END 2236 | }; 2237 | 2238 | 2239 | /* {{{ PHP_MINIT_FUNCTION(sync) 2240 | */ 2241 | PHP_MINIT_FUNCTION(sync) 2242 | { 2243 | zend_class_entry ce; 2244 | 2245 | /* Mutex */ 2246 | memcpy(&sync_Mutex_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 2247 | sync_Mutex_object_handlers.clone_obj = NULL; 2248 | #if PHP_MAJOR_VERSION >= 7 2249 | sync_Mutex_object_handlers.offset = XtOffsetOf(sync_Mutex_object, PORTABLE_default_zend_object_name); 2250 | sync_Mutex_object_handlers.free_obj = sync_Mutex_free_object; 2251 | #endif 2252 | 2253 | INIT_CLASS_ENTRY(ce, "SyncMutex", sync_Mutex_methods); 2254 | ce.create_object = sync_Mutex_create_object; 2255 | sync_Mutex_ce = zend_register_internal_class(&ce TSRMLS_CC); 2256 | 2257 | 2258 | /* Semaphore */ 2259 | memcpy(&sync_Semaphore_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 2260 | sync_Semaphore_object_handlers.clone_obj = NULL; 2261 | #if PHP_MAJOR_VERSION >= 7 2262 | sync_Semaphore_object_handlers.offset = XtOffsetOf(sync_Semaphore_object, PORTABLE_default_zend_object_name); 2263 | sync_Semaphore_object_handlers.free_obj = sync_Semaphore_free_object; 2264 | #endif 2265 | 2266 | INIT_CLASS_ENTRY(ce, "SyncSemaphore", sync_Semaphore_methods); 2267 | ce.create_object = sync_Semaphore_create_object; 2268 | sync_Semaphore_ce = zend_register_internal_class(&ce TSRMLS_CC); 2269 | 2270 | 2271 | /* Event */ 2272 | memcpy(&sync_Event_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 2273 | sync_Event_object_handlers.clone_obj = NULL; 2274 | #if PHP_MAJOR_VERSION >= 7 2275 | sync_Event_object_handlers.offset = XtOffsetOf(sync_Event_object, PORTABLE_default_zend_object_name); 2276 | sync_Event_object_handlers.free_obj = sync_Event_free_object; 2277 | #endif 2278 | 2279 | INIT_CLASS_ENTRY(ce, "SyncEvent", sync_Event_methods); 2280 | ce.create_object = sync_Event_create_object; 2281 | sync_Event_ce = zend_register_internal_class(&ce TSRMLS_CC); 2282 | 2283 | 2284 | /* Reader-Writer */ 2285 | memcpy(&sync_ReaderWriter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 2286 | sync_ReaderWriter_object_handlers.clone_obj = NULL; 2287 | #if PHP_MAJOR_VERSION >= 7 2288 | sync_ReaderWriter_object_handlers.offset = XtOffsetOf(sync_ReaderWriter_object, PORTABLE_default_zend_object_name); 2289 | sync_ReaderWriter_object_handlers.free_obj = sync_ReaderWriter_free_object; 2290 | #endif 2291 | 2292 | INIT_CLASS_ENTRY(ce, "SyncReaderWriter", sync_ReaderWriter_methods); 2293 | ce.create_object = sync_ReaderWriter_create_object; 2294 | sync_ReaderWriter_ce = zend_register_internal_class(&ce TSRMLS_CC); 2295 | 2296 | 2297 | /* Named Shared Memory */ 2298 | memcpy(&sync_SharedMemory_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 2299 | sync_SharedMemory_object_handlers.clone_obj = NULL; 2300 | #if PHP_MAJOR_VERSION >= 7 2301 | sync_SharedMemory_object_handlers.offset = XtOffsetOf(sync_SharedMemory_object, PORTABLE_default_zend_object_name); 2302 | sync_SharedMemory_object_handlers.free_obj = sync_SharedMemory_free_object; 2303 | #endif 2304 | 2305 | INIT_CLASS_ENTRY(ce, "SyncSharedMemory", sync_SharedMemory_methods); 2306 | ce.create_object = sync_SharedMemory_create_object; 2307 | sync_SharedMemory_ce = zend_register_internal_class(&ce TSRMLS_CC); 2308 | 2309 | return SUCCESS; 2310 | } 2311 | /* }}} */ 2312 | 2313 | /* {{{ PHP_MSHUTDOWN_FUNCTION 2314 | */ 2315 | PHP_MSHUTDOWN_FUNCTION(sync) 2316 | { 2317 | return SUCCESS; 2318 | } 2319 | /* }}} */ 2320 | 2321 | /* {{{ PHP_MINFO_FUNCTION 2322 | */ 2323 | PHP_MINFO_FUNCTION(sync) 2324 | { 2325 | php_info_print_table_start(); 2326 | php_info_print_table_header(2, "sync support", "enabled"); 2327 | php_info_print_table_end(); 2328 | } 2329 | /* }}} */ 2330 | 2331 | /* 2332 | * Local variables: 2333 | * tab-width: 4 2334 | * c-basic-offset: 4 2335 | * End: 2336 | * vim600: noet sw=4 ts=4 fdm=marker 2337 | * vim<600: noet sw=4 ts=4 2338 | */ 2339 | -------------------------------------------------------------------------------- /tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for sync presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 9 | --EXPECT-- 10 | sync extension is available 11 | -------------------------------------------------------------------------------- /tests/002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncMutex - unnamed mutex allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock(0)); 10 | var_dump($mutex->lock(0)); 11 | var_dump($mutex->unlock()); 12 | var_dump($mutex->unlock()); 13 | var_dump($mutex->unlock()); 14 | ?> 15 | --EXPECT-- 16 | bool(true) 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(false) 21 | -------------------------------------------------------------------------------- /tests/003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncMutex - named mutex allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock(0)); 10 | var_dump($mutex->lock(0)); 11 | var_dump($mutex->unlock()); 12 | var_dump($mutex->unlock()); 13 | var_dump($mutex->unlock()); 14 | ?> 15 | --EXPECT-- 16 | bool(true) 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(false) 21 | -------------------------------------------------------------------------------- /tests/004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSemaphore (1) - unnamed semaphore allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock()); 10 | var_dump($semaphore->unlock()); 11 | var_dump($semaphore->lock()); 12 | $val = 5; 13 | var_dump($semaphore->unlock($val)); 14 | var_dump($val); 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | int(0) 22 | -------------------------------------------------------------------------------- /tests/005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSemaphore (2) - unnamed semaphore allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock()); 10 | var_dump($semaphore->unlock()); 11 | var_dump($semaphore->lock()); 12 | $val = 5; 13 | var_dump($semaphore->unlock($val)); 14 | var_dump($val); 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | int(1) 22 | -------------------------------------------------------------------------------- /tests/006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSemaphore (1) - named semaphore allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock()); 10 | var_dump($semaphore->unlock()); 11 | var_dump($semaphore->lock()); 12 | $val = 5; 13 | var_dump($semaphore->unlock($val)); 14 | var_dump($val); 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | int(0) 22 | -------------------------------------------------------------------------------- /tests/007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSemaphore (2) - named semaphore allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | lock()); 10 | var_dump($semaphore->unlock()); 11 | var_dump($semaphore->lock()); 12 | $val = 5; 13 | var_dump($semaphore->unlock($val)); 14 | var_dump($val); 15 | ?> 16 | --EXPECT-- 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | int(1) 22 | -------------------------------------------------------------------------------- /tests/008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncEvent - unnamed automatic event object allocation and firing. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | wait(0)); 10 | var_dump($event->fire()); 11 | var_dump($event->wait(0)); 12 | var_dump($event->wait(0)); 13 | ?> 14 | --EXPECT-- 15 | bool(false) 16 | bool(true) 17 | bool(true) 18 | bool(false) 19 | -------------------------------------------------------------------------------- /tests/009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncEvent - named automatic event object allocation and firing. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | wait(0)); 10 | var_dump($event->fire()); 11 | var_dump($event->wait(0)); 12 | var_dump($event->wait(0)); 13 | ?> 14 | --EXPECT-- 15 | bool(false) 16 | bool(true) 17 | bool(true) 18 | bool(false) 19 | -------------------------------------------------------------------------------- /tests/010.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncEvent - unnamed manual event object allocation and firing. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | wait(1)); 10 | var_dump($event->fire()); 11 | var_dump($event->wait(0)); 12 | var_dump($event->wait(0)); 13 | var_dump($event->reset()); 14 | var_dump($event->wait(0)); 15 | ?> 16 | --EXPECT-- 17 | bool(false) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | bool(true) 22 | bool(false) 23 | -------------------------------------------------------------------------------- /tests/011.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncEvent - named manual event object allocation and firing. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | wait(1)); 10 | var_dump($event->fire()); 11 | var_dump($event->wait(0)); 12 | var_dump($event->wait(0)); 13 | var_dump($event->reset()); 14 | var_dump($event->wait(0)); 15 | ?> 16 | --EXPECT-- 17 | bool(false) 18 | bool(true) 19 | bool(true) 20 | bool(true) 21 | bool(true) 22 | bool(false) 23 | -------------------------------------------------------------------------------- /tests/012.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncReaderWriter - unnamed reader-writer allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | readlock(0)); 10 | var_dump($readwrite->readlock(0)); 11 | var_dump($readwrite->readunlock()); 12 | var_dump($readwrite->writelock(0)); 13 | var_dump($readwrite->readunlock()); 14 | var_dump($readwrite->readunlock()); 15 | var_dump($readwrite->writelock(0)); 16 | var_dump($readwrite->writelock(0)); 17 | var_dump($readwrite->readlock(0)); 18 | var_dump($readwrite->writeunlock()); 19 | ?> 20 | --EXPECT-- 21 | bool(true) 22 | bool(true) 23 | bool(true) 24 | bool(false) 25 | bool(true) 26 | bool(false) 27 | bool(true) 28 | bool(false) 29 | bool(false) 30 | bool(true) 31 | -------------------------------------------------------------------------------- /tests/013.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncReaderWriter - named reader-writer allocation, locking, and unlocking. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | readlock(0)); 10 | var_dump($readwrite->readlock(0)); 11 | var_dump($readwrite->readunlock()); 12 | var_dump($readwrite->writelock(0)); 13 | var_dump($readwrite->readunlock()); 14 | var_dump($readwrite->readunlock()); 15 | var_dump($readwrite->writelock(0)); 16 | var_dump($readwrite->writelock(0)); 17 | var_dump($readwrite->readlock(0)); 18 | var_dump($readwrite->writeunlock()); 19 | ?> 20 | --EXPECT-- 21 | bool(true) 22 | bool(true) 23 | bool(true) 24 | bool(false) 25 | bool(true) 26 | bool(false) 27 | bool(true) 28 | bool(false) 29 | bool(false) 30 | bool(true) 31 | -------------------------------------------------------------------------------- /tests/014.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncReaderWriter - named reader-writer allocation, locking, and unlocking freeze test. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | readlock(0)); 10 | var_dump($readwrite->readlock(0)); 11 | var_dump($readwrite->readunlock()); 12 | var_dump($readwrite->writelock(0)); 13 | var_dump($readwrite->readunlock()); 14 | var_dump($readwrite->readunlock()); 15 | var_dump($readwrite->writelock(0)); 16 | var_dump($readwrite->writelock(0)); 17 | var_dump($readwrite->readlock(0)); 18 | var_dump($readwrite->writeunlock()); 19 | ?> 20 | --EXPECT-- 21 | bool(true) 22 | bool(true) 23 | bool(true) 24 | bool(false) 25 | bool(true) 26 | bool(false) 27 | bool(true) 28 | bool(false) 29 | bool(false) 30 | bool(true) 31 | -------------------------------------------------------------------------------- /tests/015.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSharedMemory - named shared memory allocation, size, reading, and writing test. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | first()); 10 | var_dump($shm->size()); 11 | var_dump($shm->write("Everything is awesome.", 1)); 12 | var_dump($shm->read(1, 22)); 13 | ?> 14 | --EXPECT-- 15 | bool(true) 16 | int(150) 17 | int(22) 18 | string(22) "Everything is awesome." 19 | -------------------------------------------------------------------------------- /tests/016.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | SyncSharedMemory - named shared memory allocation reuse test. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | first()); 10 | var_dump($shm->size()); 11 | var_dump($shm->write("Everything is awesome.", 1)); 12 | var_dump($shm->read(1, 22)); 13 | 14 | $shm2 = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150); 15 | 16 | var_dump($shm2->first()); 17 | var_dump($shm2->size()); 18 | var_dump($shm2->read(1, 22)); 19 | 20 | unset($shm2); 21 | unset($shm); 22 | 23 | // Should be brand new. 24 | $shm = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150); 25 | 26 | var_dump($shm->first()); 27 | var_dump($shm->size()); 28 | var_dump($shm->write("Everything is awesome.", 1)); 29 | var_dump($shm->read(1, 22)); 30 | ?> 31 | --EXPECT-- 32 | bool(true) 33 | int(150) 34 | int(22) 35 | string(22) "Everything is awesome." 36 | bool(false) 37 | int(150) 38 | string(22) "Everything is awesome." 39 | bool(true) 40 | int(150) 41 | int(22) 42 | string(22) "Everything is awesome." 43 | --------------------------------------------------------------------------------