Return to sysvshm.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / sysvshm |
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: */