static void np_conn_flush (Npconn *conn) { Nptpool *tp; Npreq *creq, *nextreq; xpthread_mutex_lock(&conn->srv->lock); for (tp = conn->srv->tpool; tp != NULL; tp = tp->next) { for (creq = tp->reqs_first; creq != NULL; creq = nextreq) { nextreq = creq->next; if (creq->conn != conn) continue; np_srv_remove_req(tp, creq); np_req_unref(creq); } for (creq = tp->workreqs; creq != NULL; creq = creq->next) { if (creq->conn != conn) continue; creq->state = REQ_NOREPLY; if (conn->srv->flags & SRV_FLAGS_FLUSHSIG) pthread_kill (creq->wthread->thread, SIGUSR2); } } xpthread_mutex_unlock(&conn->srv->lock); }
static void _free_working_reqs (Npreq **reqs, int len) { int i; for(i = 0; i < len; i++) np_req_unref(reqs[i]); free(reqs); }
static void np_respond(Nptpool *tp, Npreq *req, Npfcall *rc) { Npreq *freq; xpthread_mutex_lock(&req->lock); if (req->responded) { free(rc); xpthread_mutex_unlock(&req->lock); np_req_unref(req); return; } req->responded = 1; xpthread_mutex_unlock(&req->lock); xpthread_mutex_lock(&tp->lock); np_srv_remove_workreq(tp, req); for(freq = req->flushreq; freq != NULL; freq = freq->flushreq) np_srv_remove_workreq(tp, freq); xpthread_mutex_unlock(&tp->lock); xpthread_mutex_lock(&req->lock); req->rcall = rc; if (req->rcall) { np_set_tag(req->rcall, req->tag); if (req->fid != NULL) { np_fid_decref(req->fid); req->fid = NULL; } np_conn_respond(req); } for(freq = req->flushreq; freq != NULL; freq = freq->flushreq) { xpthread_mutex_lock(&freq->lock); freq->rcall = np_create_rflush(); np_set_tag(freq->rcall, freq->tag); np_conn_respond(freq); xpthread_mutex_unlock(&freq->lock); np_req_unref(freq); } xpthread_mutex_unlock(&req->lock); np_req_unref(req); }
static void _flush_waiting_reqs (Npreq *reqs) { Npreq *req = reqs; Npreq *req1; while (req != NULL) { req1 = req->next; np_conn_respond(req); np_req_unref(req); req = req1; } }
static void np_respond(Nptpool *tp, Npreq *req, Npfcall *rc) { xpthread_mutex_lock(&tp->srv->lock); np_srv_remove_workreq(tp, req); xpthread_mutex_unlock(&tp->srv->lock); xpthread_mutex_lock(&req->lock); req->rcall = rc; if (req->rcall) { np_set_tag(req->rcall, req->tag); if (req->fid != NULL) { np_fid_decref(req->fid); req->fid = NULL; } np_conn_respond(req); } xpthread_mutex_unlock(&req->lock); np_req_unref(req); }
/* Per-connection read thread. */ static void * np_conn_read_proc(void *a) { Npconn *conn = (Npconn *)a; Npsrv *srv = conn->srv; Npreq *req; Npfcall *fc; pthread_detach(pthread_self()); for (;;) { if (np_trans_recv(conn->trans, &fc, conn->msize) < 0) { np_logerr (srv, "recv error - " "dropping connection to '%s'", conn->client_id); break; } if (!fc) /* EOF */ break; _debug_trace (srv, fc); /* Encapsulate fc in a request and hand to srv worker threads. * In np_req_alloc, req->fid is looked up/initialized. */ req = np_req_alloc(conn, fc); if (!req) { np_logmsg (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); free (fc); break; } /* Enqueue request for processing by next available worker * thread, except P9_TFLUSH which is handled immediately. */ if (fc->type == P9_TFLUSH) { if (np_flush (req, fc)) { np_req_respond_flush (req); np_req_unref(req); } xpthread_mutex_lock (&srv->lock); srv->tpool->stats.nreqs[P9_TFLUSH]++; xpthread_mutex_unlock (&srv->lock); } else { xpthread_mutex_lock(&srv->lock); np_srv_add_req(srv, req); xpthread_mutex_unlock(&srv->lock); } } /* Just got EOF on read, or some other fatal error for the * connection like out of memory. */ np_conn_flush (conn); xpthread_mutex_lock(&conn->lock); while (conn->refcount > 0) xpthread_cond_wait(&conn->refcond, &conn->lock); xpthread_mutex_unlock(&conn->lock); np_conn_destroy(conn); return NULL; }
void np_conn_reset(Npconn *conn, u32 msize, int dotu) { int i, n; Npsrv *srv; Npreq *req, *req1, *preqs, **reqs; Npfcall *fc, *fc1; pthread_mutex_lock(&conn->lock); conn->resetting = 1; pthread_mutex_unlock(&conn->lock); pthread_mutex_lock(&conn->srv->lock); srv = conn->srv; // first flush all outstanding requests preqs = NULL; req = srv->reqs_first; while (req != NULL) { req1 = req->next; if (req->conn == conn) { np_srv_remove_req(srv, req); req->next = preqs; preqs = req; } req = req1; } // then flush all working requests n = 0; req = conn->srv->workreqs; while (req != NULL) { if (req->conn == conn && (msize==0 || req->tcall->type != Tversion)) n++; req = req->next; } reqs = malloc(n * sizeof(Npreq *)); n = 0; req = conn->srv->workreqs; while (req != NULL) { if (req->conn == conn && (msize==0 || req->tcall->type != Tversion)) reqs[n++] = np_req_ref(req); req = req->next; } pthread_mutex_unlock(&conn->srv->lock); req = preqs; while (req != NULL) { req1 = req->next; np_conn_respond(req); np_req_unref(req); req = req1; } for(i = 0; i < n; i++) { req = reqs[i]; if (req->conn->srv->flush) (*req->conn->srv->flush)(req); } /* wait until all working requests finish */ /* pthread_mutex_lock(&conn->lock); while (1) { for(i = 0; i < n; i++) if (!reqs[i]->responded) break; if (i >= n) break; pthread_cond_wait(&conn->resetcond, &conn->lock); } */ pthread_mutex_lock(&srv->lock); while (1) { for(req = srv->workreqs; req != NULL; req = req->next) if (req->conn == conn && (msize==0 || req->tcall->type != Tversion)) break; if (req == NULL) break; while(conn->resetting) pthread_cond_wait(&conn->resetcond, &srv->lock); } pthread_mutex_unlock(&srv->lock); /* free old pool of fcalls */ fc = conn->freerclist; conn->freerclist = NULL; while (fc != NULL) { fc1 = fc->next; free(fc); fc = fc1; } if (conn->fidpool) { np_fidpool_destroy(conn->fidpool); conn->fidpool = NULL; } if (msize) { conn->dotu = dotu; conn->resetting = 0; conn->fidpool = np_fidpool_create(); pthread_cond_broadcast(&conn->resetdonecond); } conn->resetting = 0; pthread_mutex_unlock(&conn->lock); /* free the working requests */ for(i = 0; i < n; i++) np_req_unref(reqs[i]); free(reqs); }
static void * np_conn_read_proc(void *a) { int i, n, size, msize; Npsrv *srv; Npconn *conn; Nptrans *trans; Npreq *req; Npfcall *fc, *fc1; pthread_detach(pthread_self()); conn = a; np_conn_incref(conn); srv = conn->srv; msize = conn->msize; fc = np_conn_new_incall(conn); n = 0; while (conn->trans && (i = np_trans_read(conn->trans, fc->pkt + n, msize - n)) > 0) { pthread_mutex_lock(&conn->lock); if (conn->resetting) { while(conn->resetting) pthread_cond_wait(&conn->resetdonecond, &conn->lock); n = 0; /* discard all input */ i = 0; } pthread_mutex_unlock(&conn->lock); n += i; again: if (n < 4) continue; size = fc->pkt[0] | (fc->pkt[1]<<8) | (fc->pkt[2]<<16) | (fc->pkt[3]<<24); if (n < size) continue; if (!np_deserialize(fc, fc->pkt, conn->dotu)) break; if (conn->srv->debuglevel) { fprintf(stderr, "<<< (%p) ", conn); np_printfcall(stderr, fc, conn->dotu); fprintf(stderr, "\n"); } fc1 = np_conn_new_incall(conn); if (n > size) memmove(fc1->pkt, fc->pkt + size, n - size); n -= size; req = np_req_alloc(conn, fc); pthread_mutex_lock(&srv->lock); if (!conn->resetting) np_srv_add_req(srv, req); else np_req_unref(req); pthread_mutex_unlock(&srv->lock); fc = fc1; if (n > 0) goto again; } pthread_mutex_lock(&conn->lock); trans = conn->trans; conn->trans = NULL; np_conn_free_incall(conn, fc); pthread_mutex_unlock(&conn->lock); np_srv_remove_conn(conn->srv, conn); np_conn_reset(conn, 0, 0); if (trans) np_trans_destroy(trans); np_conn_decref(conn); return NULL; }
Npfcall* np_flush(Npreq *req, Npfcall *tc) { u16 oldtag = tc->u.tflush.oldtag; Npreq *creq = NULL; Npconn *conn = req->conn; Npfcall *ret = NULL; Nptpool *tp; xpthread_mutex_lock(&conn->srv->lock); // check pending requests for (tp = conn->srv->tpool; tp != NULL; tp = tp->next) { xpthread_mutex_lock(&tp->lock); for(creq = tp->reqs_first; creq != NULL; creq = creq->next) { if (creq->conn==conn && creq->tag==oldtag) { np_srv_remove_req(tp, creq); xpthread_mutex_lock(&creq->lock); np_conn_respond(creq); /* doesn't send anything */ xpthread_mutex_unlock(&creq->lock); np_req_unref(creq); ret = np_create_rflush(); creq = NULL; xpthread_mutex_unlock(&tp->lock); goto done; } } xpthread_mutex_unlock(&tp->lock); } // check working requests for (tp = conn->srv->tpool; tp != NULL; tp = tp->next) { xpthread_mutex_lock(&tp->lock); creq = tp->workreqs; while (creq != NULL) { if (creq->conn==conn && creq->tag==oldtag) { np_req_ref(creq); xpthread_mutex_lock(&creq->lock); req->flushreq = creq->flushreq; creq->flushreq = req; xpthread_mutex_unlock(&creq->lock); xpthread_mutex_unlock(&tp->lock); goto done; } creq = creq->next; } xpthread_mutex_unlock(&tp->lock); } // if not found, return P9_RFLUSH if (!creq) ret = np_create_rflush(); done: xpthread_mutex_unlock(&conn->srv->lock); // if working request found, try to flush it if (creq && req->conn->srv->flush) { (*req->conn->srv->flush)(creq); np_req_unref(creq); } return ret; }