/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags) { swEventData buf; if (SwooleG.task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } int ret; //for swoole_server_task if (swTask_type(current_task) & SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; swTask_type(&buf) = flags; //write to file if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; } uint16_t target_worker_id = current_task->info.from_id; swWorker *worker = swServer_get_worker(serv, target_worker_id); ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER); } else { uint64_t flag = 1; uint16_t worker_id = current_task->info.from_id; /** * Use worker shm store the result */ swEventData *result = &(SwooleG.task_result[worker_id]); swPipe *task_notify_pipe = &(SwooleG.task_notify[worker_id]); result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; swTask_type(result) = flags; if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; } while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); #ifdef HAVE_KQUEUE if (errno == EAGAIN || errno == ENOBUFS) #else if (errno == EAGAIN) #endif { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }
/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags) { swEventData buf; if (!current_task) { swWarn("cannot use finish in worker"); return SW_ERR; } if (serv->task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } if (current_task->info.type == SW_EVENT_PIPE_MESSAGE) { swWarn("task/finish is not supported in onPipeMessage callback."); return SW_ERR; } uint16_t source_worker_id = current_task->info.from_id; swWorker *worker = swServer_get_worker(serv, source_worker_id); if (worker == NULL) { swWarn("invalid worker_id[%d].", source_worker_id); return SW_ERR; } int ret; //for swoole_server_task if (swTask_type(current_task) & SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; //callback function if (swTask_type(current_task) & SW_TASK_CALLBACK) { flags |= SW_TASK_CALLBACK; } else if (swTask_type(current_task) & SW_TASK_COROUTINE) { flags |= SW_TASK_COROUTINE; } swTask_type(&buf) = flags; //write to file if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; } if (worker->pool->use_socket && worker->pool->stream->last_connection > 0) { int32_t _len = htonl(data_len); ret = swSocket_write_blocking(worker->pool->stream->last_connection, (void *) &_len, sizeof(_len)); if (ret > 0) { ret = swSocket_write_blocking(worker->pool->stream->last_connection, data, data_len); } } else { ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER); } } else { uint64_t flag = 1; /** * Use worker shm store the result */ swEventData *result = &(serv->task_result[source_worker_id]); swPipe *task_notify_pipe = &(serv->task_notify[source_worker_id]); //lock worker worker->lock.lock(&worker->lock); if (swTask_type(current_task) & SW_TASK_WAITALL) { sw_atomic_t *finish_count = (sw_atomic_t*) result->data; char *_tmpfile = result->data + 4; int fd = open(_tmpfile, O_APPEND | O_WRONLY); if (fd >= 0) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; swTask_type(&buf) = flags; //result pack if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0) { swWarn("large task pack failed()"); buf.info.len = 0; } } else { buf.info.len = data_len; memcpy(buf.data, data, data_len); } //write to tmpfile if (swoole_sync_writefile(fd, &buf, sizeof(buf.info) + buf.info.len) < 0) { swSysError("write(%s, %ld) failed.", _tmpfile, sizeof(buf.info) + buf.info.len); } sw_atomic_fetch_add(finish_count, 1); close(fd); } } else { result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; swTask_type(result) = flags; if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { //unlock worker worker->lock.unlock(&worker->lock); swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; } } //unlock worker worker->lock.unlock(&worker->lock); while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); #ifdef HAVE_KQUEUE if (ret < 0 && (errno == EAGAIN || errno == ENOBUFS)) #else if (ret < 0 && errno == EAGAIN) #endif { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }
/** * Send the task result to worker */ int swTaskWorker_finish(swServer *serv, char *data, int data_len) { swEventData buf; if (SwooleG.task_worker_num < 1) { swWarn("cannot use task/finish, because no set serv->task_worker_num."); return SW_ERR; } int ret; //for swoole_server_task if (current_task->info.type == SW_TASK_NONBLOCK) { buf.info.type = SW_EVENT_FINISH; buf.info.fd = current_task->info.fd; //write to file if (data_len >= sizeof(buf.data)) { if (swTaskWorker_large_pack(&buf, data, data_len) < 0 ) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(buf.data, data, data_len); buf.info.len = data_len; buf.info.from_fd = 0; } //tasking /** * TODO: 这里需要重构,改成统一的模式 */ if (serv->factory_mode == SW_MODE_PROCESS) { ret = swServer_send2worker_blocking(serv, &buf, sizeof(buf.info) + buf.info.len, current_task->info.from_id); } else { ret = swWrite(SwooleG.event_workers->workers[current_task->info.from_id].pipe_worker, &buf, sizeof(buf.info) + data_len); } } else { uint64_t flag = 1; uint16_t worker_id = current_task->info.from_id; /** * Use worker shm store the result */ swEventData *result = &(SwooleG.task_result[worker_id]); swPipe *task_notify_pipe = &(SwooleG.task_notify[worker_id]); result->info.type = SW_EVENT_FINISH; result->info.fd = current_task->info.fd; if (data_len >= sizeof(buf.data)) { if (swTaskWorker_large_pack(result, data, data_len) < 0) { swWarn("large task pack failed()"); return SW_ERR; } } else { memcpy(result->data, data, data_len); result->info.len = data_len; result->info.from_fd = 0; } while (1) { ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag)); if (ret < 0 && errno == EAGAIN) { if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0) { continue; } } break; } } if (ret < 0) { swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno); } return ret; }
/** * worker: send to client */ static int swFactoryProcess_finish(swFactory *factory, swSendData *resp) { int ret, sendn; swServer *serv = factory->ptr; int session_id = resp->info.fd; swConnection *conn; if (resp->info.type != SW_EVENT_CLOSE) { conn = swServer_connection_verify(serv, session_id); } else { conn = swServer_connection_verify_no_ssl(serv, session_id); } if (!conn) { swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[fd=%d] does not exists.", session_id); return SW_ERR; } else if ((conn->closed || conn->removed) && resp->info.type != SW_EVENT_CLOSE) { int _len = resp->length > 0 ? resp->length : resp->info.len; swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSED, "send %d byte failed, because connection[fd=%d] is closed.", _len, session_id); return SW_ERR; } else if (conn->overflow) { swoole_error_log(SW_LOG_WARNING, SW_ERROR_OUTPUT_BUFFER_OVERFLOW, "send failed, connection[fd=%d] output buffer has been overflowed.", session_id); return SW_ERR; } swEventData ev_data; ev_data.info.fd = session_id; ev_data.info.type = resp->info.type; swWorker *worker = swServer_get_worker(serv, SwooleWG.id); /** * Big response, use shared memory */ if (resp->length > 0) { if (worker == NULL || worker->send_shm == NULL) { goto pack_data; } //worker process if (SwooleG.main_reactor) { int _pipe_fd = swWorker_get_send_pipe(serv, session_id, conn->from_id); swConnection *_pipe_socket = swReactor_get(SwooleG.main_reactor, _pipe_fd); //cannot use send_shm if (!swBuffer_empty(_pipe_socket->out_buffer)) { pack_data: if (swTaskWorker_large_pack(&ev_data, resp->data, resp->length) < 0) { return SW_ERR; } ev_data.info.from_fd = SW_RESPONSE_TMPFILE; goto send_to_reactor_thread; } } swPackage_response response; response.length = resp->length; response.worker_id = SwooleWG.id; ev_data.info.from_fd = SW_RESPONSE_SHM; ev_data.info.len = sizeof(response); memcpy(ev_data.data, &response, sizeof(response)); swTrace("[Worker] big response, length=%d|worker_id=%d", response.length, response.worker_id); worker->lock.lock(&worker->lock); memcpy(worker->send_shm, resp->data, resp->length); } else { //copy data memcpy(ev_data.data, resp->data, resp->info.len); ev_data.info.len = resp->info.len; ev_data.info.from_fd = SW_RESPONSE_SMALL; } send_to_reactor_thread: ev_data.info.from_id = conn->from_id; sendn = ev_data.info.len + sizeof(resp->info); swTrace("[Worker] send: sendn=%d|type=%d|content=%s", sendn, resp->info.type, resp->data); ret = swWorker_send2reactor(&ev_data, sendn, session_id); if (ret < 0) { swWarn("sendto to reactor failed. Error: %s [%d]", strerror(errno), errno); } return ret; }