Back to index

php5  5.3.10
shmop.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Slava Poliakov <hackie@prohost.org>                         |
00016    |          Ilia Alshanetsky <ilia@prohost.org>                         |
00017    +----------------------------------------------------------------------+
00018  */
00019 /* $Id: shmop.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "php_shmop.h"
00028 # ifndef PHP_WIN32
00029 # include <sys/ipc.h>
00030 # include <sys/shm.h>
00031 #else
00032 #include "tsrm_win32.h"
00033 #endif
00034 
00035 
00036 #if HAVE_SHMOP
00037 
00038 #include "ext/standard/info.h"
00039 
00040 #ifdef ZTS
00041 int shmop_globals_id;
00042 #else
00043 php_shmop_globals shmop_globals;
00044 #endif
00045 
00046 int shm_type;
00047 
00048 /* {{{ arginfo */
00049 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_open, 0, 0, 4)
00050        ZEND_ARG_INFO(0, key)
00051        ZEND_ARG_INFO(0, flags)
00052        ZEND_ARG_INFO(0, mode)
00053        ZEND_ARG_INFO(0, size)
00054 ZEND_END_ARG_INFO()
00055 
00056 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_read, 0, 0, 3)
00057        ZEND_ARG_INFO(0, shmid)
00058        ZEND_ARG_INFO(0, start)
00059        ZEND_ARG_INFO(0, count)
00060 ZEND_END_ARG_INFO()
00061 
00062 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_close, 0, 0, 1)
00063        ZEND_ARG_INFO(0, shmid)
00064 ZEND_END_ARG_INFO()
00065 
00066 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_size, 0, 0, 1)
00067        ZEND_ARG_INFO(0, shmid)
00068 ZEND_END_ARG_INFO()
00069 
00070 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_write, 0, 0, 3)
00071        ZEND_ARG_INFO(0, shmid)
00072        ZEND_ARG_INFO(0, data)
00073        ZEND_ARG_INFO(0, offset)
00074 ZEND_END_ARG_INFO()
00075 
00076 ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_delete, 0, 0, 1)
00077        ZEND_ARG_INFO(0, shmid)
00078 ZEND_END_ARG_INFO()
00079 /* }}} */
00080 
00081 /* {{{ shmop_functions[] 
00082  */
00083 const zend_function_entry shmop_functions[] = {
00084        PHP_FE(shmop_open,          arginfo_shmop_open)
00085        PHP_FE(shmop_read,          arginfo_shmop_read)
00086        PHP_FE(shmop_close,  arginfo_shmop_close)
00087        PHP_FE(shmop_size,          arginfo_shmop_size)
00088        PHP_FE(shmop_write,  arginfo_shmop_write)
00089        PHP_FE(shmop_delete,        arginfo_shmop_delete)
00090        PHP_FE_END
00091 };
00092 /* }}} */
00093 
00094 /* {{{ shmop_module_entry
00095  */
00096 zend_module_entry shmop_module_entry = {
00097        STANDARD_MODULE_HEADER,
00098        "shmop",
00099        shmop_functions,
00100        PHP_MINIT(shmop),
00101        NULL,
00102        NULL,
00103        NULL,
00104        PHP_MINFO(shmop),
00105        NO_VERSION_YET,
00106        STANDARD_MODULE_PROPERTIES
00107 };
00108 /* }}} */
00109 
00110 #ifdef COMPILE_DL_SHMOP
00111 ZEND_GET_MODULE(shmop)
00112 #endif
00113 
00114 #define PHP_SHMOP_GET_RES \
00115        shmop = zend_list_find(shmid, &type);     \
00116        if (!shmop) { \
00117               php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);      \
00118               RETURN_FALSE; \
00119        } else if (type != shm_type) {     \
00120               php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a shmop resource");  \
00121               RETURN_FALSE; \
00122        }      \
00123 
00124 /* {{{ rsclean
00125  */
00126 static void rsclean(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00127 {
00128        struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
00129 
00130        shmdt(shmop->addr);
00131        efree(shmop);
00132 }
00133 /* }}} */
00134 
00135 /* {{{ PHP_MINIT_FUNCTION
00136  */
00137 PHP_MINIT_FUNCTION(shmop)
00138 {
00139        shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
00140        
00141        return SUCCESS;
00142 }
00143 /* }}} */
00144 
00145 /* {{{ PHP_MINFO_FUNCTION
00146  */
00147 PHP_MINFO_FUNCTION(shmop)
00148 {
00149        php_info_print_table_start();
00150        php_info_print_table_row(2, "shmop support", "enabled");
00151        php_info_print_table_end();
00152 }
00153 /* }}} */
00154 
00155 /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
00156    gets and attaches a shared memory segment */
00157 PHP_FUNCTION(shmop_open)
00158 {
00159        long key, mode, size;
00160        struct php_shmop *shmop;    
00161        struct shmid_ds shm;
00162        int rsid;
00163        char *flags;
00164        int flags_len;
00165 
00166        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
00167               return;
00168        }
00169 
00170        if (flags_len != 1) {
00171               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
00172               RETURN_FALSE;
00173        }
00174 
00175        shmop = emalloc(sizeof(struct php_shmop));
00176        memset(shmop, 0, sizeof(struct php_shmop));
00177 
00178        shmop->key = key;
00179        shmop->shmflg |= mode;
00180 
00181        switch (flags[0]) 
00182        {
00183               case 'a':
00184                      shmop->shmatflg |= SHM_RDONLY;
00185                      break;
00186               case 'c':
00187                      shmop->shmflg |= IPC_CREAT;
00188                      shmop->size = size;
00189                      break;
00190               case 'n':
00191                      shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
00192                      shmop->size = size;
00193                      break; 
00194               case 'w':
00195                      /* noop 
00196                             shm segment is being opened for read & write
00197                             will fail if segment does not exist
00198                      */
00199                      break;
00200               default:
00201                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
00202                      goto err;
00203        }
00204 
00205        if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
00206               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
00207               goto err;
00208        }
00209 
00210        shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
00211        if (shmop->shmid == -1) {
00212               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
00213               goto err;
00214        }
00215 
00216        if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
00217               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
00218               goto err;
00219        }      
00220 
00221        shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
00222        if (shmop->addr == (char*) -1) {
00223               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
00224               goto err;
00225        }
00226 
00227        shmop->size = shm.shm_segsz;
00228 
00229        rsid = zend_list_insert(shmop, shm_type);
00230        RETURN_LONG(rsid);
00231 err:
00232        efree(shmop);
00233        RETURN_FALSE;
00234 }
00235 /* }}} */
00236 
00237 /* {{{ proto string shmop_read (int shmid, int start, int count)
00238    reads from a shm segment */
00239 PHP_FUNCTION(shmop_read)
00240 {
00241        long shmid, start, count;
00242        struct php_shmop *shmop;
00243        int type;
00244        char *startaddr;
00245        int bytes;
00246        char *return_string;
00247 
00248        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
00249               return;
00250        }
00251 
00252        PHP_SHMOP_GET_RES
00253 
00254        if (start < 0 || start > shmop->size) {
00255               php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
00256               RETURN_FALSE;
00257        }
00258 
00259        if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) {
00260               php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
00261               RETURN_FALSE;
00262        }
00263 
00264        startaddr = shmop->addr + start;
00265        bytes = count ? count : shmop->size - start;
00266 
00267        return_string = emalloc(bytes+1);
00268        memcpy(return_string, startaddr, bytes);
00269        return_string[bytes] = 0;
00270 
00271        RETURN_STRINGL(return_string, bytes, 0);
00272 }
00273 /* }}} */
00274 
00275 /* {{{ proto void shmop_close (int shmid)
00276    closes a shared memory segment */
00277 PHP_FUNCTION(shmop_close)
00278 {
00279        long shmid;
00280        struct php_shmop *shmop;
00281        int type;
00282 
00283        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
00284               return;
00285        }
00286 
00287        PHP_SHMOP_GET_RES
00288 
00289        zend_list_delete(shmid);
00290 }
00291 /* }}} */
00292 
00293 /* {{{ proto int shmop_size (int shmid)
00294    returns the shm size */
00295 PHP_FUNCTION(shmop_size)
00296 {
00297        long shmid;
00298        struct php_shmop *shmop;
00299        int type;
00300 
00301        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
00302               return;
00303        }
00304 
00305        PHP_SHMOP_GET_RES
00306 
00307        RETURN_LONG(shmop->size);
00308 }
00309 /* }}} */
00310 
00311 /* {{{ proto int shmop_write (int shmid, string data, int offset)
00312    writes to a shared memory segment */
00313 PHP_FUNCTION(shmop_write)
00314 {
00315        struct php_shmop *shmop;
00316        int type;
00317        int writesize;
00318        long shmid, offset;
00319        char *data;
00320        int data_len;
00321 
00322        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
00323               return;
00324        }
00325 
00326        PHP_SHMOP_GET_RES
00327 
00328        if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
00329               php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
00330               RETURN_FALSE;
00331        }
00332 
00333        if (offset < 0 || offset > shmop->size) {
00334               php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
00335               RETURN_FALSE;
00336        }
00337 
00338        writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
00339        memcpy(shmop->addr + offset, data, writesize);
00340 
00341        RETURN_LONG(writesize);
00342 }
00343 /* }}} */
00344 
00345 /* {{{ proto bool shmop_delete (int shmid)
00346    mark segment for deletion */
00347 PHP_FUNCTION(shmop_delete)
00348 {
00349        long shmid;
00350        struct php_shmop *shmop;
00351        int type;
00352 
00353        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
00354               return;
00355        }
00356 
00357        PHP_SHMOP_GET_RES
00358 
00359        if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
00360               php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
00361               RETURN_FALSE;
00362        }
00363 
00364        RETURN_TRUE;
00365 }
00366 /* }}} */
00367 
00368 #endif /* HAVE_SHMOP */
00369 
00370 /*
00371  * Local variables:
00372  * tab-width: 4
00373  * c-basic-offset: 4
00374  * End:
00375  * vim600: sw=4 ts=4 fdm=marker
00376  * vim<600: sw=4 ts=4
00377  */