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>