diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/sysvsem | |
download | php2-c4dd7a1a684490673e25aaf4fabec5df138854c4.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/sysvsem')
-rw-r--r-- | ext/sysvsem/CREDITS | 2 | ||||
-rw-r--r-- | ext/sysvsem/config.m4 | 29 | ||||
-rw-r--r-- | ext/sysvsem/package.xml | 39 | ||||
-rw-r--r-- | ext/sysvsem/php_sysvsem.h | 57 | ||||
-rw-r--r-- | ext/sysvsem/sysvsem.c | 408 | ||||
-rw-r--r-- | ext/sysvsem/tests/sysv.phpt | 112 |
6 files changed, 647 insertions, 0 deletions
diff --git a/ext/sysvsem/CREDITS b/ext/sysvsem/CREDITS new file mode 100644 index 0000000..4523280 --- /dev/null +++ b/ext/sysvsem/CREDITS @@ -0,0 +1,2 @@ +System V Semaphores +Tom May diff --git a/ext/sysvsem/config.m4 b/ext/sysvsem/config.m4 new file mode 100644 index 0000000..bfb5d92 --- /dev/null +++ b/ext/sysvsem/config.m4 @@ -0,0 +1,29 @@ +dnl +dnl $Id$ +dnl + +PHP_ARG_ENABLE(sysvsem,whether to enable System V semaphore support, +[ --enable-sysvsem Enable System V semaphore support]) + +if test "$PHP_SYSVSEM" != "no"; then + PHP_NEW_EXTENSION(sysvsem, sysvsem.c, $ext_shared) + AC_DEFINE(HAVE_SYSVSEM, 1, [ ]) + AC_CACHE_CHECK(for union semun,php_cv_semun, + AC_TRY_COMPILE([ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> + ], + [union semun x;], + [ + php_cv_semun=yes + ],[ + php_cv_semun=no + ]) + ) + if test "$php_cv_semun" = "yes"; then + AC_DEFINE(HAVE_SEMUN, 1, [ ]) + else + AC_DEFINE(HAVE_SEMUN, 0, [ ]) + fi +fi diff --git a/ext/sysvsem/package.xml b/ext/sysvsem/package.xml new file mode 100644 index 0000000..6c40af0 --- /dev/null +++ b/ext/sysvsem/package.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE package SYSTEM "../pear/package.dtd"> +<package> + <name>sysvsem</name> + <summary>Unix System V IPC Semaphores</summary> + <maintainers> + <maintainer> + <user>???</user> + <name>Tom May</name> + <email>tom@go2net.com</email> + <role>lead</role> + </maintainer> + </maintainers> + <description> +Unix System V IPC Semaphores + </description> + <license>PHP</license> + <release> + <state>beta</state> + <version>5.0.0rc1</version> + <date>2004-03-19</date> + <notes> +package.xml added to support installation using pear installer + </notes> + <filelist> + <file role="doc" name="CREDITS"/> + <file role="src" name="config.m4"/> + <file role="src" name="sysvsem.c"/> + <file role="src" name="php_sysvsem.h"/> + </filelist> + <deps> + <dep type="php" rel="ge" version="5" /> + <!-- doesn't work yet <dep type="os" rel="has" name="unix"/> --> + </deps> + </release> +</package> +<!-- +vim:et:ts=1:sw=1 +--> diff --git a/ext/sysvsem/php_sysvsem.h b/ext/sysvsem/php_sysvsem.h new file mode 100644 index 0000000..c4598f5 --- /dev/null +++ b/ext/sysvsem/php_sysvsem.h @@ -0,0 +1,57 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tom May <tom@go2net.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_SYSVSEM_H +#define PHP_SYSVSEM_H + +#if HAVE_SYSVSEM + +extern zend_module_entry sysvsem_module_entry; +#define sysvsem_module_ptr &sysvsem_module_entry + +PHP_MINIT_FUNCTION(sysvsem); +PHP_FUNCTION(sem_get); +PHP_FUNCTION(sem_acquire); +PHP_FUNCTION(sem_release); +PHP_FUNCTION(sem_remove); + +typedef struct { + int le_sem; +} sysvsem_module; + +typedef struct { + int id; /* For error reporting. */ + int key; /* For error reporting. */ + int semid; /* Returned by semget(). */ + int count; /* Acquire count for auto-release. */ + int auto_release; /* flag that says to auto-release. */ +} sysvsem_sem; + +extern sysvsem_module php_sysvsem_module; + +#else + +#define sysvsem_module_ptr NULL + +#endif + +#define phpext_sysvsem_ptr sysvsem_module_ptr + +#endif /* PHP_SYSVSEM_H */ diff --git a/ext/sysvsem/sysvsem.c b/ext/sysvsem/sysvsem.c new file mode 100644 index 0000000..b6e5ccb --- /dev/null +++ b/ext/sysvsem/sysvsem.c @@ -0,0 +1,408 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Tom May <tom@go2net.com> | + | Gavin Sherry <gavin@linuxworld.com.au> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +/* Latest update build anc tested on Linux 2.2.14 + * + * This has been built and tested on Solaris 2.6 and Linux 2.1.122. + * It may not compile or execute correctly on other systems. + * + * sas: Works for me on Linux 2.0.36 and FreeBSD 3.0-current + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +#if HAVE_SYSVSEM + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <errno.h> + +#include "php_sysvsem.h" + +#if !HAVE_SEMUN + +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short int *array; /* array for GETALL, SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; + +#undef HAVE_SEMUN +#define HAVE_SEMUN 1 + +#endif + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_get, 0, 0, 1) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, max_acquire) + ZEND_ARG_INFO(0, perm) + ZEND_ARG_INFO(0, auto_release) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_acquire, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_release, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_remove, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ sysvsem_functions[] + */ +const zend_function_entry sysvsem_functions[] = { + PHP_FE(sem_get, arginfo_sem_get) + PHP_FE(sem_acquire, arginfo_sem_acquire) + PHP_FE(sem_release, arginfo_sem_release) + PHP_FE(sem_remove, arginfo_sem_remove) + PHP_FE_END +}; +/* }}} */ + +/* {{{ sysvsem_module_entry + */ +zend_module_entry sysvsem_module_entry = { + STANDARD_MODULE_HEADER, + "sysvsem", + sysvsem_functions, + PHP_MINIT(sysvsem), + NULL, + NULL, + NULL, + NULL, + NO_VERSION_YET, + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_SYSVSEM +ZEND_GET_MODULE(sysvsem) +#endif + + +THREAD_LS sysvsem_module php_sysvsem_module; + +/* Semaphore functions using System V semaphores. Each semaphore + * actually consists of three semaphores allocated as a unit under the + * same key. Semaphore 0 (SYSVSEM_SEM) is the actual semaphore, it is + * initialized to max_acquire and decremented as processes acquire it. + * The value of semaphore 1 (SYSVSEM_USAGE) is a count of the number + * of processes using the semaphore. After calling semget(), if a + * process finds that the usage count is 1, it will set the value of + * SYSVSEM_SEM to max_acquire. This allows max_acquire to be set and + * track the PHP code without having a global init routine or external + * semaphore init code. Except see the bug regarding a race condition + * php_sysvsem_get(). Semaphore 2 (SYSVSEM_SETVAL) serializes the + * calls to GETVAL SYSVSEM_USAGE and SETVAL SYSVSEM_SEM. It can be + * acquired only when it is zero. + */ + +#define SYSVSEM_SEM 0 +#define SYSVSEM_USAGE 1 +#define SYSVSEM_SETVAL 2 + +/* {{{ release_sysvsem_sem + */ +static void release_sysvsem_sem(zend_rsrc_list_entry *rsrc TSRMLS_DC) +{ + sysvsem_sem *sem_ptr = (sysvsem_sem *)rsrc->ptr; + struct sembuf sop[2]; + int opcount = 1; +/* + * if count == -1, semaphore has been removed + * Need better way to handle this + */ + + if (sem_ptr->count == -1 || !sem_ptr->auto_release) { + efree(sem_ptr); + return; + } + /* Decrement the usage count. */ + + sop[0].sem_num = SYSVSEM_USAGE; + sop[0].sem_op = -1; + sop[0].sem_flg = SEM_UNDO; + + /* Release the semaphore if it has been acquired but not released. */ + + if (sem_ptr->count) { + + sop[1].sem_num = SYSVSEM_SEM; + sop[1].sem_op = sem_ptr->count; + sop[1].sem_flg = SEM_UNDO; + + opcount++; + } + + semop(sem_ptr->semid, sop, opcount); + efree(sem_ptr); +} +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(sysvsem) +{ + php_sysvsem_module.le_sem = zend_register_list_destructors_ex(release_sysvsem_sem, NULL, "sysvsem", module_number); + return SUCCESS; +} +/* }}} */ + +#define SETVAL_WANTS_PTR + +#if defined(_AIX) +#undef SETVAL_WANTS_PTR +#endif + +/* {{{ proto resource sem_get(int key [, int max_acquire [, int perm [, int auto_release]]) + Return an id for the semaphore with the given key, and allow max_acquire (default 1) processes to acquire it simultaneously */ +PHP_FUNCTION(sem_get) +{ + long key, max_acquire = 1, perm = 0666, auto_release = 1; + int semid; + struct sembuf sop[3]; + int count; + sysvsem_sem *sem_ptr; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|lll", &key, &max_acquire, &perm, &auto_release)) { + RETURN_FALSE; + } + + /* Get/create the semaphore. Note that we rely on the semaphores + * being zeroed when they are created. Despite the fact that + * the(?) Linux semget() man page says they are not initialized, + * the kernel versions 2.0.x and 2.1.z do in fact zero them. + */ + + semid = semget(key, 3, perm|IPC_CREAT); + if (semid == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno)); + RETURN_FALSE; + } + + /* Find out how many processes are using this semaphore. Note + * that on Linux (at least) there is a race condition here because + * semaphore undo on process exit is not atomic, so we could + * acquire SYSVSEM_SETVAL before a crashed process has decremented + * SYSVSEM_USAGE in which case count will be greater than it + * should be and we won't set max_acquire. Fortunately this + * doesn't actually matter in practice. + */ + + /* Wait for sem 1 to be zero . . . */ + + sop[0].sem_num = SYSVSEM_SETVAL; + sop[0].sem_op = 0; + sop[0].sem_flg = 0; + + /* . . . and increment it so it becomes non-zero . . . */ + + sop[1].sem_num = SYSVSEM_SETVAL; + sop[1].sem_op = 1; + sop[1].sem_flg = SEM_UNDO; + + /* . . . and increment the usage count. */ + + sop[2].sem_num = SYSVSEM_USAGE; + sop[2].sem_op = 1; + sop[2].sem_flg = SEM_UNDO; + while (semop(semid, sop, 3) == -1) { + if (errno != EINTR) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed acquiring SYSVSEM_SETVAL for key 0x%lx: %s", key, strerror(errno)); + break; + } + } + + /* Get the usage count. */ + count = semctl(semid, SYSVSEM_USAGE, GETVAL, NULL); + if (count == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno)); + } + + /* If we are the only user, then take this opportunity to set the max. */ + + if (count == 1) { +#if HAVE_SEMUN + /* This is correct for Linux which has union semun. */ + union semun semarg; + semarg.val = max_acquire; + if (semctl(semid, SYSVSEM_SEM, SETVAL, semarg) == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno)); + } +#elif defined(SETVAL_WANTS_PTR) + /* This is correct for Solaris 2.6 which does not have union semun. */ + if (semctl(semid, SYSVSEM_SEM, SETVAL, &max_acquire) == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno)); + } +#else + /* This works for i.e. AIX */ + if (semctl(semid, SYSVSEM_SEM, SETVAL, max_acquire) == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno)); + } +#endif + } + + /* Set semaphore 1 back to zero. */ + + sop[0].sem_num = SYSVSEM_SETVAL; + sop[0].sem_op = -1; + sop[0].sem_flg = SEM_UNDO; + while (semop(semid, sop, 1) == -1) { + if (errno != EINTR) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed releasing SYSVSEM_SETVAL for key 0x%lx: %s", key, strerror(errno)); + break; + } + } + + sem_ptr = (sysvsem_sem *) emalloc(sizeof(sysvsem_sem)); + sem_ptr->key = key; + sem_ptr->semid = semid; + sem_ptr->count = 0; + sem_ptr->auto_release = auto_release; + + sem_ptr->id = ZEND_REGISTER_RESOURCE(return_value, sem_ptr, php_sysvsem_module.le_sem); +} +/* }}} */ + +/* {{{ php_sysvsem_semop + */ +static void php_sysvsem_semop(INTERNAL_FUNCTION_PARAMETERS, int acquire) +{ + zval *arg_id; + sysvsem_sem *sem_ptr; + struct sembuf sop; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg_id) == FAILURE) { + return; + } + + ZEND_FETCH_RESOURCE(sem_ptr, sysvsem_sem *, &arg_id, -1, "SysV semaphore", php_sysvsem_module.le_sem); + + if (!acquire && sem_ptr->count == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SysV semaphore %ld (key 0x%x) is not currently acquired", Z_LVAL_P(arg_id), sem_ptr->key); + RETURN_FALSE; + } + + sop.sem_num = SYSVSEM_SEM; + sop.sem_op = acquire ? -1 : 1; + sop.sem_flg = SEM_UNDO; + + while (semop(sem_ptr->semid, &sop, 1) == -1) { + if (errno != EINTR) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to %s key 0x%x: %s", acquire ? "acquire" : "release", sem_ptr->key, strerror(errno)); + RETURN_FALSE; + } + } + + sem_ptr->count -= acquire ? -1 : 1; + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool sem_acquire(resource id) + Acquires the semaphore with the given id, blocking if necessary */ +PHP_FUNCTION(sem_acquire) +{ + php_sysvsem_semop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + +/* {{{ proto bool sem_release(resource id) + Releases the semaphore with the given id */ +PHP_FUNCTION(sem_release) +{ + php_sysvsem_semop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto bool sem_remove(resource id) + Removes semaphore from Unix systems */ + +/* + * contributed by Gavin Sherry gavin@linuxworld.com.au + * Fri Mar 16 00:50:13 EST 2001 + */ + +PHP_FUNCTION(sem_remove) +{ + zval *arg_id; + sysvsem_sem *sem_ptr; +#if HAVE_SEMUN + union semun un; + struct semid_ds buf; +#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg_id) == FAILURE) { + return; + } + + ZEND_FETCH_RESOURCE(sem_ptr, sysvsem_sem *, &arg_id, -1, "SysV semaphore", php_sysvsem_module.le_sem); + +#if HAVE_SEMUN + un.buf = &buf; + if (semctl(sem_ptr->semid, 0, IPC_STAT, un) < 0) { +#else + if (semctl(sem_ptr->semid, 0, IPC_STAT, NULL) < 0) { +#endif + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SysV semaphore %ld does not (any longer) exist", Z_LVAL_P(arg_id)); + RETURN_FALSE; + } + +#if HAVE_SEMUN + if (semctl(sem_ptr->semid, 0, IPC_RMID, un) < 0) { +#else + if (semctl(sem_ptr->semid, 0, IPC_RMID, NULL) < 0) { +#endif + php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for SysV sempphore %ld: %s", Z_LVAL_P(arg_id), strerror(errno)); + RETURN_FALSE; + } + + /* let release_sysvsem_sem know we have removed + * the semaphore to avoid issues with releasing. + */ + + sem_ptr->count = -1; + RETURN_TRUE; +} + +/* }}} */ + +#endif /* HAVE_SYSVSEM */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/ext/sysvsem/tests/sysv.phpt b/ext/sysvsem/tests/sysv.phpt new file mode 100644 index 0000000..3a962be --- /dev/null +++ b/ext/sysvsem/tests/sysv.phpt @@ -0,0 +1,112 @@ +--TEST-- +General semaphore and shared memory test +--SKIPIF-- +<?php // vim600: ts=4 sw=4 syn=php fdm=marker +if(!extension_loaded('sysvsem') || !extension_loaded('sysvshm')) { + die("skip Both sysvsem and sysvshm required"); +} +?> +--FILE-- +<?php +$MEMSIZE = 512; // size of shared memory to allocate +$SEMKEY = 1; // Semaphore key +$SHMKEY = 2; // Shared memory key + +echo "Start.\n"; +// Get semaphore +$sem_id = sem_get($SEMKEY, 1); +if ($sem_id === FALSE) { + echo "Fail to get semaphore"; + exit; +} +echo "Got semaphore $sem_id.\n"; + +// Accuire semaphore +if (! sem_acquire($sem_id)) { + echo "Fail to aquire semaphore $sem_id.\n"; + sem_remove($sem_id); + exit; +} +echo "Success aquire semaphore $sem_id.\n"; + +$shm_id = shm_attach($SHMKEY, $MEMSIZE); +if ($shm_id === FALSE) { + echo "Fail to attach shared memory.\n"; + sem_remove($sem_id); + exit; +} +echo "Success to attach shared memory : $shm_id.\n"; + +// Write variable 1 +if (!shm_put_var($shm_id, 1, "Variable 1")) { + echo "Fail to put var 1 on shared memory $shm_id.\n"; + sem_remove($sem_id); + shm_remove ($shm_id); + exit; +} +echo "Write var1 to shared memory.\n"; + +// Write variable 2 +if (!shm_put_var($shm_id, 2, "Variable 2")) { + echo "Fail to put var 2 on shared memory $shm_id.\n"; + sem_remove($sem_id); + shm_remove ($shm_id); + exit; +} +echo "Write var2 to shared memory.\n"; + +// Read variable 1 +$var1 = shm_get_var ($shm_id, 1); +if ($var1 === FALSE) { + echo "Fail to retrieve Var 1 from Shared memory $shm_id, return value=$var1.\n"; +} else { + echo "Read var1=$var1.\n"; +} + +// Read variable 1 +$var2 = shm_get_var ($shm_id, 2); +if ($var1 === FALSE) { + echo "Fail to retrieve Var 2 from Shared memory $shm_id, return value=$var2.\n"; +} else { + echo "Read var2=$var2.\n"; +} +// Release semaphore +if (!sem_release($sem_id)) { + echo "Fail to release $sem_id semaphore.\n"; +} else { + echo "Semaphore $sem_id released.\n"; +} + +// remove shared memory segmant from SysV +if (shm_remove ($shm_id)) { + echo "Shared memory successfully removed from SysV.\n"; +} else { + echo "Fail to remove $shm_id shared memory from SysV.\n"; +} + +// Remove semaphore +if (sem_remove($sem_id)) { + echo "semaphore removed successfully from SysV.\n"; +} else { + echo "Fail to remove $sem_id semaphore from SysV.\n"; +} +echo "End.\n"; +/* NOTE: assigned semids differ depending on the kernel, since + * there are actually 3 semaphores per PHP-created + * semaphores in effect, to keep state information. + * That's the reason for EXPECTF. + */ +?> +--EXPECTF-- +Start. +Got semaphore Resource id #%i. +Success aquire semaphore Resource id #%i. +Success to attach shared memory : %s. +Write var1 to shared memory. +Write var2 to shared memory. +Read var1=Variable 1. +Read var2=Variable 2. +Semaphore Resource id #%s released. +Shared memory successfully removed from SysV. +semaphore removed successfully from SysV. +End. |