Added named shared memory support via SyncSharedMemory. Ported latest code from upstream for Mac OSX support and better overall resource usage. Fixed null name issue. Fixed memory leak issue. Added PHP 7 support.

This commit is contained in:
cubiclesoft
2016-11-26 19:21:51 -07:00
parent d64b86c971
commit dc2d7f73d0
14 changed files with 1404 additions and 526 deletions

View File

@@ -1,7 +1,9 @@
CubicleSoft PHP Extension: Synchronization Objects (sync)
==========================================================
The 'sync' extension introduces synchronization objects into PHP. Named and unnamed Mutex, Semaphore, Event, and Reader-Writer objects provide OS-level synchronization on both *NIX (POSIX semaphores required) and Windows platforms. The extension comes with a test suite that integrates cleanly into 'make test'.
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'.
The 'sync' extension is a direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp
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.
@@ -14,7 +16,7 @@ All synchronization objects are attempted to be unlocked cleanly within PHP itse
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).
```
````
void SyncMutex::__construct([string $name = null])
Constructs a named or unnamed mutex object.
@@ -35,7 +37,7 @@ bool SyncSemaphore::unlock([int &$prevcount])
Unlocks a semaphore object.
void SyncEvent::__construct([string $name = null, [bool $manual = false]])
void SyncEvent::__construct([string $name = null, [bool $manual = false], [bool $prefire = false]])
Constructs a named or unnamed event object.
bool SyncEvent::wait([int $wait = -1])
@@ -62,7 +64,23 @@ bool SyncReaderWriter::readunlock()
bool SyncReaderWriter::writeunlock()
Write unlocks a reader-writer object.
```
void SyncSharedMemory::__construct(string $name, int $size)
Constructs a named shared memory object.
bool SyncSharedMemory::first()
Returns whether or not this shared memory segment is the first time accessed (i.e. not initialized).
int SyncSharedMemory::size()
Returns the shared memory size.
int SyncSharedMemory::write(string $string, [int $start = 0])
Copies data to shared memory.
string SyncSharedMemory::read([int $start = 0, [int $length = null]])
Copies data from shared memory.
````
Usage Examples
--------------
@@ -94,7 +112,7 @@ $mutex2->unlock();
Example Semaphore usage:
```php
$semaphore = new SyncSemaphore("LimitedResource_2clients", 2);
$semaphore = new SyncSemaphore("LimitedResource_2_clients", 2);
if (!$semaphore->lock(3000))
{
@@ -132,3 +150,17 @@ $readwrite->writelock();
...
$readwrite->writeunlock();
```
Example Shared Memory usage:
```php
// You will probably need to protect shared memory with other synchronization objects.
// Shared memory goes away when the last reference to it disappears.
$mem = new SyncSharedMemory("AppReportName", 1024);
if ($mem->first())
{
// Do first time initialization work here.
}
$result = $mem->write(json_encode(array("name" => "my_report.txt")));
```

View File

@@ -5,22 +5,22 @@ PHP_ARG_ENABLE(sync, whether to enable synchronization object support (--enable-
[ --enable-sync Enable synchronization object support])
if test "$PHP_SYNC" != "no"; then
dnl # Check for sem_open() support.
AC_MSG_CHECKING([for sem_open in -pthread -lrt])
dnl # Check for shm_open() support.
AC_MSG_CHECKING([for shm_open in -pthread -lrt])
SAVED_LIBS="$LIBS"
LIBS="$LIBS -pthread -lrt"
AC_TRY_LINK([
#include <fcntl.h>
#include <semaphore.h>
#include <sys/mman.h>
], [
sem_t *MxSemMutex = sem_open("", O_CREAT, 0666, 1);
int fp = shm_open("", O_RDWR | O_CREAT | O_EXCL, 0666);
], [
have_sem_open=yes
have_shm_open=yes
AC_MSG_RESULT([yes])
], [
AC_MSG_ERROR([sem_open() is not available on this platform])
AC_MSG_ERROR([shm_open() is not available on this platform])
])
PHP_ADD_LIBRARY(rt,,SYNC_SHARED_LIBADD)

View File

@@ -3,18 +3,18 @@
<name>sync</name>
<channel>pecl.php.net</channel>
<summary>Named and unnamed synchronization objects</summary>
<description>The 'sync' extension introduces synchronization objects into PHP. Named and unnamed Mutex, Semaphore, Event, and Reader-Writer objects provide OS-level synchronization on both *NIX (POSIX semaphores required) and Windows platforms.</description>
<description>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</description>
<lead>
<name>Thomas Hruska</name>
<user>cubic</user>
<email>cubic@php.net</email>
<active>yes</active>
</lead>
<date>2014-07-25</date>
<time>08:00:00</time>
<date>2016-11-26</date>
<time>19:00:00</time>
<version>
<release>1.0.1</release>
<api>1.0.0</api>
<release>1.1.0</release>
<api>1.1.0</api>
</version>
<stability>
<release>stable</release>
@@ -22,8 +22,12 @@
</stability>
<license uri="http://opensource.org/licenses/MIT">MIT License</license>
<notes>
- Fixed Reader-Writer objects.
- Removed a lead from package maintainers list.
- Added cross-platform named shared memory objects.
- Rewrote *NIX objects to be much lighter on shared resources.
- Fixed null name issue.
- Fixed object memory leak issue.
- Now works on Mac OSX.
- Now works on PHP 7. The same code base also works on PHP 5.
</notes>
<contents>
<dir name="/">
@@ -41,6 +45,8 @@
<file name="tests/012.phpt" role="test" />
<file name="tests/013.phpt" role="test" />
<file name="tests/014.phpt" role="test" />
<file name="tests/015.phpt" role="test" />
<file name="tests/016.phpt" role="test" />
<file name="CREDITS" role="doc" />
<file name="LICENSE" role="doc" />
<file name="README.md" role="doc" />

View File

@@ -1,7 +1,7 @@
/*
Direct port of the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp
This source file is under the MIT, LGPL, or version 3.01 of the PHP license, your choice.
(C) 2014 CubicleSoft. All rights reserved.
Direct port of and compatible with the cross platform 'sync' library: https://github.com/cubiclesoft/cross-platform-cpp
This source file is under the MIT license.
(C) 2016 CubicleSoft. All rights reserved.
*/
/* $Id$ */
@@ -12,7 +12,7 @@
extern zend_module_entry sync_module_entry;
#define phpext_sync_ptr &sync_module_entry
#define PHP_SYNC_VERSION "1.0.1"
#define PHP_SYNC_VERSION "1.1.0"
#ifdef PHP_WIN32
# define PHP_SYNC_API __declspec(dllexport)
@@ -29,6 +29,7 @@ extern zend_module_entry sync_module_entry;
#ifdef PHP_WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -36,8 +37,20 @@ extern zend_module_entry sync_module_entry;
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <limits.h>
#ifdef __APPLE__
#include <mach/clock.h>
#include <mach/mach.h>
#ifndef SHM_NAME_MAX
# define SHM_NAME_MAX 31
#endif
#else
#ifndef SHM_NAME_MAX
# define SHM_NAME_MAX 255
#endif
#endif
#endif
PHP_MINIT_FUNCTION(sync);
@@ -50,9 +63,45 @@ typedef DWORD sync_ThreadIDType;
typedef pthread_t sync_ThreadIDType;
#endif
#if PHP_MAJOR_VERSION >= 7
#define PHP_SYNC_PHP_5_zend_object_std
#define PHP_SYNC_PHP_7_zend_object_std zend_object std;
#else
#define PHP_SYNC_PHP_5_zend_object_std zend_object std;
#define PHP_SYNC_PHP_7_zend_object_std
#endif
/* Generic structures */
#if defined(PHP_WIN32)
/* Nothing for Windows at the moment. */
#else
/* Some platforms are broken even for unnamed semaphores (e.g. Mac OSX). */
/* This allows for implementing all semaphores directly, bypassing POSIX semaphores. */
typedef struct _sync_UnixSemaphoreWrapper {
pthread_mutex_t *MxMutex;
volatile uint32_t *MxCount;
volatile uint32_t *MxMax;
pthread_cond_t *MxCond;
} sync_UnixSemaphoreWrapper;
/* Implements a more efficient (and portable) event object interface than trying to use semaphores. */
typedef struct _sync_UnixEventWrapper {
pthread_mutex_t *MxMutex;
volatile char *MxManual;
volatile char *MxSignaled;
volatile uint32_t *MxWaiting;
pthread_cond_t *MxCond;
} sync_UnixEventWrapper;
#endif
/* Mutex */
typedef struct _sync_Mutex_object {
zend_object std;
PHP_SYNC_PHP_5_zend_object_std
#if defined(PHP_WIN32)
CRITICAL_SECTION MxWinCritSection;
@@ -61,61 +110,94 @@ typedef struct _sync_Mutex_object {
#else
pthread_mutex_t MxPthreadCritSection;
sem_t *MxSemMutex;
int MxAllocated;
int MxNamed;
char *MxMem;
sync_UnixSemaphoreWrapper MxPthreadMutex;
#endif
volatile sync_ThreadIDType MxOwnerID;
volatile unsigned int MxCount;
PHP_SYNC_PHP_7_zend_object_std
} sync_Mutex_object;
/* Semaphore */
typedef struct _sync_Semaphore_object {
zend_object std;
PHP_SYNC_PHP_5_zend_object_std
#if defined(PHP_WIN32)
HANDLE MxWinSemaphore;
#else
sem_t *MxSemSemaphore;
int MxAllocated;
int MxNamed;
char *MxMem;
sync_UnixSemaphoreWrapper MxPthreadSemaphore;
#endif
int MxAutoUnlock;
volatile unsigned int MxCount;
PHP_SYNC_PHP_7_zend_object_std
} sync_Semaphore_object;
/* Event */
typedef struct _sync_Event_object {
zend_object std;
PHP_SYNC_PHP_5_zend_object_std
#if defined(PHP_WIN32)
HANDLE MxWinWaitEvent;
#else
sem_t *MxSemWaitMutex, *MxSemWaitEvent, *MxSemWaitCount, *MxSemWaitStatus;
int MxAllocated;
int MxManual;
int MxNamed;
char *MxMem;
sync_UnixEventWrapper MxPthreadEvent;
#endif
PHP_SYNC_PHP_7_zend_object_std
} sync_Event_object;
/* Reader-Writer */
typedef struct _sync_ReaderWriter_object {
zend_object std;
PHP_SYNC_PHP_5_zend_object_std
#if defined(PHP_WIN32)
HANDLE MxWinRSemMutex, MxWinRSemaphore, MxWinRWaitEvent, MxWinWWaitMutex;
#else
sem_t *MxSemRSemMutex, *MxSemRSemaphore, *MxSemRWaitEvent, *MxSemWWaitMutex;
int MxAllocated;
int MxNamed;
char *MxMem;
sync_UnixSemaphoreWrapper MxPthreadRCountMutex;
volatile uint32_t *MxRCount;
sync_UnixEventWrapper MxPthreadRWaitEvent;
sync_UnixSemaphoreWrapper MxPthreadWWaitMutex;
#endif
int MxAutoUnlock;
volatile unsigned int MxReadLocks, MxWriteLock;
PHP_SYNC_PHP_7_zend_object_std
} sync_ReaderWriter_object;
/* Named shared memory */
typedef struct _sync_SharedMemory_object {
PHP_SYNC_PHP_5_zend_object_std
int MxFirst;
size_t MxSize;
char *MxMem;
#if defined(PHP_WIN32)
HANDLE MxFile;
#else
char *MxMemInternal;
#endif
PHP_SYNC_PHP_7_zend_object_std
} sync_SharedMemory_object;
#endif /* PHP_SYNC_H */

1664
sync.c

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ SyncMutex - named mutex allocation, locking, and unlocking.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$mutex = new SyncMutex("Awesome_".PHP_INT_SIZE);
$mutex = new SyncMutex("Awesome_" . PHP_INT_SIZE);
var_dump($mutex->lock(0));
var_dump($mutex->lock(0));

View File

@@ -4,7 +4,7 @@ SyncSemaphore (1) - named semaphore allocation, locking, and unlocking.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$semaphore = new SyncSemaphore("Awesome_".PHP_INT_SIZE);
$semaphore = new SyncSemaphore("Awesome_" . PHP_INT_SIZE);
var_dump($semaphore->lock());
var_dump($semaphore->unlock());

View File

@@ -4,7 +4,7 @@ SyncSemaphore (2) - named semaphore allocation, locking, and unlocking.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$semaphore = new SyncSemaphore("Awesome2_".PHP_INT_SIZE, 2);
$semaphore = new SyncSemaphore("Awesome2_" . PHP_INT_SIZE, 2);
var_dump($semaphore->lock());
var_dump($semaphore->unlock());

View File

@@ -4,7 +4,7 @@ SyncEvent - named automatic event object allocation and firing.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$event = new SyncEvent("Awesome_".PHP_INT_SIZE);
$event = new SyncEvent("Awesome_" . PHP_INT_SIZE);
var_dump($event->wait(0));
var_dump($event->fire());

View File

@@ -4,7 +4,7 @@ SyncEvent - named manual event object allocation and firing.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$event = new SyncEvent("Awesome2_".PHP_INT_SIZE, true);
$event = new SyncEvent("Awesome2_" . PHP_INT_SIZE, true);
var_dump($event->wait(0));
var_dump($event->fire());

View File

@@ -4,7 +4,7 @@ SyncReaderWriter - named reader-writer allocation, locking, and unlocking.
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$readwrite = new SyncReaderWriter("Awesome_".PHP_INT_SIZE);
$readwrite = new SyncReaderWriter("Awesome_" . PHP_INT_SIZE);
var_dump($readwrite->readlock(0));
var_dump($readwrite->readlock(0));

View File

@@ -4,7 +4,7 @@ SyncReaderWriter - named reader-writer allocation, locking, and unlocking freeze
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$readwrite = new SyncReaderWriter("Awesome_".PHP_INT_SIZE);
$readwrite = new SyncReaderWriter("Awesome_" . PHP_INT_SIZE);
var_dump($readwrite->readlock(0));
var_dump($readwrite->readlock(0));

18
tests/015.phpt Normal file
View File

@@ -0,0 +1,18 @@
--TEST--
SyncSharedMemory - named shared memory allocation, size, reading, and writing test.
--SKIPIF--
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$shm = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150);
var_dump($shm->first());
var_dump($shm->size());
var_dump($shm->write("Everything is awesome.", 1));
var_dump($shm->read(1, 22));
?>
--EXPECT--
bool(true)
int(150)
int(22)
string(22) "Everything is awesome."

42
tests/016.phpt Normal file
View File

@@ -0,0 +1,42 @@
--TEST--
SyncSharedMemory - named shared memory allocation reuse test.
--SKIPIF--
<?php if (!extension_loaded("sync")) echo "skip"; ?>
--FILE--
<?php
$shm = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150);
var_dump($shm->first());
var_dump($shm->size());
var_dump($shm->write("Everything is awesome.", 1));
var_dump($shm->read(1, 22));
$shm2 = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150);
var_dump($shm2->first());
var_dump($shm2->size());
var_dump($shm2->read(1, 22));
unset($shm2);
unset($shm);
// Should be brand new.
$shm = new SyncSharedMemory("Awesome_" . PHP_INT_SIZE, 150);
var_dump($shm->first());
var_dump($shm->size());
var_dump($shm->write("Everything is awesome.", 1));
var_dump($shm->read(1, 22));
?>
--EXPECT--
bool(true)
int(150)
int(22)
string(22) "Everything is awesome."
bool(false)
int(150)
string(22) "Everything is awesome."
bool(true)
int(150)
int(22)
string(22) "Everything is awesome."