static void aio_onReadFileCompleted(swAio_event *event) { zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); if (event->ret < 0) { ZVAL_BOOL(result, 0); } else { ZVAL_STRINGL(result, event->buf, event->ret); sw_free(event->buf); } php_context *context = (php_context *) event->object; int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(event->req); efree(context); }
static int co_socket_onWritable(swReactor *reactor, swEvent *event) { util_socket *sock = (util_socket *) event->socket->object; php_context *context = &sock->context; zval *retval = NULL; zval result; reactor->del(reactor, sock->fd); if (sock->timer) { swTimer_del(&SwooleG.timer, sock->timer); sock->timer = NULL; } int n = write(sock->fd, context->private_data, sock->nbytes); if (n < 0) { SwooleG.error = errno; ZVAL_FALSE(&result); } else { ZVAL_LONG(&result, n); } int ret = coro_resume(context, &result, &retval); zval_ptr_dtor(&result); if (ret == CORO_END && retval) { zval_ptr_dtor(retval); } efree(sock); return SW_OK; }
static PHP_METHOD(swoole_coroutine_util, resume) { long id; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &id) == FAILURE) { return; } swLinkedList *coros_list = swHashMap_find_int(defer_coros, id); if (coros_list == NULL) { swoole_php_fatal_error(E_WARNING, "Nothing can coroResume."); RETURN_FALSE; } php_context *context = swLinkedList_shift(coros_list); if (context == NULL) { swoole_php_fatal_error(E_WARNING, "Nothing can coroResume."); RETURN_FALSE; } zval *retval = NULL; zval *result; SW_MAKE_STD_ZVAL(result); ZVAL_BOOL(result, 1); int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(context); RETURN_TRUE; }
static void aio_onWriteFileCompleted(swAio_event *event) { zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); if (event->ret < 0) { SwooleG.error = event->error; ZVAL_BOOL(result, 0); } else { ZVAL_LONG(result, event->ret); } php_context *context = (php_context *) event->object; int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(event->req); efree(context); }
static void coro_dns_onGetaddrinfoCompleted(swAio_event *event) { php_context *context = event->object; zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); struct sockaddr_in *addr_v4; struct sockaddr_in6 *addr_v6; swRequest_getaddrinfo *req = event->req; if (req->error == 0) { array_init(result); int i; char tmp[INET6_ADDRSTRLEN]; const char *r ; for (i = 0; i < req->count; i++) { if (req->family == AF_INET) { addr_v4 = req->result + (i * sizeof(struct sockaddr_in)); r = inet_ntop(AF_INET, (const void*) &addr_v4->sin_addr, tmp, sizeof(tmp)); } else { addr_v6 = req->result + (i * sizeof(struct sockaddr_in6)); r = inet_ntop(AF_INET6, (const void*) &addr_v6->sin6_addr, tmp, sizeof(tmp)); } if (r) { add_next_index_string(result, tmp); } } } else { ZVAL_BOOL(result, 0); SwooleG.error = req->error; } int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(req->hostname); efree(req->result); if (req->service) { efree(req->service); } efree(req); efree(context); }
static void aio_onStreamGetLineCompleted(swAio_event *event) { zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); if (event->error == 0) { SW_ZVAL_STRINGL(result, event->buf, event->ret, 1); } else { SwooleG.error = event->error; ZVAL_BOOL(result, 0); } php_context *context = (php_context *) event->object; php_stream *stream; php_stream_from_zval_no_verify(stream, &context->coro_params); stream->readpos = event->offset; stream->writepos = (long) event->req; if (event->flags & SW_AIO_EOF) { stream->eof = 1; } int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(context); }
static void php_swoole_dns_timeout_coro(swTimer *timer, swTimer_node *tnode) { zval *retval = NULL; zval *zaddress; php_context *cxt = (php_context *) tnode->data; dns_request *req = (dns_request *) cxt->coro_params.value.ptr; SW_MAKE_STD_ZVAL(zaddress); dns_cache *cache = swHashMap_find(request_cache_map, Z_STRVAL_P(req->domain), Z_STRLEN_P(req->domain)); if (cache != NULL && cache->update_time > (int64_t) swTimer_get_now_msec) { SW_ZVAL_STRINGL(zaddress, (*cache->zaddress).str, (*cache->zaddress).length, 1); } else { SW_ZVAL_STRING(zaddress, "", 1); } int ret = coro_resume(req->context, zaddress, &retval); if (ret > 0) { goto free_zdata; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } free_zdata: sw_zval_ptr_dtor(&zaddress); efree(req->context); req->useless = 1; }
static void coro_dns_onResolveCompleted(swAio_event *event) { php_context *context = event->object; zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); if (event->error == 0) { SW_ZVAL_STRING(result, event->buf, 1); } else { SwooleG.error = event->error; ZVAL_BOOL(result, 0); } int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(event->buf); efree(context); }
int main(void){ CoroP b = coro_create("ping", ping); CoroP c = coro_create("pong", pong); int i,j = 0; for(i=0; i<5; i++){ coro_resume(b, j); j++; printf("main: %d\n", i); coro_resume(c, j); printf("main: %d\n", i); } j = coro_resume(b,0); j = coro_resume(c,0); return 0; }
static void swoole_coroutine_util_resume(void *data) { php_context *context = (php_context *)data; zval *retval = NULL; zval *result; SW_MAKE_STD_ZVAL(result); ZVAL_BOOL(result, 1); int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(context); }
static void php_coroutine_sleep_timeout(swTimer *timer, swTimer_node *tnode) { zval *retval = NULL; zval *result = NULL; SW_MAKE_STD_ZVAL(result); ZVAL_BOOL(result, 1); php_context *context = (php_context *) tnode->data; int ret = coro_resume(context, result, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&result); efree(context); }
/** * @zobject: swoole_http_client object */ static void http_client_coro_onError(swClient *cli) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif zval *zdata; zval *retval = NULL; SW_MAKE_STD_ZVAL(zdata); //return false ZVAL_BOOL(zdata, 0); zval *zobject = cli->object; php_context *sw_current_context = swoole_get_property(zobject, 1); zend_update_property_long(swoole_http_client_coro_class_entry_ptr, zobject, ZEND_STRL("errCode"), SwooleG.error TSRMLS_CC); if (cli->timeout_id > 0) { php_swoole_clear_timer_coro(cli->timeout_id TSRMLS_CC); cli->timeout_id=0; } if (!cli->released) { http_client_free(zobject TSRMLS_CC); } swoole_set_object(zobject, NULL); http_client_property *hcc = swoole_get_property(zobject, 0); if(hcc->defer && hcc->defer_status != HTTP_CLIENT_STATE_DEFER_WAIT){ hcc->defer_status = HTTP_CLIENT_STATE_DEFER_DONE; hcc->defer_result = 0; goto free_zdata; } hcc->defer_status = HTTP_CLIENT_STATE_DEFER_INIT; int ret = coro_resume(sw_current_context, zdata, &retval); if (ret > 0) { goto free_zdata; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } free_zdata: sw_zval_ptr_dtor(&zdata); }
static void http_client_coro_onTimeout(php_context *ctx) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif zval *zdata; zval *retval = NULL; SW_MAKE_STD_ZVAL(zdata); ZVAL_BOOL(zdata, 0); //return false #if PHP_MAJOR_VERSION < 7 zval *zobject = (zval *)ctx->coro_params; #else zval _zobject = ctx->coro_params; zval *zobject = & _zobject; #endif //define time out RETURN ERROR 110 zend_update_property_long(swoole_http_client_coro_class_entry_ptr, zobject, ZEND_STRL("errCode"), 110 TSRMLS_CC); http_client *http = swoole_get_object(zobject); http->cli->released = 1; http_client_free(zobject TSRMLS_CC); swoole_set_object(zobject, NULL); http_client_property *hcc = swoole_get_property(zobject, 0); if(hcc->defer && hcc->defer_status != HTTP_CLIENT_STATE_DEFER_WAIT){ hcc->defer_status = HTTP_CLIENT_STATE_DEFER_DONE; hcc->defer_result = 0; goto free_zdata; } hcc->defer_status = HTTP_CLIENT_STATE_DEFER_INIT; int ret = coro_resume(ctx, zdata, &retval); if (ret > 0) { goto free_zdata; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } free_zdata: sw_zval_ptr_dtor(&zdata); }
static int co_socket_onReadable(swReactor *reactor, swEvent *event) { util_socket *sock = (util_socket *) event->socket->object; php_context *context = &sock->context; zval *retval = NULL; zval result; reactor->del(reactor, sock->fd); if (sock->timer) { swTimer_del(&SwooleG.timer, sock->timer); sock->timer = NULL; } int n = read(sock->fd, sock->buf->val, sock->nbytes); if (n < 0) { ZVAL_FALSE(&result); zend_string_free(sock->buf); } else if (n == 0) { ZVAL_EMPTY_STRING(&result); zend_string_free(sock->buf); } else { sock->buf->val[n] = 0; sock->buf->len = n; ZVAL_STR(&result, sock->buf); } int ret = coro_resume(context, &result, &retval); zval_ptr_dtor(&result); if (ret == CORO_END && retval) { zval_ptr_dtor(retval); } efree(sock); return SW_OK; }
static int process_stream_onRead(swReactor *reactor, swEvent *event) { SWOOLE_GET_TSRMLS; process_stream *ps = event->socket->object; char *buf = ps->buffer->str + ps->buffer->length; size_t len = ps->buffer->size - ps->buffer->length; int ret = read(event->fd, buf, len); if (ret > 0) { ps->buffer->length += ret; if (ps->buffer->length == ps->buffer->size) { swString_extend(ps->buffer, ps->buffer->size * 2); } return SW_OK; } else if (ret < 0) { swSysError("read() failed."); return SW_OK; } zval *retval = NULL; zval **args[2]; zval *zdata; SW_MAKE_STD_ZVAL(zdata); SW_ZVAL_STRINGL(zdata, ps->buffer->str, ps->buffer->length, 1); SwooleG.main_reactor->del(SwooleG.main_reactor, ps->fd); swString_free(ps->buffer); args[0] = &zdata; int status; zval *zstatus; SW_MAKE_STD_ZVAL(zstatus); pid_t pid = swWaitpid(ps->pid, &status, WNOHANG); if (pid > 0) { array_init(zstatus); add_assoc_long(zstatus, "code", WEXITSTATUS(status)); add_assoc_long(zstatus, "signal", WTERMSIG(status)); } else { ZVAL_FALSE(zstatus); } args[1] = &zstatus; zval *zcallback = ps->callback; if (zcallback) { if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 2, args, 0, NULL TSRMLS_CC) == FAILURE) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete handler error"); } sw_zval_free(zcallback); } else { #ifdef SW_COROUTINE php_context *context = ps->context; sw_zval_add_ref(&zdata); add_assoc_zval(zstatus, "output", zdata); int ret = coro_resume(context, zstatus, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } efree(context); #else return SW_OK; #endif } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&zdata); sw_zval_ptr_dtor(&zstatus); close(ps->fd); efree(ps); return SW_OK; }
static ALWAYS_INLINE void resume_coro_if_needed(struct death_queue_t *dq, lwan_connection_t *conn, int epoll_fd) { assert(conn->coro); if (!(conn->flags & CONN_SHOULD_RESUME_CORO)) return; lwan_connection_coro_yield_t yield_result = coro_resume(conn->coro); /* CONN_CORO_ABORT is -1, but comparing with 0 is cheaper */ if (yield_result < CONN_CORO_MAY_RESUME) { destroy_coro(dq, conn); return; } bool write_events; if (conn->flags & CONN_MUST_READ) { write_events = true; } else { bool should_resume_coro = (yield_result == CONN_CORO_MAY_RESUME); if (should_resume_coro) conn->flags |= CONN_SHOULD_RESUME_CORO; else conn->flags &= ~CONN_SHOULD_RESUME_CORO; write_events = (conn->flags & CONN_WRITE_EVENTS); if (should_resume_coro == write_events) return; } struct epoll_event event = { .events = events_by_write_flag[write_events], .data.ptr = conn }; int fd = lwan_connection_get_fd(dq->lwan, conn); if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)) lwan_status_perror("epoll_ctl"); conn->flags ^= CONN_WRITE_EVENTS; } static void death_queue_kill_waiting(struct death_queue_t *dq) { dq->time++; while (!death_queue_empty(dq)) { lwan_connection_t *conn = death_queue_idx_to_node(dq, dq->head.next); if (conn->time_to_die > dq->time) return; destroy_coro(dq, conn); } /* Death queue exhausted: reset epoch */ dq->time = 0; }
static int process_request_coro(coro_t *coro) { strbuf_t *strbuf = coro_malloc_full(coro, sizeof(*strbuf), strbuf_free); lwan_connection_t *conn = coro_get_data(coro); lwan_t *lwan = conn->thread->lwan; int fd = lwan_connection_get_fd(conn); char request_buffer[DEFAULT_BUFFER_SIZE]; lwan_value_t buffer = { .value = request_buffer, .len = 0 }; char *next_request = NULL; strbuf_init(strbuf); while (true) { lwan_request_t request = { .conn = conn, .fd = fd, .response = { .buffer = strbuf }, }; assert(conn->flags & CONN_IS_ALIVE); next_request = lwan_process_request(lwan, &request, &buffer, next_request); if (!next_request) break; coro_yield(coro, CONN_CORO_MAY_RESUME); if (UNLIKELY(!strbuf_reset_length(strbuf))) return CONN_CORO_ABORT; } return CONN_CORO_FINISHED; } static ALWAYS_INLINE void resume_coro_if_needed(struct death_queue_t *dq, lwan_connection_t *conn, int epoll_fd) { assert(conn->coro); if (!(conn->flags & CONN_SHOULD_RESUME_CORO)) return; lwan_connection_coro_yield_t yield_result = coro_resume(conn->coro); /* CONN_CORO_ABORT is -1, but comparing with 0 is cheaper */ if (yield_result < CONN_CORO_MAY_RESUME) { destroy_coro(dq, conn); return; } bool write_events; if (conn->flags & CONN_MUST_READ) { write_events = true; } else { bool should_resume_coro = (yield_result == CONN_CORO_MAY_RESUME); if (should_resume_coro) conn->flags |= CONN_SHOULD_RESUME_CORO; else conn->flags &= ~CONN_SHOULD_RESUME_CORO; write_events = (conn->flags & CONN_WRITE_EVENTS); if (should_resume_coro == write_events) return; } struct epoll_event event = { .events = events_by_write_flag[write_events], .data.ptr = conn }; int fd = lwan_connection_get_fd(conn); if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)) lwan_status_perror("epoll_ctl"); conn->flags ^= CONN_WRITE_EVENTS; } static void death_queue_kill_waiting(struct death_queue_t *dq) { dq->time++; while (!death_queue_empty(dq)) { lwan_connection_t *conn = death_queue_idx_to_node(dq, dq->head.next); if (conn->time_to_die > dq->time) return; destroy_coro(dq, conn); } /* Death queue exhausted: reset epoch */ dq->time = 0; }
static void php_swoole_dns_callback_coro(char *domain, swDNSResolver_result *result, void *data) { SWOOLE_GET_TSRMLS; dns_request *req = data; zval *retval = NULL; zval *zaddress; char *address; SW_MAKE_STD_ZVAL(zaddress); if (result->num > 0) { if (SwooleG.dns_lookup_random) { address = result->hosts[rand() % result->num].address; } else { address = result->hosts[0].address; } SW_ZVAL_STRING(zaddress, address, 1); } else { SW_ZVAL_STRING(zaddress, "", 1); } //update cache dns_cache *cache = swHashMap_find(request_cache_map, Z_STRVAL_P(req->domain), Z_STRLEN_P(req->domain)); if (cache == NULL ) { cache = emalloc(sizeof(dns_cache)); swHashMap_add(request_cache_map, Z_STRVAL_P(req->domain), Z_STRLEN_P(req->domain), cache); cache->zaddress = swString_new(20); } swString_write_ptr(cache->zaddress, 0, Z_STRVAL_P(zaddress), Z_STRLEN_P(zaddress)); cache->update_time = (int64_t) swTimer_get_now_msec + (int64_t) (SwooleG.dns_cache_refresh_time * 1000); //timeout if (req->timer) { swTimer_del(&SwooleG.timer, req->timer); req->timer = NULL; } if (req->useless) { efree(req); return; } int ret = coro_resume(req->context, zaddress, &retval); if (ret > 0) { goto free_zdata; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } //说明已经yield走了 free_zdata: // free 上下文 sw_zval_ptr_dtor(&zaddress); efree(req->context); efree(req); }
static void http_client_coro_onReceive(swClient *cli, char *data, uint32_t length) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif zval *zobject = cli->object; zval *retval = NULL; http_client *http = swoole_get_object(zobject); if (!http->cli) { swoole_php_fatal_error(E_WARNING, "object is not instanceof swoole_http_client_coro."); return; } //timeout if (cli->timeout_id > 0) { php_swoole_clear_timer_coro(cli->timeout_id TSRMLS_CC); cli->timeout_id=0; } long parsed_n = php_http_parser_execute(&http->parser, &http_parser_settings, data, length); http_client_property *hcc = swoole_get_property(zobject, 0); zval *zdata; SW_MAKE_STD_ZVAL(zdata); if (parsed_n < 0) { //错误情况 标志位 done defer 保存 sw_zend_call_method_with_0_params(&zobject, swoole_http_client_coro_class_entry_ptr, NULL, "close", &retval); if (retval) { sw_zval_ptr_dtor(&retval); } ZVAL_BOOL(zdata, 0); //return false if (hcc->defer && hcc->defer_status != HTTP_CLIENT_STATE_DEFER_WAIT) { //not recv yet sava data hcc->defer_status = HTTP_CLIENT_STATE_DEFER_DONE; hcc->defer_result = 0; goto free_zdata; //wait for recv } goto begin_resume; } //not complete if (!http->completed) { return; } // if(!hcc->defer_chunk_status){ //not recv all wait for next // return; // } ZVAL_BOOL(zdata, 1); //return false if (hcc->defer && hcc->defer_status != HTTP_CLIENT_STATE_DEFER_WAIT) { //not recv yet sava data hcc->defer_status = HTTP_CLIENT_STATE_DEFER_DONE; hcc->defer_result = 1; goto free_zdata; } begin_resume: { //if should resume /*if next cr*/ php_context *sw_current_context = swoole_get_property(zobject, 1); hcc->defer_status = HTTP_CLIENT_STATE_DEFER_INIT; // hcc->defer_chunk_status = 0; http->completed = 0; int ret = coro_resume(sw_current_context, zdata, &retval); if (ret > 0) { goto free_zdata; } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } } free_zdata: sw_zval_ptr_dtor(&zdata); }