PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/sysvsem - sysvsem.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 63 95 66.3 %
Date: 2014-10-24 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Tom May <tom@go2net.com>                                    |
      16             :    |          Gavin Sherry <gavin@linuxworld.com.au>                      |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             :  
      20             : /* $Id$ */
      21             : 
      22             : /* Latest update build anc tested on Linux 2.2.14
      23             :  *
      24             :  * This has been built and tested on Solaris 2.6 and Linux 2.1.122.
      25             :  * It may not compile or execute correctly on other systems.
      26             :  *
      27             :  * sas: Works for me on Linux 2.0.36 and FreeBSD 3.0-current
      28             :  */
      29             : 
      30             : #ifdef HAVE_CONFIG_H
      31             : #include "config.h"
      32             : #endif
      33             : 
      34             : #include "php.h"
      35             : 
      36             : #if HAVE_SYSVSEM
      37             : 
      38             : #include <sys/types.h>
      39             : #include <sys/ipc.h>
      40             : #include <sys/sem.h>
      41             : #include <errno.h>
      42             : 
      43             : #include "php_sysvsem.h"
      44             : 
      45             : #if !HAVE_SEMUN
      46             : 
      47             : union semun {
      48             :         int val;                    /* value for SETVAL */
      49             :         struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
      50             :         unsigned short int *array;  /* array for GETALL, SETALL */
      51             :         struct seminfo *__buf;      /* buffer for IPC_INFO */
      52             : };
      53             : 
      54             : #undef HAVE_SEMUN
      55             : #define HAVE_SEMUN 1
      56             : 
      57             : #endif
      58             : 
      59             : /* {{{ arginfo */
      60             : ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_get, 0, 0, 1)
      61             :         ZEND_ARG_INFO(0, key)
      62             :         ZEND_ARG_INFO(0, max_acquire)
      63             :         ZEND_ARG_INFO(0, perm)
      64             :         ZEND_ARG_INFO(0, auto_release)
      65             : ZEND_END_ARG_INFO()
      66             : 
      67             : ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_acquire, 0, 0, 1)
      68             :         ZEND_ARG_INFO(0, sem_identifier)
      69             : ZEND_END_ARG_INFO()
      70             : 
      71             : ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_release, 0, 0, 1)
      72             :         ZEND_ARG_INFO(0, sem_identifier)
      73             : ZEND_END_ARG_INFO()
      74             : 
      75             : ZEND_BEGIN_ARG_INFO_EX(arginfo_sem_remove, 0, 0, 1)
      76             :         ZEND_ARG_INFO(0, sem_identifier)
      77             : ZEND_END_ARG_INFO()
      78             : /* }}} */
      79             : 
      80             : /* {{{ sysvsem_functions[]
      81             :  */
      82             : const zend_function_entry sysvsem_functions[] = {
      83             :         PHP_FE(sem_get,                 arginfo_sem_get)
      84             :         PHP_FE(sem_acquire,             arginfo_sem_acquire)
      85             :         PHP_FE(sem_release,             arginfo_sem_release)
      86             :         PHP_FE(sem_remove,              arginfo_sem_remove)
      87             :         PHP_FE_END
      88             : };
      89             : /* }}} */
      90             : 
      91             : /* {{{ sysvsem_module_entry
      92             :  */
      93             : zend_module_entry sysvsem_module_entry = {
      94             :         STANDARD_MODULE_HEADER,
      95             :         "sysvsem",
      96             :         sysvsem_functions,
      97             :         PHP_MINIT(sysvsem),
      98             :         NULL,
      99             :         NULL,
     100             :         NULL,
     101             :         NULL,
     102             :         NO_VERSION_YET,
     103             :         STANDARD_MODULE_PROPERTIES
     104             : };
     105             : /* }}} */
     106             : 
     107             : #ifdef COMPILE_DL_SYSVSEM
     108             : ZEND_GET_MODULE(sysvsem)
     109             : #endif
     110             : 
     111             : 
     112             : THREAD_LS sysvsem_module php_sysvsem_module;
     113             : 
     114             : /* Semaphore functions using System V semaphores.  Each semaphore
     115             :  * actually consists of three semaphores allocated as a unit under the
     116             :  * same key.  Semaphore 0 (SYSVSEM_SEM) is the actual semaphore, it is
     117             :  * initialized to max_acquire and decremented as processes acquire it.
     118             :  * The value of semaphore 1 (SYSVSEM_USAGE) is a count of the number
     119             :  * of processes using the semaphore.  After calling semget(), if a
     120             :  * process finds that the usage count is 1, it will set the value of
     121             :  * SYSVSEM_SEM to max_acquire.  This allows max_acquire to be set and
     122             :  * track the PHP code without having a global init routine or external
     123             :  * semaphore init code.  Except see the bug regarding a race condition
     124             :  * php_sysvsem_get().  Semaphore 2 (SYSVSEM_SETVAL) serializes the
     125             :  * calls to GETVAL SYSVSEM_USAGE and SETVAL SYSVSEM_SEM.  It can be
     126             :  * acquired only when it is zero.
     127             :  */
     128             : 
     129             : #define SYSVSEM_SEM             0
     130             : #define SYSVSEM_USAGE   1
     131             : #define SYSVSEM_SETVAL  2
     132             : 
     133             : /* {{{ release_sysvsem_sem
     134             :  */
     135           1 : static void release_sysvsem_sem(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     136             : {
     137           1 :         sysvsem_sem *sem_ptr = (sysvsem_sem *)rsrc->ptr;
     138             :         struct sembuf sop[2];
     139           1 :         int opcount = 1;
     140             : /*
     141             :  * if count == -1, semaphore has been removed
     142             :  * Need better way to handle this
     143             :  */
     144             : 
     145           1 :         if (sem_ptr->count == -1 || !sem_ptr->auto_release) {
     146           1 :                 efree(sem_ptr);
     147           1 :                 return;
     148             :         }
     149             :         /* Decrement the usage count. */
     150             : 
     151           0 :         sop[0].sem_num = SYSVSEM_USAGE;
     152           0 :         sop[0].sem_op  = -1;
     153           0 :         sop[0].sem_flg = SEM_UNDO;
     154             : 
     155             :         /* Release the semaphore if it has been acquired but not released. */
     156             : 
     157           0 :         if (sem_ptr->count) {
     158             : 
     159           0 :                 sop[1].sem_num = SYSVSEM_SEM;
     160           0 :                 sop[1].sem_op  = sem_ptr->count;
     161           0 :                 sop[1].sem_flg = SEM_UNDO;
     162             : 
     163           0 :                 opcount++;
     164             :         }
     165             : 
     166           0 :         semop(sem_ptr->semid, sop, opcount);
     167           0 :         efree(sem_ptr);
     168             : }
     169             : /* }}} */
     170             : 
     171             : /* {{{ PHP_MINIT_FUNCTION
     172             :  */
     173       20225 : PHP_MINIT_FUNCTION(sysvsem)
     174             : {
     175       20225 :         php_sysvsem_module.le_sem = zend_register_list_destructors_ex(release_sysvsem_sem, NULL, "sysvsem", module_number);
     176       20225 :         return SUCCESS;
     177             : }
     178             : /* }}} */
     179             : 
     180             : #define SETVAL_WANTS_PTR
     181             : 
     182             : #if defined(_AIX)
     183             : #undef SETVAL_WANTS_PTR
     184             : #endif
     185             : 
     186             : /* {{{ proto resource sem_get(int key [, int max_acquire [, int perm [, int auto_release]])
     187             :    Return an id for the semaphore with the given key, and allow max_acquire (default 1) processes to acquire it simultaneously */
     188           1 : PHP_FUNCTION(sem_get)
     189             : {
     190           1 :         long key, max_acquire = 1, perm = 0666, auto_release = 1;
     191             :         int semid;
     192             :         struct sembuf sop[3];
     193             :         int count;
     194             :         sysvsem_sem *sem_ptr;
     195             : 
     196           1 :         if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|lll", &key, &max_acquire, &perm, &auto_release)) {
     197           0 :                 RETURN_FALSE;
     198             :         }
     199             : 
     200             :         /* Get/create the semaphore.  Note that we rely on the semaphores
     201             :          * being zeroed when they are created.  Despite the fact that
     202             :          * the(?)  Linux semget() man page says they are not initialized,
     203             :          * the kernel versions 2.0.x and 2.1.z do in fact zero them.
     204             :          */
     205             : 
     206           1 :         semid = semget(key, 3, perm|IPC_CREAT);
     207           1 :         if (semid == -1) {
     208           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
     209           0 :                 RETURN_FALSE;
     210             :         }
     211             : 
     212             :         /* Find out how many processes are using this semaphore.  Note
     213             :          * that on Linux (at least) there is a race condition here because
     214             :          * semaphore undo on process exit is not atomic, so we could
     215             :          * acquire SYSVSEM_SETVAL before a crashed process has decremented
     216             :          * SYSVSEM_USAGE in which case count will be greater than it
     217             :          * should be and we won't set max_acquire.  Fortunately this
     218             :          * doesn't actually matter in practice.
     219             :          */
     220             : 
     221             :         /* Wait for sem 1 to be zero . . . */
     222             : 
     223           1 :         sop[0].sem_num = SYSVSEM_SETVAL;
     224           1 :         sop[0].sem_op  = 0;
     225           1 :         sop[0].sem_flg = 0;
     226             : 
     227             :         /* . . . and increment it so it becomes non-zero . . . */
     228             : 
     229           1 :         sop[1].sem_num = SYSVSEM_SETVAL;
     230           1 :         sop[1].sem_op  = 1;
     231           1 :         sop[1].sem_flg = SEM_UNDO;
     232             : 
     233             :         /* . . . and increment the usage count. */
     234             : 
     235           1 :         sop[2].sem_num = SYSVSEM_USAGE;
     236           1 :         sop[2].sem_op  = 1;
     237           1 :         sop[2].sem_flg = SEM_UNDO;
     238           2 :         while (semop(semid, sop, 3) == -1) {
     239           0 :                 if (errno != EINTR) {
     240           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed acquiring SYSVSEM_SETVAL for key 0x%lx: %s", key, strerror(errno));
     241           0 :                         break;
     242             :                 }
     243             :         }
     244             : 
     245             :         /* Get the usage count. */
     246           1 :         count = semctl(semid, SYSVSEM_USAGE, GETVAL, NULL);
     247           1 :         if (count == -1) {
     248           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
     249             :         }
     250             : 
     251             :         /* If we are the only user, then take this opportunity to set the max. */
     252             : 
     253           1 :         if (count == 1) {
     254             : #if HAVE_SEMUN
     255             :                 /* This is correct for Linux which has union semun. */
     256             :                 union semun semarg;
     257           1 :                 semarg.val = max_acquire;
     258           1 :                 if (semctl(semid, SYSVSEM_SEM, SETVAL, semarg) == -1) {
     259           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
     260             :                 }
     261             : #elif defined(SETVAL_WANTS_PTR)
     262             :                 /* This is correct for Solaris 2.6 which does not have union semun. */
     263             :                 if (semctl(semid, SYSVSEM_SEM, SETVAL, &max_acquire) == -1) {
     264             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
     265             :                 }
     266             : #else
     267             :                 /* This works for i.e. AIX */
     268             :                 if (semctl(semid, SYSVSEM_SEM, SETVAL, max_acquire) == -1) {
     269             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
     270             :                 }
     271             : #endif
     272             :         }
     273             : 
     274             :         /* Set semaphore 1 back to zero. */
     275             : 
     276           1 :         sop[0].sem_num = SYSVSEM_SETVAL;
     277           1 :         sop[0].sem_op  = -1;
     278           1 :         sop[0].sem_flg = SEM_UNDO;
     279           2 :         while (semop(semid, sop, 1) == -1) {
     280           0 :                 if (errno != EINTR) {
     281           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed releasing SYSVSEM_SETVAL for key 0x%lx: %s", key, strerror(errno));
     282           0 :                         break;
     283             :                 }
     284             :         }
     285             : 
     286           1 :         sem_ptr = (sysvsem_sem *) emalloc(sizeof(sysvsem_sem));
     287           1 :         sem_ptr->key   = key;
     288           1 :         sem_ptr->semid = semid;
     289           1 :         sem_ptr->count = 0;
     290           1 :         sem_ptr->auto_release = auto_release;
     291             : 
     292           1 :         sem_ptr->id = ZEND_REGISTER_RESOURCE(return_value, sem_ptr, php_sysvsem_module.le_sem);
     293             : }
     294             : /* }}} */
     295             : 
     296             : /* {{{ php_sysvsem_semop
     297             :  */
     298           2 : static void php_sysvsem_semop(INTERNAL_FUNCTION_PARAMETERS, int acquire)
     299             : {
     300             :         zval *arg_id;
     301             :         sysvsem_sem *sem_ptr;
     302             :         struct sembuf sop;
     303             : 
     304           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg_id) == FAILURE) {
     305           0 :                 return;
     306             :         }
     307             : 
     308           2 :         ZEND_FETCH_RESOURCE(sem_ptr, sysvsem_sem *, &arg_id, -1, "SysV semaphore", php_sysvsem_module.le_sem);
     309             : 
     310           2 :         if (!acquire && sem_ptr->count == 0) {
     311           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);
     312           0 :                 RETURN_FALSE;
     313             :         }
     314             : 
     315           2 :         sop.sem_num = SYSVSEM_SEM;
     316           2 :         sop.sem_op  = acquire ? -1 : 1;
     317           2 :         sop.sem_flg = SEM_UNDO;
     318             : 
     319           4 :         while (semop(sem_ptr->semid, &sop, 1) == -1) {
     320           0 :                 if (errno != EINTR) {
     321           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to %s key 0x%x: %s", acquire ? "acquire" : "release", sem_ptr->key, strerror(errno));
     322           0 :                         RETURN_FALSE;
     323             :                 }
     324             :         }
     325             : 
     326           2 :         sem_ptr->count -= acquire ? -1 : 1;
     327           2 :         RETURN_TRUE;
     328             : }
     329             : /* }}} */
     330             : 
     331             : /* {{{ proto bool sem_acquire(resource id)
     332             :    Acquires the semaphore with the given id, blocking if necessary */
     333           1 : PHP_FUNCTION(sem_acquire)
     334             : {
     335           1 :         php_sysvsem_semop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     336           1 : }
     337             : /* }}} */
     338             : 
     339             : /* {{{ proto bool sem_release(resource id)
     340             :    Releases the semaphore with the given id */
     341           1 : PHP_FUNCTION(sem_release)
     342             : {
     343           1 :         php_sysvsem_semop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     344           1 : }
     345             : /* }}} */
     346             : 
     347             : /* {{{ proto bool sem_remove(resource id)
     348             :    Removes semaphore from Unix systems */
     349             : 
     350             : /*
     351             :  * contributed by Gavin Sherry gavin@linuxworld.com.au
     352             :  * Fri Mar 16 00:50:13 EST 2001
     353             :  */
     354             : 
     355           1 : PHP_FUNCTION(sem_remove)
     356             : {
     357             :         zval *arg_id;
     358             :         sysvsem_sem *sem_ptr;
     359             : #if HAVE_SEMUN
     360             :         union semun un;
     361             :         struct semid_ds buf;
     362             : #endif
     363             : 
     364           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg_id) == FAILURE) {
     365           0 :                 return;
     366             :         }
     367             : 
     368           1 :         ZEND_FETCH_RESOURCE(sem_ptr, sysvsem_sem *, &arg_id, -1, "SysV semaphore", php_sysvsem_module.le_sem);
     369             : 
     370             : #if HAVE_SEMUN
     371           1 :         un.buf = &buf;
     372           1 :         if (semctl(sem_ptr->semid, 0, IPC_STAT, un) < 0) {
     373             : #else
     374             :         if (semctl(sem_ptr->semid, 0, IPC_STAT, NULL) < 0) {
     375             : #endif
     376           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SysV semaphore %ld does not (any longer) exist", Z_LVAL_P(arg_id));
     377           0 :                 RETURN_FALSE;
     378             :         }
     379             : 
     380             : #if HAVE_SEMUN
     381           1 :         if (semctl(sem_ptr->semid, 0, IPC_RMID, un) < 0) {
     382             : #else
     383             :         if (semctl(sem_ptr->semid, 0, IPC_RMID, NULL) < 0) {
     384             : #endif
     385           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for SysV sempphore %ld: %s", Z_LVAL_P(arg_id), strerror(errno));
     386           0 :                 RETURN_FALSE;
     387             :         }
     388             :         
     389             :         /* let release_sysvsem_sem know we have removed
     390             :          * the semaphore to avoid issues with releasing.
     391             :          */ 
     392             : 
     393           1 :         sem_ptr->count = -1;
     394           1 :         RETURN_TRUE;
     395             : }
     396             : 
     397             : /* }}} */
     398             : 
     399             : #endif /* HAVE_SYSVSEM */
     400             : 
     401             : /*
     402             :  * Local variables:
     403             :  * tab-width: 4
     404             :  * c-basic-offset: 4
     405             :  * End:
     406             :  * vim600: sw=4 ts=4 fdm=marker
     407             :  * vim<600: sw=4 ts=4
     408             :  */

Generated by: LCOV version 1.10

Generated at Fri, 24 Oct 2014 05:21:58 +0000 (36 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.