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: 77 101 76.2 %
Date: 2014-09-27 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 27 Sep 2014 16:43:20 +0000 (4 days ago)

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