summaryrefslogtreecommitdiff
path: root/ext/shmop/shmop.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/shmop/shmop.c')
-rw-r--r--ext/shmop/shmop.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c
new file mode 100644
index 0000000..a14a0b7
--- /dev/null
+++ b/ext/shmop/shmop.c
@@ -0,0 +1,377 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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: Slava Poliakov <hackie@prohost.org> |
+ | Ilia Alshanetsky <ilia@prohost.org> |
+ +----------------------------------------------------------------------+
+ */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "php_shmop.h"
+# ifndef PHP_WIN32
+# include <sys/ipc.h>
+# include <sys/shm.h>
+#else
+#include "tsrm_win32.h"
+#endif
+
+
+#if HAVE_SHMOP
+
+#include "ext/standard/info.h"
+
+#ifdef ZTS
+int shmop_globals_id;
+#else
+php_shmop_globals shmop_globals;
+#endif
+
+int shm_type;
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_open, 0, 0, 4)
+ ZEND_ARG_INFO(0, key)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, size)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_read, 0, 0, 3)
+ ZEND_ARG_INFO(0, shmid)
+ ZEND_ARG_INFO(0, start)
+ ZEND_ARG_INFO(0, count)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_close, 0, 0, 1)
+ ZEND_ARG_INFO(0, shmid)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_size, 0, 0, 1)
+ ZEND_ARG_INFO(0, shmid)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_write, 0, 0, 3)
+ ZEND_ARG_INFO(0, shmid)
+ ZEND_ARG_INFO(0, data)
+ ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_delete, 0, 0, 1)
+ ZEND_ARG_INFO(0, shmid)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ shmop_functions[]
+ */
+const zend_function_entry shmop_functions[] = {
+ PHP_FE(shmop_open, arginfo_shmop_open)
+ PHP_FE(shmop_read, arginfo_shmop_read)
+ PHP_FE(shmop_close, arginfo_shmop_close)
+ PHP_FE(shmop_size, arginfo_shmop_size)
+ PHP_FE(shmop_write, arginfo_shmop_write)
+ PHP_FE(shmop_delete, arginfo_shmop_delete)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ shmop_module_entry
+ */
+zend_module_entry shmop_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "shmop",
+ shmop_functions,
+ PHP_MINIT(shmop),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(shmop),
+ NO_VERSION_YET,
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_SHMOP
+ZEND_GET_MODULE(shmop)
+#endif
+
+#define PHP_SHMOP_GET_RES \
+ shmop = zend_list_find(shmid, &type); \
+ if (!shmop) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid); \
+ RETURN_FALSE; \
+ } else if (type != shm_type) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a shmop resource"); \
+ RETURN_FALSE; \
+ } \
+
+/* {{{ rsclean
+ */
+static void rsclean(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
+
+ shmdt(shmop->addr);
+ efree(shmop);
+}
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(shmop)
+{
+ shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(shmop)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "shmop support", "enabled");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ proto int shmop_open (int key, string flags, int mode, int size)
+ gets and attaches a shared memory segment */
+PHP_FUNCTION(shmop_open)
+{
+ long key, mode, size;
+ struct php_shmop *shmop;
+ struct shmid_ds shm;
+ int rsid;
+ char *flags;
+ int flags_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
+ return;
+ }
+
+ if (flags_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
+ RETURN_FALSE;
+ }
+
+ shmop = emalloc(sizeof(struct php_shmop));
+ memset(shmop, 0, sizeof(struct php_shmop));
+
+ shmop->key = key;
+ shmop->shmflg |= mode;
+
+ switch (flags[0])
+ {
+ case 'a':
+ shmop->shmatflg |= SHM_RDONLY;
+ break;
+ case 'c':
+ shmop->shmflg |= IPC_CREAT;
+ shmop->size = size;
+ break;
+ case 'n':
+ shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
+ shmop->size = size;
+ break;
+ case 'w':
+ /* noop
+ shm segment is being opened for read & write
+ will fail if segment does not exist
+ */
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
+ goto err;
+ }
+
+ if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
+ goto err;
+ }
+
+ shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
+ if (shmop->shmid == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
+ goto err;
+ }
+
+ if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
+ goto err;
+ }
+
+ shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
+ if (shmop->addr == (char*) -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
+ goto err;
+ }
+
+ shmop->size = shm.shm_segsz;
+
+ rsid = zend_list_insert(shmop, shm_type TSRMLS_CC);
+ RETURN_LONG(rsid);
+err:
+ efree(shmop);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string shmop_read (int shmid, int start, int count)
+ reads from a shm segment */
+PHP_FUNCTION(shmop_read)
+{
+ long shmid, start, count;
+ struct php_shmop *shmop;
+ int type;
+ char *startaddr;
+ int bytes;
+ char *return_string;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
+ return;
+ }
+
+ PHP_SHMOP_GET_RES
+
+ if (start < 0 || start > shmop->size) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
+ RETURN_FALSE;
+ }
+
+ if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
+ RETURN_FALSE;
+ }
+
+ startaddr = shmop->addr + start;
+ bytes = count ? count : shmop->size - start;
+
+ return_string = emalloc(bytes+1);
+ memcpy(return_string, startaddr, bytes);
+ return_string[bytes] = 0;
+
+ RETURN_STRINGL(return_string, bytes, 0);
+}
+/* }}} */
+
+/* {{{ proto void shmop_close (int shmid)
+ closes a shared memory segment */
+PHP_FUNCTION(shmop_close)
+{
+ long shmid;
+ struct php_shmop *shmop;
+ int type;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
+ return;
+ }
+
+ PHP_SHMOP_GET_RES
+
+ zend_list_delete(shmid);
+}
+/* }}} */
+
+/* {{{ proto int shmop_size (int shmid)
+ returns the shm size */
+PHP_FUNCTION(shmop_size)
+{
+ long shmid;
+ struct php_shmop *shmop;
+ int type;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
+ return;
+ }
+
+ PHP_SHMOP_GET_RES
+
+ RETURN_LONG(shmop->size);
+}
+/* }}} */
+
+/* {{{ proto int shmop_write (int shmid, string data, int offset)
+ writes to a shared memory segment */
+PHP_FUNCTION(shmop_write)
+{
+ struct php_shmop *shmop;
+ int type;
+ int writesize;
+ long shmid, offset;
+ char *data;
+ int data_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
+ return;
+ }
+
+ PHP_SHMOP_GET_RES
+
+ if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
+ RETURN_FALSE;
+ }
+
+ if (offset < 0 || offset > shmop->size) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
+ RETURN_FALSE;
+ }
+
+ writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
+ memcpy(shmop->addr + offset, data, writesize);
+
+ RETURN_LONG(writesize);
+}
+/* }}} */
+
+/* {{{ proto bool shmop_delete (int shmid)
+ mark segment for deletion */
+PHP_FUNCTION(shmop_delete)
+{
+ long shmid;
+ struct php_shmop *shmop;
+ int type;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
+ return;
+ }
+
+ PHP_SHMOP_GET_RES
+
+ if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+#endif /* HAVE_SHMOP */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */