Back to index

php5  5.3.10
sysvshm.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    | Author: Christian Cartus <cartus@atrior.de>                          |
00016    +----------------------------------------------------------------------+
00017  */
00018  
00019 /* $Id: sysvshm.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 /* This has been built and tested on Linux 2.2.14 
00022  *
00023  * This has been built and tested on Solaris 2.6.
00024  * It may not compile or execute correctly on other systems.
00025  */
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include "config.h"
00029 #endif
00030 
00031 #include "php.h"
00032 
00033 #if HAVE_SYSVSHM
00034 
00035 #include <errno.h>
00036 
00037 #include "php_sysvshm.h"
00038 #include "ext/standard/php_var.h"
00039 #include "ext/standard/php_smart_str.h"
00040 #include "php_ini.h"
00041 
00042 /* {{{ arginfo */
00043 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_attach, 0, 0, 1)
00044        ZEND_ARG_INFO(0, key)
00045        ZEND_ARG_INFO(0, memsize)
00046        ZEND_ARG_INFO(0, perm)
00047 ZEND_END_ARG_INFO()
00048 
00049 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_detach, 0, 0, 1)
00050        ZEND_ARG_INFO(0, shm_identifier)
00051 ZEND_END_ARG_INFO()
00052 
00053 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_has_var, 0, 0, 2)
00054        ZEND_ARG_INFO(0, id)
00055        ZEND_ARG_INFO(0, variable_key)
00056 ZEND_END_ARG_INFO()
00057 
00058 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_remove, 0, 0, 1)
00059        ZEND_ARG_INFO(0, shm_identifier)
00060 ZEND_END_ARG_INFO()
00061 
00062 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_put_var, 0, 0, 3)
00063        ZEND_ARG_INFO(0, shm_identifier)
00064        ZEND_ARG_INFO(0, variable_key)
00065        ZEND_ARG_INFO(0, variable)
00066 ZEND_END_ARG_INFO()
00067 
00068 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_get_var, 0, 0, 2)
00069        ZEND_ARG_INFO(0, id)
00070        ZEND_ARG_INFO(0, variable_key)
00071 ZEND_END_ARG_INFO()
00072 
00073 ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_remove_var, 0, 0, 2)
00074        ZEND_ARG_INFO(0, id)
00075        ZEND_ARG_INFO(0, variable_key)
00076 ZEND_END_ARG_INFO()
00077 /* }}} */
00078 
00079 /* {{{ sysvshm_functions[]
00080  */
00081 const zend_function_entry sysvshm_functions[] = {
00082        PHP_FE(shm_attach,          arginfo_shm_attach)
00083        PHP_FE(shm_remove,          arginfo_shm_detach)
00084        PHP_FE(shm_detach,          arginfo_shm_remove)
00085        PHP_FE(shm_put_var,         arginfo_shm_put_var)
00086        PHP_FE(shm_has_var,         arginfo_shm_has_var)
00087        PHP_FE(shm_get_var,         arginfo_shm_get_var)
00088        PHP_FE(shm_remove_var,      arginfo_shm_remove_var)
00089        PHP_FE_END
00090 };
00091 /* }}} */
00092 
00093 /* {{{ sysvshm_module_entry
00094  */
00095 zend_module_entry sysvshm_module_entry = {
00096        STANDARD_MODULE_HEADER,
00097        "sysvshm",
00098        sysvshm_functions, 
00099        PHP_MINIT(sysvshm),
00100        NULL,
00101        NULL,
00102        NULL,
00103        NULL,
00104        NO_VERSION_YET,
00105        STANDARD_MODULE_PROPERTIES
00106 };
00107 /* }}} */
00108 
00109 #ifdef COMPILE_DL_SYSVSHM
00110 ZEND_GET_MODULE(sysvshm)
00111 #endif
00112 
00113 #undef shm_ptr                                   /* undefine AIX-specific macro */
00114 
00115 #define SHM_FETCH_RESOURCE(shm_ptr, z_ptr) ZEND_FETCH_RESOURCE(shm_ptr, sysvshm_shm *, &z_ptr, -1, PHP_SHM_RSRC_NAME, php_sysvshm.le_shm)
00116 
00117 THREAD_LS sysvshm_module php_sysvshm;
00118 
00119 static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, const char *data, long len);
00120 static long php_check_shm_data(sysvshm_chunk_head *ptr, long key);
00121 static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos);
00122 
00123 /* {{{ php_release_sysvshm
00124  */
00125 static void php_release_sysvshm(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00126 {
00127        sysvshm_shm *shm_ptr = (sysvshm_shm *) rsrc->ptr;
00128        shmdt((void *) shm_ptr->ptr);
00129        efree(shm_ptr);
00130 }
00131 /* }}} */
00132 
00133 /* {{{ PHP_MINIT_FUNCTION
00134  */
00135 PHP_MINIT_FUNCTION(sysvshm)
00136 {
00137        php_sysvshm.le_shm = zend_register_list_destructors_ex(php_release_sysvshm, NULL, PHP_SHM_RSRC_NAME, module_number);
00138 
00139        if (cfg_get_long("sysvshm.init_mem", &php_sysvshm.init_mem) == FAILURE) {
00140               php_sysvshm.init_mem=10000;
00141        }
00142        return SUCCESS;
00143 }
00144 /* }}} */
00145 
00146 /* {{{ proto int shm_attach(int key [, int memsize [, int perm]])
00147    Creates or open a shared memory segment */
00148 PHP_FUNCTION(shm_attach)
00149 {
00150        sysvshm_shm *shm_list_ptr;
00151        char *shm_ptr;
00152        sysvshm_chunk_head *chunk_ptr;
00153        long shm_key, shm_id, shm_size = php_sysvshm.init_mem, shm_flag = 0666;
00154 
00155        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &shm_key, &shm_size, &shm_flag)) {
00156               return;
00157        }
00158 
00159        if (shm_size < 1) {
00160               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Segment size must be greater than zero");
00161               RETURN_FALSE;
00162        }
00163 
00164        shm_list_ptr = (sysvshm_shm *) emalloc(sizeof(sysvshm_shm));
00165 
00166        /* get the id from a specified key or create new shared memory */
00167        if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
00168               if (shm_size < sizeof(sysvshm_chunk_head)) {
00169                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: memorysize too small", shm_key);
00170                      efree(shm_list_ptr);
00171                      RETURN_FALSE;
00172               }
00173               if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL)) < 0) {
00174                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", shm_key, strerror(errno));
00175                      efree(shm_list_ptr);
00176                      RETURN_FALSE;
00177               }
00178        }
00179 
00180        if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
00181               php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", shm_key, strerror(errno));
00182               efree(shm_list_ptr);
00183               RETURN_FALSE;
00184        }
00185 
00186        /* check if shm is already initialized */
00187        chunk_ptr = (sysvshm_chunk_head *) shm_ptr;
00188        if (strcmp((char*) &(chunk_ptr->magic), "PHP_SM") != 0) {
00189               strcpy((char*) &(chunk_ptr->magic), "PHP_SM");   
00190               chunk_ptr->start = sizeof(sysvshm_chunk_head);
00191               chunk_ptr->end = chunk_ptr->start;
00192               chunk_ptr->total = shm_size;
00193               chunk_ptr->free = shm_size-chunk_ptr->end;
00194        }
00195 
00196        shm_list_ptr->key = shm_key;
00197        shm_list_ptr->id = shm_id;
00198        shm_list_ptr->ptr = chunk_ptr;
00199        
00200        ZEND_REGISTER_RESOURCE(return_value, shm_list_ptr, php_sysvshm.le_shm);
00201 }
00202 /* }}} */
00203 
00204 /* {{{ proto bool shm_detach(resource shm_identifier)
00205    Disconnects from shared memory segment */
00206 PHP_FUNCTION(shm_detach)
00207 {
00208        zval *shm_id;
00209        sysvshm_shm *shm_list_ptr;
00210 
00211        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &shm_id)) {
00212               return;
00213        }
00214        SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
00215        RETURN_BOOL(SUCCESS == zend_list_delete(Z_LVAL_P(shm_id)));
00216 }
00217 /* }}} */
00218 
00219 /* {{{ proto bool shm_remove(resource shm_identifier)
00220    Removes shared memory from Unix systems */
00221 PHP_FUNCTION(shm_remove)
00222 {
00223        zval *shm_id;
00224        sysvshm_shm *shm_list_ptr;
00225 
00226        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &shm_id)) {
00227               return;
00228        }
00229        SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
00230        
00231        if (shmctl(shm_list_ptr->id, IPC_RMID, NULL) < 0) {
00232               php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%x, id %ld: %s", shm_list_ptr->key, Z_LVAL_P(shm_id), strerror(errno));
00233               RETURN_FALSE;
00234        }
00235 
00236        RETURN_TRUE;
00237 }
00238 /* }}} */
00239 
00240 /* {{{ proto bool shm_put_var(resource shm_identifier, int variable_key, mixed variable)
00241    Inserts or updates a variable in shared memory */
00242 PHP_FUNCTION(shm_put_var)
00243 {
00244        zval *shm_id, *arg_var;
00245        int ret;
00246        long shm_key;
00247        sysvshm_shm *shm_list_ptr;
00248        smart_str shm_var = {0};
00249        php_serialize_data_t var_hash;
00250 
00251        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &shm_id, &shm_key, &arg_var)) {
00252               return;
00253        }
00254        
00255        /* setup string-variable and serialize */
00256        PHP_VAR_SERIALIZE_INIT(var_hash);
00257        php_var_serialize(&shm_var, &arg_var, &var_hash TSRMLS_CC);
00258        PHP_VAR_SERIALIZE_DESTROY(var_hash);
00259        
00260        shm_list_ptr = zend_fetch_resource(&shm_id TSRMLS_CC, -1, PHP_SHM_RSRC_NAME, NULL, 1, php_sysvshm.le_shm);
00261        if (!shm_list_ptr) {
00262               smart_str_free(&shm_var);
00263               RETURN_FALSE;
00264        }
00265 
00266        /* insert serialized variable into shared memory */
00267        ret = php_put_shm_data(shm_list_ptr->ptr, shm_key, shm_var.c, shm_var.len);
00268 
00269        /* free string */
00270        smart_str_free(&shm_var);
00271        
00272        if (ret == -1) {
00273               php_error_docref(NULL TSRMLS_CC, E_WARNING, "not enough shared memory left");
00274               RETURN_FALSE;
00275        }
00276        RETURN_TRUE;
00277 }
00278 /* }}} */
00279 
00280 /* {{{ proto mixed shm_get_var(resource id, int variable_key)
00281    Returns a variable from shared memory */
00282 PHP_FUNCTION(shm_get_var)
00283 {
00284        zval *shm_id;
00285        long shm_key;
00286        sysvshm_shm *shm_list_ptr;
00287        char *shm_data;
00288        long shm_varpos;
00289        sysvshm_chunk *shm_var;
00290        php_unserialize_data_t var_hash;
00291        
00292        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
00293               return;
00294        }
00295        SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
00296 
00297        /* setup string-variable and serialize */
00298        /* get serialized variable from shared memory */
00299        shm_varpos = php_check_shm_data((shm_list_ptr->ptr), shm_key);
00300 
00301        if (shm_varpos < 0) {
00302               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", shm_key);
00303               RETURN_FALSE;
00304        }
00305        shm_var = (sysvshm_chunk*) ((char *)shm_list_ptr->ptr + shm_varpos);
00306        shm_data = &shm_var->mem;
00307        
00308        PHP_VAR_UNSERIALIZE_INIT(var_hash);
00309        if (php_var_unserialize(&return_value, (const unsigned char **) &shm_data, (unsigned char *) shm_data + shm_var->length, &var_hash TSRMLS_CC) != 1) {
00310               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable data in shared memory is corrupted");
00311               RETVAL_FALSE;
00312        }
00313        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
00314 }
00315 /* }}} */
00316 
00317 /* {{{ proto bool shm_has_var(resource id, int variable_key)
00318        Checks whether a specific entry exists */
00319 PHP_FUNCTION(shm_has_var)
00320 {
00321        zval *shm_id;
00322        long shm_key;
00323        sysvshm_shm *shm_list_ptr;
00324        
00325        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
00326               return;
00327        }
00328        SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
00329        RETURN_BOOL(php_check_shm_data(shm_list_ptr->ptr, shm_key) >= 0);
00330 }
00331 /* }}} */
00332 
00333 /* {{{ proto bool shm_remove_var(resource id, int variable_key)
00334    Removes variable from shared memory */
00335 PHP_FUNCTION(shm_remove_var)
00336 {
00337        zval *shm_id;
00338        long shm_key, shm_varpos;
00339        sysvshm_shm *shm_list_ptr;
00340        
00341        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
00342               return;
00343        }
00344        SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
00345 
00346        shm_varpos = php_check_shm_data((shm_list_ptr->ptr), shm_key);
00347 
00348        if (shm_varpos < 0) {
00349               php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", shm_key);
00350               RETURN_FALSE;
00351        }
00352        php_remove_shm_data((shm_list_ptr->ptr), shm_varpos);
00353        RETURN_TRUE;
00354 }
00355 /* }}} */
00356 
00357 /* {{{ php_put_shm_data
00358  * inserts an ascii-string into shared memory */
00359 static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, const char *data, long len)
00360 {
00361        sysvshm_chunk *shm_var;
00362        long total_size;
00363        long shm_varpos;
00364 
00365        total_size = ((long) (len + sizeof(sysvshm_chunk) - 1) / sizeof(long)) * sizeof(long) + sizeof(long); /* long alligment */
00366 
00367        if ((shm_varpos = php_check_shm_data(ptr, key)) > 0) {
00368               php_remove_shm_data(ptr, shm_varpos);
00369        }
00370        
00371        if (ptr->free < total_size) {
00372               return -1; /* not enough memory */
00373        }
00374 
00375        shm_var = (sysvshm_chunk *) ((char *) ptr + ptr->end);  
00376        shm_var->key = key;
00377        shm_var->length = len;
00378        shm_var->next = total_size;   
00379        memcpy(&(shm_var->mem), data, len);       
00380        ptr->end += total_size;
00381        ptr->free -= total_size;
00382        return 0;
00383 }
00384 /* }}} */
00385 
00386 /* {{{ php_check_shm_data
00387  */
00388 static long php_check_shm_data(sysvshm_chunk_head *ptr, long key)
00389 {
00390        long pos;
00391        sysvshm_chunk *shm_var;
00392 
00393        pos = ptr->start;
00394                      
00395        for (;;) {
00396               if (pos >= ptr->end) {
00397                      return -1;
00398               }
00399               shm_var = (sysvshm_chunk*) ((char *) ptr + pos);
00400               if (shm_var->key == key) {
00401                      return pos;
00402               }      
00403               pos += shm_var->next;
00404 
00405               if (shm_var->next <= 0 || pos < ptr->start) {
00406                      return -1;
00407               }
00408        }
00409        return -1;
00410 }
00411 /* }}} */
00412 
00413 /* {{{ php_remove_shm_data
00414  */
00415 static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos)
00416 {
00417        sysvshm_chunk *chunk_ptr, *next_chunk_ptr;
00418        long memcpy_len;
00419        
00420        chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos);
00421        next_chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos + chunk_ptr->next);
00422        
00423        memcpy_len = ptr->end-shm_varpos - chunk_ptr->next;
00424        ptr->free += chunk_ptr->next;
00425        ptr->end -= chunk_ptr->next;
00426        if (memcpy_len > 0) {
00427               memmove(chunk_ptr, next_chunk_ptr, memcpy_len);
00428        }
00429        return 0;
00430 }
00431 /* }}} */
00432 
00433 #endif /* HAVE_SYSVSHM */
00434 
00435 /*
00436  * Local variables:
00437  * tab-width: 4
00438  * c-basic-offset: 4
00439  * End:
00440  * vim600: sw=4 ts=4 fdm=marker
00441  * vim<600: sw=4 ts=4
00442  */