diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2069785 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +.deps +*.lo +*.la +.libs +acinclude.m4 +aclocal.m4 +autom4te.cache +build +config.guess +config.h +config.h.in +config.log +config.nice +config.status +config.sub +configure +configure.ac +include +install-sh +libtool +ltmain.sh +Makefile +Makefile.fragments +Makefile.global +Makefile.objects +missing +mkinstalldirs +modules +run-tests.php +tests/*.diff +tests/*.out +tests/*.php +tests/*.exp +tests/*.log +tests/*.sh diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..207a649 --- /dev/null +++ b/config.m4 @@ -0,0 +1,81 @@ +dnl $Id$ +dnl config.m4 for extension counterlock + +dnl Comments in this file start with the string 'dnl'. +dnl Remove where necessary. This file will not work +dnl without editing. + +dnl If your extension references something external, use with: + +dnl PHP_ARG_WITH(counterlock, for counterlock support, +dnl Make sure that the comment is aligned: +dnl [ --with-counterlock Include counterlock support]) + +dnl Otherwise use enable: + +PHP_ARG_ENABLE(counterlock, whether to enable counterlock support, +dnl Make sure that the comment is aligned: +[ --enable-counterlock Enable counterlock support]) + +if test "$PHP_COUNTERLOCK" != "no"; then + dnl Write more examples of tests here... + + dnl # get library FOO build options from pkg-config output + dnl AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + dnl AC_MSG_CHECKING(for libfoo) + dnl if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists foo; then + dnl if $PKG_CONFIG foo --atleast-version 1.2.3; then + dnl LIBFOO_CFLAGS=`$PKG_CONFIG foo --cflags` + dnl LIBFOO_LIBDIR=`$PKG_CONFIG foo --libs` + dnl LIBFOO_VERSON=`$PKG_CONFIG foo --modversion` + dnl AC_MSG_RESULT(from pkgconfig: version $LIBFOO_VERSON) + dnl else + dnl AC_MSG_ERROR(system libfoo is too old: version 1.2.3 required) + dnl fi + dnl else + dnl AC_MSG_ERROR(pkg-config not found) + dnl fi + dnl PHP_EVAL_LIBLINE($LIBFOO_LIBDIR, COUNTERLOCK_SHARED_LIBADD) + dnl PHP_EVAL_INCLINE($LIBFOO_CFLAGS) + + dnl # --with-counterlock -> check with-path + dnl SEARCH_PATH="/usr/local /usr" # you might want to change this + dnl SEARCH_FOR="/include/counterlock.h" # you most likely want to change this + dnl if test -r $PHP_COUNTERLOCK/$SEARCH_FOR; then # path given as parameter + dnl COUNTERLOCK_DIR=$PHP_COUNTERLOCK + dnl else # search default path list + dnl AC_MSG_CHECKING([for counterlock files in default path]) + dnl for i in $SEARCH_PATH ; do + dnl if test -r $i/$SEARCH_FOR; then + dnl COUNTERLOCK_DIR=$i + dnl AC_MSG_RESULT(found in $i) + dnl fi + dnl done + dnl fi + dnl + dnl if test -z "$COUNTERLOCK_DIR"; then + dnl AC_MSG_RESULT([not found]) + dnl AC_MSG_ERROR([Please reinstall the counterlock distribution]) + dnl fi + + dnl # --with-counterlock -> add include path + dnl PHP_ADD_INCLUDE($COUNTERLOCK_DIR/include) + + dnl # --with-counterlock -> check for lib and symbol presence + dnl LIBNAME=counterlock # you may want to change this + dnl LIBSYMBOL=counterlock # you most likely want to change this + + dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, + dnl [ + dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $COUNTERLOCK_DIR/$PHP_LIBDIR, COUNTERLOCK_SHARED_LIBADD) + dnl AC_DEFINE(HAVE_COUNTERLOCKLIB,1,[ ]) + dnl ],[ + dnl AC_MSG_ERROR([wrong counterlock lib version or lib not found]) + dnl ],[ + dnl -L$COUNTERLOCK_DIR/$PHP_LIBDIR -lm + dnl ]) + dnl + dnl PHP_SUBST(COUNTERLOCK_SHARED_LIBADD) + + PHP_NEW_EXTENSION(counterlock, counterlock.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) +fi diff --git a/config.w32 b/config.w32 new file mode 100644 index 0000000..f4d4e3b --- /dev/null +++ b/config.w32 @@ -0,0 +1,13 @@ +// $Id$ +// vim:ft=javascript + +// If your extension references something external, use ARG_WITH +// ARG_WITH("counterlock", "for counterlock support", "no"); + +// Otherwise, use ARG_ENABLE +ARG_ENABLE("counterlock", "enable counterlock support", "no"); + +if (PHP_COUNTERLOCK != "no") { + EXTENSION("counterlock", "counterlock.c", PHP_EXTNAME_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); +} + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..1cf38a2 --- /dev/null +++ b/configure.in @@ -0,0 +1,201 @@ +dnl This file becomes configure.in for self-contained extensions. + +AC_PREREQ(2.59) +AC_INIT(config.m4) +ifdef([AC_PRESERVE_HELP_ORDER], [AC_PRESERVE_HELP_ORDER], []) + +PHP_CONFIG_NICE(config.nice) + +dnl +AC_DEFUN([PHP_EXT_BUILDDIR],[.])dnl +AC_DEFUN([PHP_EXT_DIR],[""])dnl +AC_DEFUN([PHP_EXT_SRCDIR],[$abs_srcdir])dnl +AC_DEFUN([PHP_ALWAYS_SHARED],[ + ext_output="yes, shared" + ext_shared=yes + test "[$]$1" = "no" && $1=yes +])dnl +dnl + +test -z "$CFLAGS" && auto_cflags=1 + +abs_srcdir=`(cd $srcdir && pwd)` +abs_builddir=`pwd` + +AC_PROG_CC([cc gcc]) +PHP_DETECT_ICC +PHP_DETECT_SUNCC +AC_PROG_CC_C_O + +dnl Support systems with system libraries in e.g. /usr/lib64 +PHP_ARG_WITH(libdir, for system library directory, +[ --with-libdir=NAME Look for libraries in .../NAME rather than .../lib], lib, no) + +PHP_RUNPATH_SWITCH +PHP_SHLIB_SUFFIX_NAMES + +dnl Find php-config script +PHP_ARG_WITH(php-config,, +[ --with-php-config=PATH Path to php-config [php-config]], php-config, no) + +dnl For BC +PHP_CONFIG=$PHP_PHP_CONFIG +prefix=`$PHP_CONFIG --prefix 2>/dev/null` +phpincludedir=`$PHP_CONFIG --include-dir 2>/dev/null` +INCLUDES=`$PHP_CONFIG --includes 2>/dev/null` +EXTENSION_DIR=`$PHP_CONFIG --extension-dir 2>/dev/null` +PHP_EXECUTABLE=`$PHP_CONFIG --php-binary 2>/dev/null` + +if test -z "$prefix"; then + AC_MSG_ERROR([Cannot find php-config. Please use --with-php-config=PATH]) +fi + +php_shtool=$srcdir/build/shtool +PHP_INIT_BUILD_SYSTEM + +AC_MSG_CHECKING([for PHP prefix]) +AC_MSG_RESULT([$prefix]) +AC_MSG_CHECKING([for PHP includes]) +AC_MSG_RESULT([$INCLUDES]) +AC_MSG_CHECKING([for PHP extension directory]) +AC_MSG_RESULT([$EXTENSION_DIR]) +AC_MSG_CHECKING([for PHP installed headers prefix]) +AC_MSG_RESULT([$phpincludedir]) + +dnl Checks for PHP_DEBUG / ZEND_DEBUG / ZTS +AC_MSG_CHECKING([if debug is enabled]) +old_CPPFLAGS=$CPPFLAGS +CPPFLAGS="-I$phpincludedir" +AC_EGREP_CPP(php_debug_is_enabled,[ +#include
+#if ZEND_DEBUG +php_debug_is_enabled +#endif +],[ + PHP_DEBUG=yes +],[ + PHP_DEBUG=no +]) +CPPFLAGS=$old_CPPFLAGS +AC_MSG_RESULT([$PHP_DEBUG]) + +AC_MSG_CHECKING([if zts is enabled]) +old_CPPFLAGS=$CPPFLAGS +CPPFLAGS="-I$phpincludedir" +AC_EGREP_CPP(php_zts_is_enabled,[ +#include
+#if ZTS +php_zts_is_enabled +#endif +],[ + PHP_THREAD_SAFETY=yes +],[ + PHP_THREAD_SAFETY=no +]) +CPPFLAGS=$old_CPPFLAGS +AC_MSG_RESULT([$PHP_THREAD_SAFETY]) + +dnl Support for building and testing Zend extensions +ZEND_EXT_TYPE="zend_extension" +PHP_SUBST(ZEND_EXT_TYPE) + +dnl Discard optimization flags when debugging is enabled +if test "$PHP_DEBUG" = "yes"; then + PHP_DEBUG=1 + ZEND_DEBUG=yes + changequote({,}) + CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'` + CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` + changequote([,]) + dnl add -O0 only if GCC or ICC is used + if test "$GCC" = "yes" || test "$ICC" = "yes"; then + CFLAGS="$CFLAGS -O0" + CXXFLAGS="$CXXFLAGS -g -O0" + fi + if test "$SUNCC" = "yes"; then + if test -n "$auto_cflags"; then + CFLAGS="-g" + CXXFLAGS="-g" + else + CFLAGS="$CFLAGS -g" + CXXFLAGS="$CFLAGS -g" + fi + fi +else + PHP_DEBUG=0 + ZEND_DEBUG=no +fi + +dnl Always shared +PHP_BUILD_SHARED + +dnl Required programs +PHP_PROG_RE2C +PHP_PROG_AWK + +sinclude(config.m4) + +enable_static=no +enable_shared=yes + +dnl Only allow AC_PROG_CXX and AC_PROG_CXXCPP if they are explicitly called (by PHP_REQUIRE_CXX). +dnl Otherwise AC_PROG_LIBTOOL fails if there is no working C++ compiler. +AC_PROVIDE_IFELSE([PHP_REQUIRE_CXX], [], [ + undefine([AC_PROG_CXX]) + AC_DEFUN([AC_PROG_CXX], []) + undefine([AC_PROG_CXXCPP]) + AC_DEFUN([AC_PROG_CXXCPP], [php_prog_cxxcpp=disabled]) +]) +AC_PROG_LIBTOOL + +all_targets='$(PHP_MODULES) $(PHP_ZEND_EX)' +install_targets="install-modules install-headers" +phplibdir="`pwd`/modules" +CPPFLAGS="$CPPFLAGS -DHAVE_CONFIG_H" +CFLAGS_CLEAN='$(CFLAGS)' +CXXFLAGS_CLEAN='$(CXXFLAGS)' + +test "$prefix" = "NONE" && prefix="/usr/local" +test "$exec_prefix" = "NONE" && exec_prefix='$(prefix)' + +PHP_SUBST(PHP_MODULES) +PHP_SUBST(PHP_ZEND_EX) + +PHP_SUBST(all_targets) +PHP_SUBST(install_targets) + +PHP_SUBST(prefix) +PHP_SUBST(exec_prefix) +PHP_SUBST(libdir) +PHP_SUBST(prefix) +PHP_SUBST(phplibdir) +PHP_SUBST(phpincludedir) + +PHP_SUBST(CC) +PHP_SUBST(CFLAGS) +PHP_SUBST(CFLAGS_CLEAN) +PHP_SUBST(CPP) +PHP_SUBST(CPPFLAGS) +PHP_SUBST(CXX) +PHP_SUBST(CXXFLAGS) +PHP_SUBST(CXXFLAGS_CLEAN) +PHP_SUBST(EXTENSION_DIR) +PHP_SUBST(PHP_EXECUTABLE) +PHP_SUBST(EXTRA_LDFLAGS) +PHP_SUBST(EXTRA_LIBS) +PHP_SUBST(INCLUDES) +PHP_SUBST(LFLAGS) +PHP_SUBST(LDFLAGS) +PHP_SUBST(SHARED_LIBTOOL) +PHP_SUBST(LIBTOOL) +PHP_SUBST(SHELL) +PHP_SUBST(INSTALL_HEADERS) + +PHP_GEN_BUILD_DIRS +PHP_GEN_GLOBAL_MAKEFILE + +test -d modules || $php_shtool mkdir modules + +AC_CONFIG_HEADER(config.h) + +AC_OUTPUT() diff --git a/counterlock.c b/counterlock.c new file mode 100644 index 0000000..fbf7755 --- /dev/null +++ b/counterlock.c @@ -0,0 +1,290 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2018 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: | + +----------------------------------------------------------------------+ +*/ + +/* @see http://man7.org/linux/man-pages/man2/semop.2.html */ +/* @see http://man7.org/linux/man-pages/man2/semget.2.html */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_counterlock.h" +#include "Zend/zend_gc.h" +#include "Zend/zend_builtin_functions.h" +#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ +#include "ext/standard/php_array.h" +#include "Zend/zend_interfaces.h" +#include "Zend/zend_alloc.h" +#include "SAPI.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_counter_create, 0, 0, 1) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, perm) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_counter_increment, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_counter_decrement, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_counter_remove, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_counter_value, 0, 0, 1) + ZEND_ARG_INFO(0, sem_identifier) +ZEND_END_ARG_INFO() +/* }}} */ + +ZEND_GET_MODULE(counterlock); +THREAD_LS sysvcount_module php_sysvcount_module; + +zend_function_entry counterlock_functions[] = { + PHP_FE(counter_create, arginfo_counter_create) + PHP_FE(counter_increment, arginfo_counter_increment) + PHP_FE(counter_decrement, arginfo_counter_decrement) + PHP_FE(counter_remove, arginfo_counter_remove) + PHP_FE(counter_value, arginfo_counter_value) + PHP_FE_END +}; + +zend_module_entry counterlock_module_entry = { + STANDARD_MODULE_HEADER, + "Cuantic SysSem counter", + counterlock_functions, + PHP_MINIT(counterlock), + NULL, + NULL, + NULL, + NULL, + PHP_COUNTERLOCK_VERSION, + STANDARD_MODULE_PROPERTIES, +}; + +static void release_sysvcount_sem(zend_resource *rsrc) +{ + sysvcount_sem *sem_ptr = (sysvcount_sem *)rsrc->ptr; + struct sembuf sop[1]; + int opcount = 1; + + efree(sem_ptr); +} + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(counterlock) +{ + // Declare resurece ID + // To prevent PHP Warning: Unknown list entry type (0) in Unknown on line 0 + php_sysvcount_module.le_sem = zend_register_list_destructors_ex(release_sysvcount_sem, NULL, "counterlock", module_number); + return SUCCESS; +} + +PHP_FUNCTION(counter_create) +{ + zend_long key, perm = 0666; + struct sembuf sop[1]; + int semid; + int count; + sysvcount_sem *sem_ptr; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key, &perm)) { + 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, 1, perm|IPC_CREAT); + if (semid == -1) { + php_error_docref(NULL, E_WARNING, "failed for key 0x" ZEND_XLONG_FMT ": %s", key, strerror(errno)); + RETURN_FALSE; + } + + sem_ptr = (sysvcount_sem *) emalloc(sizeof(sysvcount_sem)); + sem_ptr->key = key; + sem_ptr->semid = semid; + sem_ptr->count = 0; + RETVAL_RES(zend_register_resource(sem_ptr, php_sysvcount_module.le_sem)); + sem_ptr->id = Z_RES_HANDLE_P(return_value); +} + +PHP_FUNCTION(counter_increment) +{ + zval *arg_id; + zend_bool nowait = 0; + sysvcount_sem *sem_ptr; + struct sembuf sop; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg_id)) { + RETURN_FALSE; + } + + if ((sem_ptr = (sysvcount_sem *)zend_fetch_resource(Z_RES_P(arg_id), "SysV counter", php_sysvcount_module.le_sem)) == NULL) { + RETURN_FALSE; + } + + sop.sem_num = 0; + sop.sem_op = 1; + sop.sem_flg = SEM_UNDO; + + while (semop(sem_ptr->semid, &sop, 1) == -1) { + if (errno != EINTR) { + if (errno != EAGAIN) { + php_error_docref(NULL, E_WARNING, "failed to %s key 0x%x: %s", "increment", sem_ptr->key, strerror(errno)); + } + RETURN_FALSE; + } + } + + sem_ptr->count += 1; + RETURN_TRUE; +} + +PHP_FUNCTION(counter_decrement) +{ + zval *arg_id; + zend_bool nowait = 0; + sysvcount_sem *sem_ptr; + struct sembuf sop; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg_id)) { + RETURN_FALSE; + } + + if ((sem_ptr = (sysvcount_sem *)zend_fetch_resource(Z_RES_P(arg_id), "SysV counter", php_sysvcount_module.le_sem)) == NULL) { + RETURN_FALSE; + } + + if (sem_ptr->count == 0) { + php_error_docref(NULL, E_WARNING, "SysV counter " ZEND_LONG_FMT " (key 0x%x) is not increment yet", Z_LVAL_P(arg_id), sem_ptr->key); + RETURN_FALSE; + } + + sop.sem_num = 0; + sop.sem_op = -1; + sop.sem_flg = SEM_UNDO | IPC_NOWAIT; + + while (semop(sem_ptr->semid, &sop, 1) == -1) { + if (errno != EINTR) { + if (errno != EAGAIN) { + php_error_docref(NULL, E_WARNING, "failed to %s key 0x%x: %s", "decrement", sem_ptr->key, strerror(errno)); + } + RETURN_FALSE; + } + } + + sem_ptr->count -= 1; + RETURN_TRUE; +} + +PHP_FUNCTION(counter_remove) +{ + zval *arg_id; + sysvcount_sem *sem_ptr; + union semun un; + struct semid_ds buf; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg_id) == FAILURE) { + return; + } + + if ((sem_ptr = (sysvcount_sem *)zend_fetch_resource(Z_RES_P(arg_id), "SysV counter", php_sysvcount_module.le_sem)) == NULL) { + RETURN_FALSE; + } + + un.buf = &buf; + if (semctl(sem_ptr->semid, 0, IPC_STAT, un) < 0) { + php_error_docref(NULL, E_WARNING, "SysV counter " ZEND_LONG_FMT " does not (any longer) exist", Z_LVAL_P(arg_id)); + RETURN_FALSE; + } + + if (semctl(sem_ptr->semid, 0, IPC_RMID, un) < 0) { + php_error_docref(NULL, E_WARNING, "failed for SysV counter " ZEND_LONG_FMT ": %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; +} + +PHP_FUNCTION(counter_value) +{ + zval *arg_id; + zend_bool nowait = 0; + sysvcount_sem *sem_ptr; + struct sembuf sop; + int retval; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg_id)) { + RETURN_FALSE; + } + + if ((sem_ptr = (sysvcount_sem *)zend_fetch_resource(Z_RES_P(arg_id), "SysV counter", php_sysvcount_module.le_sem)) == NULL) { + RETURN_FALSE; + } + + retval = semctl(sem_ptr->semid, 0, GETVAL, NULL); + if (retval == -1) { + php_error_docref(NULL, E_WARNING, "failed for key 0x" ZEND_XLONG_FMT ": %s", sem_ptr->key, strerror(errno)); + RETURN_FALSE; + } + + RETURN_LONG(retval); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/counterlock.php b/counterlock.php new file mode 100644 index 0000000..d7e2cae --- /dev/null +++ b/counterlock.php @@ -0,0 +1,21 @@ +"; + +if(!extension_loaded('counterlock')) { + dl('counterlock.' . PHP_SHLIB_SUFFIX); +} +$module = 'counterlock'; +$functions = get_extension_funcs($module); +echo "Functions available in the test extension:$br\n"; +foreach($functions as $func) { + echo $func."$br\n"; +} +echo "$br\n"; +$function = 'confirm_' . $module . '_compiled'; +if (extension_loaded($module)) { + $str = $function($module); +} else { + $str = "Module $module is not compiled into PHP"; +} +echo "$str\n"; +?> diff --git a/example.php b/example.php new file mode 100644 index 0000000..8b6ff39 --- /dev/null +++ b/example.php @@ -0,0 +1,7 @@ + +--FILE-- + +--EXPECT-- +0 +1 +2 +1