Annotation of embedaddon/php/ext/sysvshm/sysvshm.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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: | Author: Christian Cartus <cartus@atrior.de> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: sysvshm.c 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: /* This has been built and tested on Linux 2.2.14
! 22: *
! 23: * This has been built and tested on Solaris 2.6.
! 24: * It may not compile or execute correctly on other systems.
! 25: */
! 26:
! 27: #ifdef HAVE_CONFIG_H
! 28: #include "config.h"
! 29: #endif
! 30:
! 31: #include "php.h"
! 32:
! 33: #if HAVE_SYSVSHM
! 34:
! 35: #include <errno.h>
! 36:
! 37: #include "php_sysvshm.h"
! 38: #include "ext/standard/php_var.h"
! 39: #include "ext/standard/php_smart_str.h"
! 40: #include "php_ini.h"
! 41:
! 42: /* {{{ arginfo */
! 43: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_attach, 0, 0, 1)
! 44: ZEND_ARG_INFO(0, key)
! 45: ZEND_ARG_INFO(0, memsize)
! 46: ZEND_ARG_INFO(0, perm)
! 47: ZEND_END_ARG_INFO()
! 48:
! 49: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_detach, 0, 0, 1)
! 50: ZEND_ARG_INFO(0, shm_identifier)
! 51: ZEND_END_ARG_INFO()
! 52:
! 53: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_has_var, 0, 0, 2)
! 54: ZEND_ARG_INFO(0, id)
! 55: ZEND_ARG_INFO(0, variable_key)
! 56: ZEND_END_ARG_INFO()
! 57:
! 58: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_remove, 0, 0, 1)
! 59: ZEND_ARG_INFO(0, shm_identifier)
! 60: ZEND_END_ARG_INFO()
! 61:
! 62: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_put_var, 0, 0, 3)
! 63: ZEND_ARG_INFO(0, shm_identifier)
! 64: ZEND_ARG_INFO(0, variable_key)
! 65: ZEND_ARG_INFO(0, variable)
! 66: ZEND_END_ARG_INFO()
! 67:
! 68: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_get_var, 0, 0, 2)
! 69: ZEND_ARG_INFO(0, id)
! 70: ZEND_ARG_INFO(0, variable_key)
! 71: ZEND_END_ARG_INFO()
! 72:
! 73: ZEND_BEGIN_ARG_INFO_EX(arginfo_shm_remove_var, 0, 0, 2)
! 74: ZEND_ARG_INFO(0, id)
! 75: ZEND_ARG_INFO(0, variable_key)
! 76: ZEND_END_ARG_INFO()
! 77: /* }}} */
! 78:
! 79: /* {{{ sysvshm_functions[]
! 80: */
! 81: const zend_function_entry sysvshm_functions[] = {
! 82: PHP_FE(shm_attach, arginfo_shm_attach)
! 83: PHP_FE(shm_remove, arginfo_shm_detach)
! 84: PHP_FE(shm_detach, arginfo_shm_remove)
! 85: PHP_FE(shm_put_var, arginfo_shm_put_var)
! 86: PHP_FE(shm_has_var, arginfo_shm_has_var)
! 87: PHP_FE(shm_get_var, arginfo_shm_get_var)
! 88: PHP_FE(shm_remove_var, arginfo_shm_remove_var)
! 89: PHP_FE_END
! 90: };
! 91: /* }}} */
! 92:
! 93: /* {{{ sysvshm_module_entry
! 94: */
! 95: zend_module_entry sysvshm_module_entry = {
! 96: STANDARD_MODULE_HEADER,
! 97: "sysvshm",
! 98: sysvshm_functions,
! 99: PHP_MINIT(sysvshm),
! 100: NULL,
! 101: NULL,
! 102: NULL,
! 103: NULL,
! 104: NO_VERSION_YET,
! 105: STANDARD_MODULE_PROPERTIES
! 106: };
! 107: /* }}} */
! 108:
! 109: #ifdef COMPILE_DL_SYSVSHM
! 110: ZEND_GET_MODULE(sysvshm)
! 111: #endif
! 112:
! 113: #undef shm_ptr /* undefine AIX-specific macro */
! 114:
! 115: #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)
! 116:
! 117: THREAD_LS sysvshm_module php_sysvshm;
! 118:
! 119: static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, const char *data, long len);
! 120: static long php_check_shm_data(sysvshm_chunk_head *ptr, long key);
! 121: static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos);
! 122:
! 123: /* {{{ php_release_sysvshm
! 124: */
! 125: static void php_release_sysvshm(zend_rsrc_list_entry *rsrc TSRMLS_DC)
! 126: {
! 127: sysvshm_shm *shm_ptr = (sysvshm_shm *) rsrc->ptr;
! 128: shmdt((void *) shm_ptr->ptr);
! 129: efree(shm_ptr);
! 130: }
! 131: /* }}} */
! 132:
! 133: /* {{{ PHP_MINIT_FUNCTION
! 134: */
! 135: PHP_MINIT_FUNCTION(sysvshm)
! 136: {
! 137: php_sysvshm.le_shm = zend_register_list_destructors_ex(php_release_sysvshm, NULL, PHP_SHM_RSRC_NAME, module_number);
! 138:
! 139: if (cfg_get_long("sysvshm.init_mem", &php_sysvshm.init_mem) == FAILURE) {
! 140: php_sysvshm.init_mem=10000;
! 141: }
! 142: return SUCCESS;
! 143: }
! 144: /* }}} */
! 145:
! 146: /* {{{ proto int shm_attach(int key [, int memsize [, int perm]])
! 147: Creates or open a shared memory segment */
! 148: PHP_FUNCTION(shm_attach)
! 149: {
! 150: sysvshm_shm *shm_list_ptr;
! 151: char *shm_ptr;
! 152: sysvshm_chunk_head *chunk_ptr;
! 153: long shm_key, shm_id, shm_size = php_sysvshm.init_mem, shm_flag = 0666;
! 154:
! 155: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &shm_key, &shm_size, &shm_flag)) {
! 156: return;
! 157: }
! 158:
! 159: if (shm_size < 1) {
! 160: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Segment size must be greater than zero");
! 161: RETURN_FALSE;
! 162: }
! 163:
! 164: shm_list_ptr = (sysvshm_shm *) emalloc(sizeof(sysvshm_shm));
! 165:
! 166: /* get the id from a specified key or create new shared memory */
! 167: if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
! 168: if (shm_size < sizeof(sysvshm_chunk_head)) {
! 169: php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: memorysize too small", shm_key);
! 170: efree(shm_list_ptr);
! 171: RETURN_FALSE;
! 172: }
! 173: if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL)) < 0) {
! 174: php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", shm_key, strerror(errno));
! 175: efree(shm_list_ptr);
! 176: RETURN_FALSE;
! 177: }
! 178: }
! 179:
! 180: if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) -1) {
! 181: php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", shm_key, strerror(errno));
! 182: efree(shm_list_ptr);
! 183: RETURN_FALSE;
! 184: }
! 185:
! 186: /* check if shm is already initialized */
! 187: chunk_ptr = (sysvshm_chunk_head *) shm_ptr;
! 188: if (strcmp((char*) &(chunk_ptr->magic), "PHP_SM") != 0) {
! 189: strcpy((char*) &(chunk_ptr->magic), "PHP_SM");
! 190: chunk_ptr->start = sizeof(sysvshm_chunk_head);
! 191: chunk_ptr->end = chunk_ptr->start;
! 192: chunk_ptr->total = shm_size;
! 193: chunk_ptr->free = shm_size-chunk_ptr->end;
! 194: }
! 195:
! 196: shm_list_ptr->key = shm_key;
! 197: shm_list_ptr->id = shm_id;
! 198: shm_list_ptr->ptr = chunk_ptr;
! 199:
! 200: ZEND_REGISTER_RESOURCE(return_value, shm_list_ptr, php_sysvshm.le_shm);
! 201: }
! 202: /* }}} */
! 203:
! 204: /* {{{ proto bool shm_detach(resource shm_identifier)
! 205: Disconnects from shared memory segment */
! 206: PHP_FUNCTION(shm_detach)
! 207: {
! 208: zval *shm_id;
! 209: sysvshm_shm *shm_list_ptr;
! 210:
! 211: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &shm_id)) {
! 212: return;
! 213: }
! 214: SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
! 215: RETURN_BOOL(SUCCESS == zend_list_delete(Z_LVAL_P(shm_id)));
! 216: }
! 217: /* }}} */
! 218:
! 219: /* {{{ proto bool shm_remove(resource shm_identifier)
! 220: Removes shared memory from Unix systems */
! 221: PHP_FUNCTION(shm_remove)
! 222: {
! 223: zval *shm_id;
! 224: sysvshm_shm *shm_list_ptr;
! 225:
! 226: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &shm_id)) {
! 227: return;
! 228: }
! 229: SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
! 230:
! 231: if (shmctl(shm_list_ptr->id, IPC_RMID, NULL) < 0) {
! 232: 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));
! 233: RETURN_FALSE;
! 234: }
! 235:
! 236: RETURN_TRUE;
! 237: }
! 238: /* }}} */
! 239:
! 240: /* {{{ proto bool shm_put_var(resource shm_identifier, int variable_key, mixed variable)
! 241: Inserts or updates a variable in shared memory */
! 242: PHP_FUNCTION(shm_put_var)
! 243: {
! 244: zval *shm_id, *arg_var;
! 245: int ret;
! 246: long shm_key;
! 247: sysvshm_shm *shm_list_ptr;
! 248: smart_str shm_var = {0};
! 249: php_serialize_data_t var_hash;
! 250:
! 251: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &shm_id, &shm_key, &arg_var)) {
! 252: return;
! 253: }
! 254:
! 255: /* setup string-variable and serialize */
! 256: PHP_VAR_SERIALIZE_INIT(var_hash);
! 257: php_var_serialize(&shm_var, &arg_var, &var_hash TSRMLS_CC);
! 258: PHP_VAR_SERIALIZE_DESTROY(var_hash);
! 259:
! 260: shm_list_ptr = zend_fetch_resource(&shm_id TSRMLS_CC, -1, PHP_SHM_RSRC_NAME, NULL, 1, php_sysvshm.le_shm);
! 261: if (!shm_list_ptr) {
! 262: smart_str_free(&shm_var);
! 263: RETURN_FALSE;
! 264: }
! 265:
! 266: /* insert serialized variable into shared memory */
! 267: ret = php_put_shm_data(shm_list_ptr->ptr, shm_key, shm_var.c, shm_var.len);
! 268:
! 269: /* free string */
! 270: smart_str_free(&shm_var);
! 271:
! 272: if (ret == -1) {
! 273: php_error_docref(NULL TSRMLS_CC, E_WARNING, "not enough shared memory left");
! 274: RETURN_FALSE;
! 275: }
! 276: RETURN_TRUE;
! 277: }
! 278: /* }}} */
! 279:
! 280: /* {{{ proto mixed shm_get_var(resource id, int variable_key)
! 281: Returns a variable from shared memory */
! 282: PHP_FUNCTION(shm_get_var)
! 283: {
! 284: zval *shm_id;
! 285: long shm_key;
! 286: sysvshm_shm *shm_list_ptr;
! 287: char *shm_data;
! 288: long shm_varpos;
! 289: sysvshm_chunk *shm_var;
! 290: php_unserialize_data_t var_hash;
! 291:
! 292: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
! 293: return;
! 294: }
! 295: SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
! 296:
! 297: /* setup string-variable and serialize */
! 298: /* get serialized variable from shared memory */
! 299: shm_varpos = php_check_shm_data((shm_list_ptr->ptr), shm_key);
! 300:
! 301: if (shm_varpos < 0) {
! 302: php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", shm_key);
! 303: RETURN_FALSE;
! 304: }
! 305: shm_var = (sysvshm_chunk*) ((char *)shm_list_ptr->ptr + shm_varpos);
! 306: shm_data = &shm_var->mem;
! 307:
! 308: PHP_VAR_UNSERIALIZE_INIT(var_hash);
! 309: if (php_var_unserialize(&return_value, (const unsigned char **) &shm_data, (unsigned char *) shm_data + shm_var->length, &var_hash TSRMLS_CC) != 1) {
! 310: php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable data in shared memory is corrupted");
! 311: RETVAL_FALSE;
! 312: }
! 313: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
! 314: }
! 315: /* }}} */
! 316:
! 317: /* {{{ proto bool shm_has_var(resource id, int variable_key)
! 318: Checks whether a specific entry exists */
! 319: PHP_FUNCTION(shm_has_var)
! 320: {
! 321: zval *shm_id;
! 322: long shm_key;
! 323: sysvshm_shm *shm_list_ptr;
! 324:
! 325: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
! 326: return;
! 327: }
! 328: SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
! 329: RETURN_BOOL(php_check_shm_data(shm_list_ptr->ptr, shm_key) >= 0);
! 330: }
! 331: /* }}} */
! 332:
! 333: /* {{{ proto bool shm_remove_var(resource id, int variable_key)
! 334: Removes variable from shared memory */
! 335: PHP_FUNCTION(shm_remove_var)
! 336: {
! 337: zval *shm_id;
! 338: long shm_key, shm_varpos;
! 339: sysvshm_shm *shm_list_ptr;
! 340:
! 341: if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &shm_id, &shm_key)) {
! 342: return;
! 343: }
! 344: SHM_FETCH_RESOURCE(shm_list_ptr, shm_id);
! 345:
! 346: shm_varpos = php_check_shm_data((shm_list_ptr->ptr), shm_key);
! 347:
! 348: if (shm_varpos < 0) {
! 349: php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", shm_key);
! 350: RETURN_FALSE;
! 351: }
! 352: php_remove_shm_data((shm_list_ptr->ptr), shm_varpos);
! 353: RETURN_TRUE;
! 354: }
! 355: /* }}} */
! 356:
! 357: /* {{{ php_put_shm_data
! 358: * inserts an ascii-string into shared memory */
! 359: static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, const char *data, long len)
! 360: {
! 361: sysvshm_chunk *shm_var;
! 362: long total_size;
! 363: long shm_varpos;
! 364:
! 365: total_size = ((long) (len + sizeof(sysvshm_chunk) - 1) / sizeof(long)) * sizeof(long) + sizeof(long); /* long alligment */
! 366:
! 367: if ((shm_varpos = php_check_shm_data(ptr, key)) > 0) {
! 368: php_remove_shm_data(ptr, shm_varpos);
! 369: }
! 370:
! 371: if (ptr->free < total_size) {
! 372: return -1; /* not enough memory */
! 373: }
! 374:
! 375: shm_var = (sysvshm_chunk *) ((char *) ptr + ptr->end);
! 376: shm_var->key = key;
! 377: shm_var->length = len;
! 378: shm_var->next = total_size;
! 379: memcpy(&(shm_var->mem), data, len);
! 380: ptr->end += total_size;
! 381: ptr->free -= total_size;
! 382: return 0;
! 383: }
! 384: /* }}} */
! 385:
! 386: /* {{{ php_check_shm_data
! 387: */
! 388: static long php_check_shm_data(sysvshm_chunk_head *ptr, long key)
! 389: {
! 390: long pos;
! 391: sysvshm_chunk *shm_var;
! 392:
! 393: pos = ptr->start;
! 394:
! 395: for (;;) {
! 396: if (pos >= ptr->end) {
! 397: return -1;
! 398: }
! 399: shm_var = (sysvshm_chunk*) ((char *) ptr + pos);
! 400: if (shm_var->key == key) {
! 401: return pos;
! 402: }
! 403: pos += shm_var->next;
! 404:
! 405: if (shm_var->next <= 0 || pos < ptr->start) {
! 406: return -1;
! 407: }
! 408: }
! 409: return -1;
! 410: }
! 411: /* }}} */
! 412:
! 413: /* {{{ php_remove_shm_data
! 414: */
! 415: static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos)
! 416: {
! 417: sysvshm_chunk *chunk_ptr, *next_chunk_ptr;
! 418: long memcpy_len;
! 419:
! 420: chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos);
! 421: next_chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos + chunk_ptr->next);
! 422:
! 423: memcpy_len = ptr->end-shm_varpos - chunk_ptr->next;
! 424: ptr->free += chunk_ptr->next;
! 425: ptr->end -= chunk_ptr->next;
! 426: if (memcpy_len > 0) {
! 427: memmove(chunk_ptr, next_chunk_ptr, memcpy_len);
! 428: }
! 429: return 0;
! 430: }
! 431: /* }}} */
! 432:
! 433: #endif /* HAVE_SYSVSHM */
! 434:
! 435: /*
! 436: * Local variables:
! 437: * tab-width: 4
! 438: * c-basic-offset: 4
! 439: * End:
! 440: * vim600: sw=4 ts=4 fdm=marker
! 441: * vim<600: sw=4 ts=4
! 442: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>