void notify_io_complete(const void *cookie, ENGINE_ERROR_CODE status) { struct conn *conn = (struct conn *)cookie; mc_logger->log(EXTENSION_LOG_DEBUG, NULL, "Got notify from %d, status %x\n", conn->sfd, status); /* ** There may be a race condition between the engine calling this ** function and the core closing the connection. ** Let's lock the connection structure (this might not be the ** correct one) and re-evaluate. */ LIBEVENT_THREAD *thr = conn->thread; if (thr == NULL || conn->state == conn_closing) { return; } int notify = 0; LOCK_THREAD(thr); if (thr != conn->thread || conn->state == conn_closing || !conn->io_blocked){ conn->premature_notify_io_complete = true; UNLOCK_THREAD(thr); mc_logger->log(EXTENSION_LOG_DEBUG, NULL, "Premature notify_io_complete\n"); return; } conn->io_blocked = false; conn->aiostat = status; if (number_of_pending(conn, thr->pending_io) == 0) { if (thr->pending_io == NULL) { notify = 1; } conn->next = thr->pending_io; thr->pending_io = conn; } assert(number_of_pending(conn, thr->pending_io) == 1); UNLOCK_THREAD(thr); /* kick the thread in the butt */ if (notify && write(thr->notify_send_fd, "", 1) != 1) { mc_logger->log(EXTENSION_LOG_WARNING, NULL, "Writing to thread notify pipe: %s", strerror(errno)); } }
int add_conn_to_pending_io_list(conn *c) { int notify = 0; if (number_of_pending(c, c->thread->pending_io) == 0) { if (c->thread->pending_io == NULL) { notify = 1; } enlist_conn(c, &c->thread->pending_io); } return notify; }
void notify_io_complete(const void *cookie, ENGINE_ERROR_CODE status) { if (cookie == NULL) { settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL, "notify_io_complete called without a valid cookie (status %x)\n", status); return ; } struct conn *conn = (struct conn *)cookie; settings.extensions.logger->log(EXTENSION_LOG_DEBUG, NULL, "Got notify from %d, status %x\n", conn->sfd, status); /* ** TROND: ** I changed the logic for the tap connections so that the core ** issues the ON_DISCONNECT call to the engine instead of trying ** to close the connection. Then it let's the engine have a grace ** period to call notify_io_complete if not it will go ahead and ** kill it. ** */ if (status == ENGINE_DISCONNECT && conn->thread == tap_thread) { LOCK_THREAD(conn->thread); /** Remove the connection from both of the lists */ conn->thread->pending_io = list_remove(conn->thread->pending_io, conn); conn->thread->pending_close = list_remove(conn->thread->pending_close, conn); if (conn->state == conn_pending_close || conn->state == conn_immediate_close) { if (conn->refcount == 1) { settings.extensions.logger->log(EXTENSION_LOG_DEBUG, NULL, "Complete shutdown of %p", conn); conn_set_state(conn, conn_immediate_close); enlist_conn(conn, &conn->thread->pending_close); } else { settings.extensions.logger->log(EXTENSION_LOG_DEBUG, NULL, "Keep on waiting for shutdown of %p", conn); } } else { settings.extensions.logger->log(EXTENSION_LOG_DEBUG, NULL, "Engine requested shutdown of %p", conn); conn_set_state(conn, conn_closing); enlist_conn(conn, &conn->thread->pending_io); } if (!is_thread_me(conn->thread)) { /* kick the thread in the butt */ notify_thread(conn->thread); } UNLOCK_THREAD(conn->thread); return; } /* ** There may be a race condition between the engine calling this ** function and the core closing the connection. ** Let's lock the connection structure (this might not be the ** correct one) and re-evaluate. */ LIBEVENT_THREAD *thr = conn->thread; if (thr == NULL || (conn->state == conn_closing || conn->state == conn_pending_close || conn->state == conn_immediate_close)) { return; } int notify = 0; LOCK_THREAD(thr); if (thr != conn->thread || !conn->ewouldblock) { // Ignore UNLOCK_THREAD(thr); return; } conn->aiostat = status; /* Move the connection to the closing state if the engine * wants it to be disconnected */ if (status == ENGINE_DISCONNECT) { conn->state = conn_closing; notify = 1; thr->pending_io = list_remove(thr->pending_io, conn); if (number_of_pending(conn, thr->pending_close) == 0) { enlist_conn(conn, &thr->pending_close); } } else { if (number_of_pending(conn, thr->pending_io) + number_of_pending(conn, thr->pending_close) == 0) { if (thr->pending_io == NULL) { notify = 1; } enlist_conn(conn, &thr->pending_io); } } UNLOCK_THREAD(thr); /* kick the thread in the butt */ if (notify) { notify_thread(thr); } }