cvs: php4 /ext/ircg ircg.c php_ircg.h php_ircg_private.h php_ircg_tokenizer.c php_ircg_tokenizer.h
| From: | Sascha Schumann | Date: | Wed, 23 Apr 2003 04:02:10 +0000 |
| Subject: | cvs: php4 /ext/ircg ircg.c php_ircg.h php_ircg_private.h php_ircg_tokenizer.c php_ircg_tokenizer.h | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-20437@lists.php.net to get a copy of this message | ||
sas Wed Apr 23 00:02:10 2003 EDT
Modified files:
/php4/ext/ircg ircg.c php_ircg.h php_ircg_private.h
php_ircg_tokenizer.c php_ircg_tokenizer.h
Log:
Improve format messages handling
Untrusted users can no longer fill the shm segment with unused format sets
Also, the tokenizer now uses inline strings for storing smaller strings
which can have a profound effect on the memory use of format sets.
Index: php4/ext/ircg/ircg.c diff -u php4/ext/ircg/ircg.c:1.175 php4/ext/ircg/ircg.c:1.176 --- php4/ext/ircg/ircg.c:1.175 Tue Apr 22 02:55:36 2003 +++ php4/ext/ircg/ircg.c Wed Apr 23 00:02:10 2003 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: ircg.c,v 1.175 2003/04/22 06:55:36 sas Exp $ */ +/* $Id: ircg.c,v 1.176 2003/04/23 04:02:10 sas Exp $ */ /* {{{ includes */ @@ -219,6 +219,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("ircg.work_dir", "/tmp/ircg", PHP_INI_ALL, OnUpdateString, work_dir, zend_ircg_globals, ircg_globals) STD_PHP_INI_ENTRY("ircg.shared_mem_size", "6000000", PHP_INI_ALL, OnUpdateInt, shared_mem_size, zend_ircg_globals, ircg_globals) + STD_PHP_INI_ENTRY("ircg.max_format_message_sets", "12", PHP_INI_ALL, OnUpdateInt, max_fmt_msg_sets, zend_ircg_globals, ircg_globals) STD_PHP_INI_ENTRY("ircg.control_user", "nobody", PHP_INI_ALL, OnUpdateString, control_user, zend_ircg_globals, ircg_globals) PHP_INI_END() @@ -247,15 +248,18 @@ int i; for (i = 0; i < NO_FMTS; i++) { - php_ircg_free_fmt_msg(fmt_msgs->fmt_msgs[i]); + if (fmt_msgs->fmt_msgs[i]) + php_ircg_free_fmt_msg(fmt_msgs->fmt_msgs[i]); } + php_ircg->fmt_sets_destroyed++; + IRCG_SHARED_FREE(dummy); } static php_irconn_t *lookup_irconn(int id) { - php_irconn_t **ret; - #ifdef USE_IRCONN_MANAGEMENT + php_irconn_t **ret; + if (ircg_hash_index_find(&h_irconn, id, (void **) &ret) == FAILURE) return NULL; return *ret; @@ -273,13 +277,40 @@ } #endif -static php_fmt_msgs_t *lookup_fmt_msgs(zval **id) +static php_fmt_msgs_t *lookup_fmt_msgs(zval **id, int inc) { - php_fmt_msgs_t *ret; + int *i; + php_fmt_msgs_t *p; - if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(id), Z_STRLEN_PP(id), (void **) &ret) == FAILURE) + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); + if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(id), Z_STRLEN_PP(id), + (void **) &i) == FAILURE) { + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); return NULL; - return ret; + } + p = php_ircg->fmt_msgs[*i]; + + assert(p != NULL); + assert(p->dead == 0); + + if (inc) { + p->rc++; + } + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); + + return p; +} + +static void fmt_msgs_drop_ref(php_fmt_msgs_t *p) +{ + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); + + assert(p->rc > 0); + if (--p->rc == 0 && p->dead) { + fmt_msgs_dtor(p); + } + + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); } static void irconn_dtor(void *dummy) @@ -345,6 +376,10 @@ #ifdef USE_IRCONN_MANAGEMENT ircg_hash_index_del(&h_irconn, conn->irconn_id); #endif + + if (conn->fmt_msgs->rc > 0) { + fmt_msgs_drop_ref(conn->fmt_msgs); + } ircg_hash_destroy(&conn->ctcp_msgs); smart_str_free_ex(&conn->buffer, 1); @@ -1021,8 +1056,6 @@ static void wbuf_add_complete(irc_write_buf *p, void *data) { - php_irconn_t *conn = data; - put_irconn(data); } @@ -1520,12 +1553,23 @@ convert_to_string_ex(p1); - if (lookup_fmt_msgs(p1)) + if (lookup_fmt_msgs(p1, 0)) RETURN_TRUE; RETVAL_FALSE; } /* }}} */ +static int delete_idx(void *dest, void *arg) +{ + int *idx = dest; + + if (*idx == (int) arg) { + php_ircg->fmt_sets_evicted++; + return 1; + } + return 0; +} + /* {{{ proto bool ircg_register_format_messages(string name, array messages) Registers a set of format strings for display of IRC messages */ PHP_FUNCTION(ircg_register_format_messages) @@ -1533,9 +1577,12 @@ zval **p1, **p2; HashTable *h; int i; - php_fmt_msgs_t fmt_msgs; + int *ip; + php_fmt_msgs_t *fmt_msgs; zval **arg; - + php_fmt_msgs_t *old = NULL; + int ret = SUCCESS; + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &p1, &p2) == FAILURE) WRONG_PARAM_COUNT; @@ -1549,21 +1596,70 @@ h = HASH_OF(*p2); + fmt_msgs = IRCG_SHARED_ALLOC(sizeof *fmt_msgs); + php_ircg->fmt_sets_created++; + fmt_msgs->rc = 0; + fmt_msgs->dead = 0; + for (i = 0; i < NO_FMTS; i++) { - fmt_msgs.fmt_msgs[i] = 0; + fmt_msgs->fmt_msgs[i] = 0; if (zend_hash_index_find(h, i, (void **) &arg) == SUCCESS) { convert_to_string_ex(arg); - php_ircg_token_compiler(Z_STRVAL_PP(arg), &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler(Z_STRVAL_PP(arg), &fmt_msgs->fmt_msgs[i]); } else - php_ircg_token_compiler("", &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler("", &fmt_msgs->fmt_msgs[i]); } + + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); - ircg_hash_update(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1), - &fmt_msgs, sizeof(fmt_msgs), NULL); + if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1), + (void **) &ip) == SUCCESS) { + i = *ip; + old = php_ircg->fmt_msgs[i]; + php_ircg->fmt_msgs[i] = fmt_msgs; + php_ircg->fmt_sets_updates++; + } else { + int lim = IRCGG(max_fmt_msg_sets); + + for (i = 0; i < lim; i++) { + if (php_ircg->fmt_msgs[i] == 0 + || php_ircg->fmt_msgs[i]->rc == 0) { + old = php_ircg->fmt_msgs[i]; + php_ircg->fmt_msgs[i] = fmt_msgs; + break; + } + } + + if (old) { + ircg_hash_apply_with_argument(&php_ircg->h_fmt_msgs, + delete_idx, (void *) i); + } else { + php_ircg->fmt_sets_exist++; + } + if (i != lim) { + ircg_hash_update(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), + Z_STRLEN_PP(p1), &i, sizeof(i), NULL); + } else { + /* no available slot */ + php_ircg->fmt_sets_ignored++; + fmt_msgs_dtor(fmt_msgs); + ret = FAILURE; + } + } + + if (old) { + if (old->rc) { + old->dead = 1; + } else { + fmt_msgs_dtor(old); + } + } IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); - RETVAL_TRUE; + if (ret == FAILURE) + RETURN_FALSE; + RETURN_TRUE; } /* }}} */ @@ -1725,6 +1821,7 @@ ??? */ PHP_FUNCTION(ircg_pconnect) { + int drop_ref = 0; /* This should become an array very soon */ zval **p1, **p2, **p3, **p4 = NULL, **p5 = NULL, **p6, **p7; const char *username = 0; @@ -1747,7 +1844,8 @@ case 5: case 4: convert_to_string_ex(p4); - fmt_msgs = lookup_fmt_msgs(p4); + if ((fmt_msgs = lookup_fmt_msgs(p4, 1))) + drop_ref = 1; case 3: convert_to_long_ex(p3); port = Z_LVAL_PP(p3); @@ -1794,6 +1892,8 @@ conn->fmt_msgs = fmt_msgs; if (irc_connect(username, register_hooks, conn, server, port, &conn->conn)) { + if (drop_ref) + fmt_msgs_drop_ref(fmt_msgs); IRCG_SHARED_FREE(conn); RETURN_FALSE; } @@ -2083,6 +2183,7 @@ PHP_RINIT_FUNCTION(ircg) { IRCGG(flush_data) = 0; + return SUCCESS; } /* {{{ PHP_RSHUTDOWN @@ -2199,7 +2300,7 @@ setup(1); #endif - ircg_hash_init(&php_ircg->h_fmt_msgs, 0, NULL, fmt_msgs_dtor, 1); + ircg_hash_init(&php_ircg->h_fmt_msgs, 0, NULL, NULL, 1); #ifdef USE_FD2IRCONN ircg_hash_init(&h_fd2irconn, 0, NULL, NULL, 1); #endif @@ -2274,6 +2375,18 @@ php_ircg->failed_set_currents); php_ircg_print_table_row("Write buffer destructs", php_ircg->irc_wbuf_destructs); + php_ircg_print_table_row("Format sets exist", + php_ircg->fmt_sets_exist); + php_ircg_print_table_row("Format sets evicted", + php_ircg->fmt_sets_evicted); + php_ircg_print_table_row("Format sets updates", + php_ircg->fmt_sets_updates); + php_ircg_print_table_row("Format sets ignored", + php_ircg->fmt_sets_ignored); + php_ircg_print_table_row("Format sets created", + php_ircg->fmt_sets_created); + php_ircg_print_table_row("Format sets destroyed", + php_ircg->fmt_sets_destroyed); #if IRCG_API_VERSION >= 20021127 @@ -2304,8 +2417,14 @@ ircg_register_relocation_map("php_ircg_wbuf_handler", php_ircg_cb_wbuf); } else if (stage == 1) { + size_t sz; + php_ircg_cache_entries = malloc(sizeof(struct cache_entry) * NR_CACHE_ENTRIES); memset(php_ircg_cache_entries, 0, sizeof(struct cache_entry) * NR_CACHE_ENTRIES); + + sz = sizeof(void *) * IRCGG(max_fmt_msg_sets); + php_ircg->fmt_msgs = IRCG_SHARED_ALLOC(sz); + memset(php_ircg->fmt_msgs, 0, sz); } else if (stage == -1) { memset(php_ircg, 0x78, sizeof *php_ircg); IRCG_SHARED_FREE(php_ircg); Index: php4/ext/ircg/php_ircg.h diff -u php4/ext/ircg/php_ircg.h:1.26 php4/ext/ircg/php_ircg.h:1.27 --- php4/ext/ircg/php_ircg.h:1.26 Tue Dec 31 11:06:50 2002 +++ php4/ext/ircg/php_ircg.h Wed Apr 23 00:02:10 2003 @@ -67,6 +67,7 @@ void *flush_data; char *control_user; long shared_mem_size; + long max_fmt_msg_sets; char *work_dir; ZEND_END_MODULE_GLOBALS(ircg) Index: php4/ext/ircg/php_ircg_private.h diff -u php4/ext/ircg/php_ircg_private.h:1.7 php4/ext/ircg/php_ircg_private.h:1.8 --- php4/ext/ircg/php_ircg_private.h:1.7 Tue Apr 22 01:30:47 2003 +++ php4/ext/ircg/php_ircg_private.h Wed Apr 23 00:02:10 2003 @@ -28,12 +28,15 @@ #include "php_ircg_formats.h" typedef struct { + int rc; /* how many connections reference this struct */ + int dead; format_msg_t *fmt_msgs[NO_FMTS]; } php_fmt_msgs_t; struct php_ircg_global { + + php_fmt_msgs_t **fmt_msgs; ircg_hash_table h_fmt_msgs; - IRCG_LOCK(fmt_msgs_lock); /* these just serve statistical/entertainment purposes */ @@ -41,6 +44,8 @@ exec_fmt_msgs, exec_token_compiler, irc_wbuf_destructs, failed_set_currents, max_concurrency; + unsigned long fmt_sets_exist, fmt_sets_evicted, fmt_sets_updates, + fmt_sets_ignored, fmt_sets_created, fmt_sets_destroyed; unsigned long cache_hits, cache_misses; time_t next_gc; Index: php4/ext/ircg/php_ircg_tokenizer.c diff -u php4/ext/ircg/php_ircg_tokenizer.c:1.2 php4/ext/ircg/php_ircg_tokenizer.c:1.3 --- php4/ext/ircg/php_ircg_tokenizer.c:1.2 Sat Apr 19 14:03:48 2003 +++ php4/ext/ircg/php_ircg_tokenizer.c Wed Apr 23 00:02:10 2003 @@ -1,3 +1,5 @@ +#define SMART_STR_PREALLOC 4 + #include "php_ircg_private.h" #include "php_ircg_alloc.h" #include "php_ircg_conversion.h" @@ -19,6 +21,21 @@ f->t[n++].para.b +#define HANDLE_VERBATIM_STRING() \ + if (len <= INLINE_STRING_LEN) { \ + struct inline_string is; \ + \ + is.buf_len = len; \ + memcpy(is.buf, p, len); \ + NEW_TOKEN(C_STRING_INLINE, is) = is; \ + } else { \ + s.c = 0; \ + smart_str_appendl_ex(&s, p, len, 1); \ + NEW_TOKEN(C_STRING, s) = s; \ + } + + + void php_ircg_token_compiler(const char *fmt, format_msg_t **fp) { const char *p, *pe; @@ -45,18 +62,14 @@ q = p; while (*q != '%') if (++q >= pe) { - s.c = 0; - smart_str_appendl_ex(&s, p, pe - p, 1); - - NEW_TOKEN(C_STRING, s) = s; + len = pe - p; + HANDLE_VERBATIM_STRING(); goto leave_loop; } len = q - p; if (len > 0) { - s.c = 0; - smart_str_appendl_ex(&s, p, len, 1); - NEW_TOKEN(C_STRING, s) = s; + HANDLE_VERBATIM_STRING(); } mode = 0; @@ -163,6 +176,8 @@ for (; ntoken-- > 0; i++) { switch (t[i].code) { + case C_STRING_INLINE: smart_str_appendl_ex(result, t[i].para.is.buf, + t[i].para.is.buf_len, 1); break; case C_STRING: smart_str_append_ex(result, &t[i].para.s, 1); break; case C_FROM: IRCG_APPEND(from); break; case C_TO: IRCG_APPEND(to); break; Index: php4/ext/ircg/php_ircg_tokenizer.h diff -u php4/ext/ircg/php_ircg_tokenizer.h:1.3 php4/ext/ircg/php_ircg_tokenizer.h:1.4 --- php4/ext/ircg/php_ircg_tokenizer.h:1.3 Sat Apr 19 14:03:48 2003 +++ php4/ext/ircg/php_ircg_tokenizer.h Wed Apr 23 00:02:10 2003 @@ -3,12 +3,20 @@ #include "ircg_smart_str_public.h" +#define INLINE_STRING_LEN 15 + +struct inline_string { + char buf_len; + char buf[INLINE_STRING_LEN]; +}; + typedef struct { unsigned char code; union { unsigned char v; void *ptr; smart_str s; + struct inline_string is; } para; } token_t; @@ -23,6 +31,7 @@ C_TO, C_MESSAGE, C_STRING, + C_STRING_INLINE, C_PERCENT, C_TERMINATE_1 /* auth by username */ };
Index: php4/ext/ircg/ircg.c diff -u php4/ext/ircg/ircg.c:1.175 php4/ext/ircg/ircg.c:1.176 --- php4/ext/ircg/ircg.c:1.175 Tue Apr 22 02:55:36 2003 +++ php4/ext/ircg/ircg.c Wed Apr 23 00:02:10 2003 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: ircg.c,v 1.175 2003/04/22 06:55:36 sas Exp $ */ +/* $Id: ircg.c,v 1.176 2003/04/23 04:02:10 sas Exp $ */ /* {{{ includes */ @@ -219,6 +219,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("ircg.work_dir", "/tmp/ircg", PHP_INI_ALL, OnUpdateString, work_dir, zend_ircg_globals, ircg_globals) STD_PHP_INI_ENTRY("ircg.shared_mem_size", "6000000", PHP_INI_ALL, OnUpdateInt, shared_mem_size, zend_ircg_globals, ircg_globals) + STD_PHP_INI_ENTRY("ircg.max_format_message_sets", "12", PHP_INI_ALL, OnUpdateInt, max_fmt_msg_sets, zend_ircg_globals, ircg_globals) STD_PHP_INI_ENTRY("ircg.control_user", "nobody", PHP_INI_ALL, OnUpdateString, control_user, zend_ircg_globals, ircg_globals) PHP_INI_END() @@ -247,15 +248,18 @@ int i; for (i = 0; i < NO_FMTS; i++) { - php_ircg_free_fmt_msg(fmt_msgs->fmt_msgs[i]); + if (fmt_msgs->fmt_msgs[i]) + php_ircg_free_fmt_msg(fmt_msgs->fmt_msgs[i]); } + php_ircg->fmt_sets_destroyed++; + IRCG_SHARED_FREE(dummy); } static php_irconn_t *lookup_irconn(int id) { - php_irconn_t **ret; - #ifdef USE_IRCONN_MANAGEMENT + php_irconn_t **ret; + if (ircg_hash_index_find(&h_irconn, id, (void **) &ret) == FAILURE) return NULL; return *ret; @@ -273,13 +277,40 @@ } #endif -static php_fmt_msgs_t *lookup_fmt_msgs(zval **id) +static php_fmt_msgs_t *lookup_fmt_msgs(zval **id, int inc) { - php_fmt_msgs_t *ret; + int *i; + php_fmt_msgs_t *p; - if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(id), Z_STRLEN_PP(id), (void **) &ret) == FAILURE) + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); + if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(id), Z_STRLEN_PP(id), + (void **) &i) == FAILURE) { + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); return NULL; - return ret; + } + p = php_ircg->fmt_msgs[*i]; + + assert(p != NULL); + assert(p->dead == 0); + + if (inc) { + p->rc++; + } + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); + + return p; +} + +static void fmt_msgs_drop_ref(php_fmt_msgs_t *p) +{ + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); + + assert(p->rc > 0); + if (--p->rc == 0 && p->dead) { + fmt_msgs_dtor(p); + } + + IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); } static void irconn_dtor(void *dummy) @@ -345,6 +376,10 @@ #ifdef USE_IRCONN_MANAGEMENT ircg_hash_index_del(&h_irconn, conn->irconn_id); #endif + + if (conn->fmt_msgs->rc > 0) { + fmt_msgs_drop_ref(conn->fmt_msgs); + } ircg_hash_destroy(&conn->ctcp_msgs); smart_str_free_ex(&conn->buffer, 1); @@ -1021,8 +1056,6 @@ static void wbuf_add_complete(irc_write_buf *p, void *data) { - php_irconn_t *conn = data; - put_irconn(data); } @@ -1520,12 +1553,23 @@ convert_to_string_ex(p1); - if (lookup_fmt_msgs(p1)) + if (lookup_fmt_msgs(p1, 0)) RETURN_TRUE; RETVAL_FALSE; } /* }}} */ +static int delete_idx(void *dest, void *arg) +{ + int *idx = dest; + + if (*idx == (int) arg) { + php_ircg->fmt_sets_evicted++; + return 1; + } + return 0; +} + /* {{{ proto bool ircg_register_format_messages(string name, array messages) Registers a set of format strings for display of IRC messages */ PHP_FUNCTION(ircg_register_format_messages) @@ -1533,9 +1577,12 @@ zval **p1, **p2; HashTable *h; int i; - php_fmt_msgs_t fmt_msgs; + int *ip; + php_fmt_msgs_t *fmt_msgs; zval **arg; - + php_fmt_msgs_t *old = NULL; + int ret = SUCCESS; + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &p1, &p2) == FAILURE) WRONG_PARAM_COUNT; @@ -1549,21 +1596,70 @@ h = HASH_OF(*p2); + fmt_msgs = IRCG_SHARED_ALLOC(sizeof *fmt_msgs); + php_ircg->fmt_sets_created++; + fmt_msgs->rc = 0; + fmt_msgs->dead = 0; + for (i = 0; i < NO_FMTS; i++) { - fmt_msgs.fmt_msgs[i] = 0; + fmt_msgs->fmt_msgs[i] = 0; if (zend_hash_index_find(h, i, (void **) &arg) == SUCCESS) { convert_to_string_ex(arg); - php_ircg_token_compiler(Z_STRVAL_PP(arg), &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler(Z_STRVAL_PP(arg), &fmt_msgs->fmt_msgs[i]); } else - php_ircg_token_compiler("", &fmt_msgs.fmt_msgs[i]); + php_ircg_token_compiler("", &fmt_msgs->fmt_msgs[i]); } + + IRCG_LOCK_GET(php_ircg->fmt_msgs_lock); - ircg_hash_update(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1), - &fmt_msgs, sizeof(fmt_msgs), NULL); + if (ircg_hash_find(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), Z_STRLEN_PP(p1), + (void **) &ip) == SUCCESS) { + i = *ip; + old = php_ircg->fmt_msgs[i]; + php_ircg->fmt_msgs[i] = fmt_msgs; + php_ircg->fmt_sets_updates++; + } else { + int lim = IRCGG(max_fmt_msg_sets); + + for (i = 0; i < lim; i++) { + if (php_ircg->fmt_msgs[i] == 0 + || php_ircg->fmt_msgs[i]->rc == 0) { + old = php_ircg->fmt_msgs[i]; + php_ircg->fmt_msgs[i] = fmt_msgs; + break; + } + } + + if (old) { + ircg_hash_apply_with_argument(&php_ircg->h_fmt_msgs, + delete_idx, (void *) i); + } else { + php_ircg->fmt_sets_exist++; + } + if (i != lim) { + ircg_hash_update(&php_ircg->h_fmt_msgs, Z_STRVAL_PP(p1), + Z_STRLEN_PP(p1), &i, sizeof(i), NULL); + } else { + /* no available slot */ + php_ircg->fmt_sets_ignored++; + fmt_msgs_dtor(fmt_msgs); + ret = FAILURE; + } + } + + if (old) { + if (old->rc) { + old->dead = 1; + } else { + fmt_msgs_dtor(old); + } + } IRCG_LOCK_PUT(php_ircg->fmt_msgs_lock); - RETVAL_TRUE; + if (ret == FAILURE) + RETURN_FALSE; + RETURN_TRUE; } /* }}} */ @@ -1725,6 +1821,7 @@ ??? */ PHP_FUNCTION(ircg_pconnect) { + int drop_ref = 0; /* This should become an array very soon */ zval **p1, **p2, **p3, **p4 = NULL, **p5 = NULL, **p6, **p7; const char *username = 0; @@ -1747,7 +1844,8 @@ case 5: case 4: convert_to_string_ex(p4); - fmt_msgs = lookup_fmt_msgs(p4); + if ((fmt_msgs = lookup_fmt_msgs(p4, 1))) + drop_ref = 1; case 3: convert_to_long_ex(p3); port = Z_LVAL_PP(p3); @@ -1794,6 +1892,8 @@ conn->fmt_msgs = fmt_msgs; if (irc_connect(username, register_hooks, conn, server, port, &conn->conn)) { + if (drop_ref) + fmt_msgs_drop_ref(fmt_msgs); IRCG_SHARED_FREE(conn); RETURN_FALSE; } @@ -2083,6 +2183,7 @@ PHP_RINIT_FUNCTION(ircg) { IRCGG(flush_data) = 0; + return SUCCESS; } /* {{{ PHP_RSHUTDOWN @@ -2199,7 +2300,7 @@ setup(1); #endif - ircg_hash_init(&php_ircg->h_fmt_msgs, 0, NULL, fmt_msgs_dtor, 1); + ircg_hash_init(&php_ircg->h_fmt_msgs, 0, NULL, NULL, 1); #ifdef USE_FD2IRCONN ircg_hash_init(&h_fd2irconn, 0, NULL, NULL, 1); #endif @@ -2274,6 +2375,18 @@ php_ircg->failed_set_currents); php_ircg_print_table_row("Write buffer destructs", php_ircg->irc_wbuf_destructs); + php_ircg_print_table_row("Format sets exist", + php_ircg->fmt_sets_exist); + php_ircg_print_table_row("Format sets evicted", + php_ircg->fmt_sets_evicted); + php_ircg_print_table_row("Format sets updates", + php_ircg->fmt_sets_updates); + php_ircg_print_table_row("Format sets ignored", + php_ircg->fmt_sets_ignored); + php_ircg_print_table_row("Format sets created", + php_ircg->fmt_sets_created); + php_ircg_print_table_row("Format sets destroyed", + php_ircg->fmt_sets_destroyed); #if IRCG_API_VERSION >= 20021127 @@ -2304,8 +2417,14 @@ ircg_register_relocation_map("php_ircg_wbuf_handler", php_ircg_cb_wbuf); } else if (stage == 1) { + size_t sz; + php_ircg_cache_entries = malloc(sizeof(struct cache_entry) * NR_CACHE_ENTRIES); memset(php_ircg_cache_entries, 0, sizeof(struct cache_entry) * NR_CACHE_ENTRIES); + + sz = sizeof(void *) * IRCGG(max_fmt_msg_sets); + php_ircg->fmt_msgs = IRCG_SHARED_ALLOC(sz); + memset(php_ircg->fmt_msgs, 0, sz); } else if (stage == -1) { memset(php_ircg, 0x78, sizeof *php_ircg); IRCG_SHARED_FREE(php_ircg); Index: php4/ext/ircg/php_ircg.h diff -u php4/ext/ircg/php_ircg.h:1.26 php4/ext/ircg/php_ircg.h:1.27 --- php4/ext/ircg/php_ircg.h:1.26 Tue Dec 31 11:06:50 2002 +++ php4/ext/ircg/php_ircg.h Wed Apr 23 00:02:10 2003 @@ -67,6 +67,7 @@ void *flush_data; char *control_user; long shared_mem_size; + long max_fmt_msg_sets; char *work_dir; ZEND_END_MODULE_GLOBALS(ircg) Index: php4/ext/ircg/php_ircg_private.h diff -u php4/ext/ircg/php_ircg_private.h:1.7 php4/ext/ircg/php_ircg_private.h:1.8 --- php4/ext/ircg/php_ircg_private.h:1.7 Tue Apr 22 01:30:47 2003 +++ php4/ext/ircg/php_ircg_private.h Wed Apr 23 00:02:10 2003 @@ -28,12 +28,15 @@ #include "php_ircg_formats.h" typedef struct { + int rc; /* how many connections reference this struct */ + int dead; format_msg_t *fmt_msgs[NO_FMTS]; } php_fmt_msgs_t; struct php_ircg_global { + + php_fmt_msgs_t **fmt_msgs; ircg_hash_table h_fmt_msgs; - IRCG_LOCK(fmt_msgs_lock); /* these just serve statistical/entertainment purposes */ @@ -41,6 +44,8 @@ exec_fmt_msgs, exec_token_compiler, irc_wbuf_destructs, failed_set_currents, max_concurrency; + unsigned long fmt_sets_exist, fmt_sets_evicted, fmt_sets_updates, + fmt_sets_ignored, fmt_sets_created, fmt_sets_destroyed; unsigned long cache_hits, cache_misses; time_t next_gc; Index: php4/ext/ircg/php_ircg_tokenizer.c diff -u php4/ext/ircg/php_ircg_tokenizer.c:1.2 php4/ext/ircg/php_ircg_tokenizer.c:1.3 --- php4/ext/ircg/php_ircg_tokenizer.c:1.2 Sat Apr 19 14:03:48 2003 +++ php4/ext/ircg/php_ircg_tokenizer.c Wed Apr 23 00:02:10 2003 @@ -1,3 +1,5 @@ +#define SMART_STR_PREALLOC 4 + #include "php_ircg_private.h" #include "php_ircg_alloc.h" #include "php_ircg_conversion.h" @@ -19,6 +21,21 @@ f->t[n++].para.b +#define HANDLE_VERBATIM_STRING() \ + if (len <= INLINE_STRING_LEN) { \ + struct inline_string is; \ + \ + is.buf_len = len; \ + memcpy(is.buf, p, len); \ + NEW_TOKEN(C_STRING_INLINE, is) = is; \ + } else { \ + s.c = 0; \ + smart_str_appendl_ex(&s, p, len, 1); \ + NEW_TOKEN(C_STRING, s) = s; \ + } + + + void php_ircg_token_compiler(const char *fmt, format_msg_t **fp) { const char *p, *pe; @@ -45,18 +62,14 @@ q = p; while (*q != '%') if (++q >= pe) { - s.c = 0; - smart_str_appendl_ex(&s, p, pe - p, 1); - - NEW_TOKEN(C_STRING, s) = s; + len = pe - p; + HANDLE_VERBATIM_STRING(); goto leave_loop; } len = q - p; if (len > 0) { - s.c = 0; - smart_str_appendl_ex(&s, p, len, 1); - NEW_TOKEN(C_STRING, s) = s; + HANDLE_VERBATIM_STRING(); } mode = 0; @@ -163,6 +176,8 @@ for (; ntoken-- > 0; i++) { switch (t[i].code) { + case C_STRING_INLINE: smart_str_appendl_ex(result, t[i].para.is.buf, + t[i].para.is.buf_len, 1); break; case C_STRING: smart_str_append_ex(result, &t[i].para.s, 1); break; case C_FROM: IRCG_APPEND(from); break; case C_TO: IRCG_APPEND(to); break; Index: php4/ext/ircg/php_ircg_tokenizer.h diff -u php4/ext/ircg/php_ircg_tokenizer.h:1.3 php4/ext/ircg/php_ircg_tokenizer.h:1.4 --- php4/ext/ircg/php_ircg_tokenizer.h:1.3 Sat Apr 19 14:03:48 2003 +++ php4/ext/ircg/php_ircg_tokenizer.h Wed Apr 23 00:02:10 2003 @@ -3,12 +3,20 @@ #include "ircg_smart_str_public.h" +#define INLINE_STRING_LEN 15 + +struct inline_string { + char buf_len; + char buf[INLINE_STRING_LEN]; +}; + typedef struct { unsigned char code; union { unsigned char v; void *ptr; smart_str s; + struct inline_string is; } para; } token_t; @@ -23,6 +31,7 @@ C_TO, C_MESSAGE, C_STRING, + C_STRING_INLINE, C_PERCENT, C_TERMINATE_1 /* auth by username */ };