Return to ibase_events.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / interbase |
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: | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: ! 19: /* $Id: ibase_events.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 20: ! 21: #ifdef HAVE_CONFIG_H ! 22: #include "config.h" ! 23: #endif ! 24: ! 25: #include "php.h" ! 26: ! 27: #if HAVE_IBASE ! 28: ! 29: #include "php_interbase.h" ! 30: #include "php_ibase_includes.h" ! 31: ! 32: static int le_event; ! 33: ! 34: static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */ ! 35: { ! 36: isc_free(event_buf); ! 37: isc_free(result_buf); ! 38: } ! 39: /* }}} */ ! 40: ! 41: void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */ ! 42: { ! 43: unsigned short i; ! 44: ! 45: event->state = DEAD; ! 46: ! 47: if (event->link != NULL) { ! 48: ibase_event **node; ! 49: ! 50: if (event->link->handle != NULL && ! 51: isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) { ! 52: _php_ibase_error(TSRMLS_C); ! 53: } ! 54: ! 55: /* delete this event from the link struct */ ! 56: for (node = &event->link->event_head; *node != event; node = &(*node)->event_next); ! 57: *node = event->event_next; ! 58: } ! 59: ! 60: if (event->callback) { ! 61: zval_dtor(event->callback); ! 62: FREE_ZVAL(event->callback); ! 63: event->callback = NULL; ! 64: ! 65: _php_ibase_event_free(event->event_buffer,event->result_buffer); ! 66: ! 67: for (i = 0; i < event->event_count; ++i) { ! 68: efree(event->events[i]); ! 69: } ! 70: efree(event->events); ! 71: } ! 72: } ! 73: /* }}} */ ! 74: ! 75: static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ ! 76: { ! 77: ibase_event *e = (ibase_event *) rsrc->ptr; ! 78: ! 79: _php_ibase_free_event(e TSRMLS_CC); ! 80: ! 81: efree(e); ! 82: } ! 83: /* }}} */ ! 84: ! 85: void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */ ! 86: { ! 87: le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, ! 88: "interbase event", module_number); ! 89: } ! 90: /* }}} */ ! 91: ! 92: static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, /* {{{ */ ! 93: char **events, unsigned short *l, char **event_buf, char **result_buf) ! 94: { ! 95: ISC_STATUS dummy_result[20]; ! 96: unsigned long dummy_count[15]; ! 97: ! 98: /** ! 99: * Unfortunately, there's no clean and portable way in C to pass arguments to ! 100: * a variadic function if you don't know the number of arguments at compile time. ! 101: * (And even if there were a way, the Interbase API doesn't provide a version of ! 102: * this function that takes a va_list as an argument) ! 103: * ! 104: * In this case, the number of arguments is limited to 18 by the underlying API, ! 105: * so we can work around it. ! 106: */ ! 107: ! 108: *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0], ! 109: events[1], events[2], events[3], events[4], events[5], events[6], events[7], ! 110: events[8], events[9], events[10], events[11], events[12], events[13], events[14]); ! 111: ! 112: /** ! 113: * Currently, this is the only way to correctly initialize an event buffer. ! 114: * This is clearly something that should be fixed, cause the semantics of ! 115: * isc_wait_for_event() indicate that it blocks until an event occurs. ! 116: * If the Firebird people ever fix this, these lines should be removed, ! 117: * otherwise, events will have to fire twice before ibase_wait_event() returns. ! 118: */ ! 119: ! 120: isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf); ! 121: isc_event_counts(dummy_count, *l, *event_buf, *result_buf); ! 122: } ! 123: /* }}} */ ! 124: ! 125: /* {{{ proto string ibase_wait_event([resource link_identifier,] string event [, string event [, ...]]) ! 126: Waits for any one of the passed Interbase events to be posted by the database, and returns its name */ ! 127: PHP_FUNCTION(ibase_wait_event) ! 128: { ! 129: zval ***args; ! 130: ibase_db_link *ib_link; ! 131: int num_args; ! 132: char *event_buffer, *result_buffer, *events[15]; ! 133: unsigned short i = 0, event_count = 0, buffer_size; ! 134: unsigned long occurred_event[15]; ! 135: ! 136: RESET_ERRMSG; ! 137: ! 138: /* no more than 15 events */ ! 139: if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) { ! 140: WRONG_PARAM_COUNT; ! 141: } ! 142: ! 143: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) { ! 144: return; ! 145: } ! 146: ! 147: if (Z_TYPE_PP(args[0]) == IS_RESOURCE) { ! 148: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) { ! 149: efree(args); ! 150: RETURN_FALSE; ! 151: } ! 152: i = 1; ! 153: } else { ! 154: if (ZEND_NUM_ARGS() > 15) { ! 155: efree(args); ! 156: WRONG_PARAM_COUNT; ! 157: } ! 158: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) { ! 159: efree(args); ! 160: RETURN_FALSE; ! 161: } ! 162: } ! 163: ! 164: for (; i < ZEND_NUM_ARGS(); ++i) { ! 165: convert_to_string_ex(args[i]); ! 166: events[event_count++] = Z_STRVAL_PP(args[i]); ! 167: } ! 168: ! 169: /* fills the required data structure with information about the events */ ! 170: _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer); ! 171: ! 172: /* now block until an event occurs */ ! 173: if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) { ! 174: _php_ibase_error(TSRMLS_C); ! 175: _php_ibase_event_free(event_buffer,result_buffer); ! 176: efree(args); ! 177: RETURN_FALSE; ! 178: } ! 179: ! 180: /* find out which event occurred */ ! 181: isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer); ! 182: for (i = 0; i < event_count; ++i) { ! 183: if (occurred_event[i]) { ! 184: char *result = estrdup(events[i]); ! 185: _php_ibase_event_free(event_buffer,result_buffer); ! 186: efree(args); ! 187: RETURN_STRING(result,0); ! 188: } ! 189: } ! 190: ! 191: /* If we reach this line, isc_wait_for_event() did return, but we don't know ! 192: which event fired. */ ! 193: _php_ibase_event_free(event_buffer,result_buffer); ! 194: efree(args); ! 195: RETURN_FALSE; ! 196: } ! 197: /* }}} */ ! 198: ! 199: static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ ! 200: unsigned short buffer_size, char *result_buf) ! 201: { ! 202: /* this function is called asynchronously by the Interbase client library. */ ! 203: TSRMLS_FETCH_FROM_CTX(event->thread_ctx); ! 204: ! 205: /** ! 206: * The callback function is called when the event is first registered and when the event ! 207: * is cancelled. I consider this is a bug. By clearing event->callback first and setting ! 208: * it to -1 later, we make sure nothing happens if no event was actually posted. ! 209: */ ! 210: switch (event->state) { ! 211: unsigned short i; ! 212: unsigned long occurred_event[15]; ! 213: zval event_name, link_id, return_value, *args[2]; ! 214: ! 215: default: /* == DEAD */ ! 216: break; ! 217: case ACTIVE: ! 218: args[0] = &event_name; ! 219: args[1] = &link_id; ! 220: ! 221: /* copy the updated results into the result buffer */ ! 222: memcpy(event->result_buffer, result_buf, buffer_size); ! 223: ! 224: INIT_ZVAL(event_name); ! 225: INIT_ZVAL(link_id); ! 226: ZVAL_RESOURCE(&link_id, event->link_res_id); ! 227: ! 228: /* find out which event occurred */ ! 229: isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer); ! 230: for (i = 0; i < event->event_count; ++i) { ! 231: if (occurred_event[i]) { ! 232: ZVAL_STRING(&event_name,event->events[i],0); ! 233: break; ! 234: } ! 235: } ! 236: ! 237: /* call the callback provided by the user */ ! 238: if (SUCCESS != call_user_function(EG(function_table), NULL, ! 239: event->callback, &return_value, 2, args TSRMLS_CC)) { ! 240: _php_ibase_module_error("Error calling callback %s" TSRMLS_CC, Z_STRVAL_P(event->callback)); ! 241: break; ! 242: } ! 243: ! 244: if (Z_TYPE(return_value) == IS_BOOL && !Z_BVAL(return_value)) { ! 245: event->state = DEAD; ! 246: break; ! 247: } ! 248: case NEW: ! 249: /* re-register the event */ ! 250: if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size, ! 251: event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) { ! 252: ! 253: _php_ibase_error(TSRMLS_C); ! 254: } ! 255: event->state = ACTIVE; ! 256: } ! 257: return 0; ! 258: } ! 259: /* }}} */ ! 260: ! 261: /* {{{ proto resource ibase_set_event_handler([resource link_identifier,] callback handler, string event [, string event [, ...]]) ! 262: Register the callback for handling each of the named events */ ! 263: PHP_FUNCTION(ibase_set_event_handler) ! 264: { ! 265: /** ! 266: * The callback passed to this function should take an event name (string) and a ! 267: * link resource id (int) as arguments. The value returned from the function is ! 268: * used to determine if the event handler should remain set. ! 269: */ ! 270: char *cb_name; ! 271: zval ***args, **cb_arg; ! 272: ibase_db_link *ib_link; ! 273: ibase_event *event; ! 274: unsigned short i = 1, buffer_size; ! 275: int link_res_id, num_args; ! 276: ! 277: RESET_ERRMSG; ! 278: ! 279: /* Minimum and maximum number of arguments allowed */ ! 280: if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) { ! 281: WRONG_PARAM_COUNT; ! 282: } ! 283: ! 284: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) { ! 285: return; ! 286: } ! 287: ! 288: /* get a working link */ ! 289: if (Z_TYPE_PP(args[0]) != IS_STRING) { ! 290: /* resource, callback, event_1 [, ... event_15] ! 291: * No more than 15 events ! 292: */ ! 293: if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) { ! 294: efree(args); ! 295: WRONG_PARAM_COUNT; ! 296: } ! 297: ! 298: cb_arg = args[1]; ! 299: i = 2; ! 300: ! 301: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) { ! 302: efree(args); ! 303: RETURN_FALSE; ! 304: } ! 305: ! 306: convert_to_long_ex(args[0]); ! 307: link_res_id = Z_LVAL_PP(args[0]); ! 308: ! 309: } else { ! 310: /* callback, event_1 [, ... event_15] ! 311: * No more than 15 events ! 312: */ ! 313: if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) { ! 314: efree(args); ! 315: WRONG_PARAM_COUNT; ! 316: } ! 317: ! 318: cb_arg = args[0]; ! 319: ! 320: if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) { ! 321: efree(args); ! 322: RETURN_FALSE; ! 323: } ! 324: link_res_id = IBG(default_link); ! 325: } ! 326: ! 327: /* get the callback */ ! 328: if (!zend_is_callable(*cb_arg, 0, &cb_name TSRMLS_CC)) { ! 329: _php_ibase_module_error("Callback argument %s is not a callable function" TSRMLS_CC, cb_name); ! 330: efree(cb_name); ! 331: efree(args); ! 332: RETURN_FALSE; ! 333: } ! 334: efree(cb_name); ! 335: ! 336: /* allocate the event resource */ ! 337: event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0); ! 338: TSRMLS_SET_CTX(event->thread_ctx); ! 339: event->link_res_id = link_res_id; ! 340: event->link = ib_link; ! 341: event->event_count = 0; ! 342: event->state = NEW; ! 343: event->events = (char **) safe_emalloc(sizeof(char *),ZEND_NUM_ARGS()-i,0); ! 344: ! 345: ALLOC_ZVAL(event->callback); ! 346: *event->callback = **cb_arg; ! 347: INIT_PZVAL(event->callback); ! 348: zval_copy_ctor(event->callback); ! 349: ! 350: for (; i < ZEND_NUM_ARGS(); ++i) { ! 351: convert_to_string_ex(args[i]); ! 352: event->events[event->event_count++] = estrdup(Z_STRVAL_PP(args[i])); ! 353: } ! 354: ! 355: /* fills the required data structure with information about the events */ ! 356: _php_ibase_event_block(ib_link, event->event_count, event->events, ! 357: &buffer_size, &event->event_buffer, &event->result_buffer); ! 358: ! 359: /* now register the events with the Interbase API */ ! 360: if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size, ! 361: event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) { ! 362: ! 363: _php_ibase_error(TSRMLS_C); ! 364: efree(event); ! 365: efree(args); ! 366: RETURN_FALSE; ! 367: } ! 368: ! 369: event->event_next = ib_link->event_head; ! 370: ib_link->event_head = event; ! 371: ! 372: ZEND_REGISTER_RESOURCE(return_value, event, le_event); ! 373: zend_list_addref(Z_LVAL_P(return_value)); ! 374: efree(args); ! 375: } ! 376: /* }}} */ ! 377: ! 378: /* {{{ proto bool ibase_free_event_handler(resource event) ! 379: Frees the event handler set by ibase_set_event_handler() */ ! 380: PHP_FUNCTION(ibase_free_event_handler) ! 381: { ! 382: zval *event_arg; ! 383: ! 384: RESET_ERRMSG; ! 385: ! 386: if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &event_arg)) { ! 387: ibase_event *event; ! 388: ! 389: ZEND_FETCH_RESOURCE(event, ibase_event *, &event_arg, -1, "Interbase event", le_event); ! 390: ! 391: event->state = DEAD; ! 392: ! 393: zend_list_delete(Z_LVAL_P(event_arg)); ! 394: RETURN_TRUE; ! 395: } else { ! 396: RETURN_FALSE; ! 397: } ! 398: } ! 399: /* }}} */ ! 400: ! 401: #endif /* HAVE_IBASE */ ! 402: ! 403: /* ! 404: * Local variables: ! 405: * tab-width: 4 ! 406: * c-basic-offset: 4 ! 407: * End: ! 408: * vim600: sw=4 ts=4 fdm=marker ! 409: * vim<600: sw=4 ts=4 ! 410: */