Annotation of embedaddon/php/ext/sysvshm/sysvshm.c, revision 1.1.1.2

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:  
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      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>