static void segdev_callback(struct segdev *dev, xport portno) { struct xseg *xseg; struct segpriv *priv = dev->priv; struct xseg_private *xpriv; struct xseg_port *port; struct segdev_signal_desc *ssd; xseg = xsegments[portno]; if (!xseg) return; if (priv->segno >= nr_xsegments) return; xpriv = xseg->priv; port = xseg_get_port(xseg, portno); if (!port) return; ssd = xseg_get_signal_desc(xseg, port); if (!ssd || !ssd->waitcue){ return; } if (xpriv->wakeup) { xpriv->wakeup(portno); } return; }
static struct posixfd_signal_desc * __get_signal_desc(struct xseg *xseg, xport portno) { struct xseg_port *port = xseg_get_port(xseg, portno); if (!port) return NULL; struct posixfd_signal_desc *psd = xseg_get_signal_desc(xseg, port); if (!psd) return NULL; return psd; }
static int posix_cancel_wait(struct xseg *xseg, uint32_t portno) { struct xseg_port *port = xseg_get_port(xseg, portno); if (!port) return -1; struct posix_signal_desc *psd = xseg_get_signal_desc(xseg, port); if (!psd) return -1; psd->waitcue = 0; return 0; }
static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno) { struct segdev_signal_desc *ssd; struct xseg_port *port = xseg_get_port(xseg, portno); if (!port) return -1; ssd = xseg_get_signal_desc(xseg, port); if (!ssd) return -1; /* true/false value */ ssd->waitcue = 0; return -0; }
static int posix_signal(struct xseg *xseg, uint32_t portno) { struct xseg_port *port = xseg_get_port(xseg, portno); if (!port) return -1; struct posix_signal_desc *psd = xseg_get_signal_desc(xseg, port); if (!psd) return -1; pid_t cue = (pid_t)psd->waitcue; if (!cue) //HACKY! return -2; /* FIXME: Make calls to xseg_signal() check for errors */ return syscall(SYS_tkill, cue, SIGIO); }
static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port, struct xseg_request *expected_req) { struct xseg_request *req; xseg_prepare_wait(xseg, srcport); void *psd = xseg_get_signal_desc(xseg, port); while (1) { req = xseg_receive(xseg, srcport, X_NONBLOCK); if (req) { if (req != expected_req) { archipelagolog("Unknown received request\n"); xseg_put_request(xseg, req, srcport); } else if (!(req->state & XS_SERVED)) { return -1; } else { break; } } xseg_wait_signal(xseg, psd, 100000UL); } xseg_cancel_wait(xseg, srcport); return 0; }
static void xseg_request_handler(void *state) { BDRVArchipelagoState *s = (BDRVArchipelagoState *) state; void *psd = xseg_get_signal_desc(s->xseg, s->port); qemu_mutex_lock(&s->request_mutex); while (!s->stopping) { struct xseg_request *req; void *data; xseg_prepare_wait(s->xseg, s->srcport); req = xseg_receive(s->xseg, s->srcport, X_NONBLOCK); if (req) { AIORequestData *reqdata; ArchipelagoSegmentedRequest *segreq; xseg_get_req_data(s->xseg, req, (void **)&reqdata); switch (reqdata->op) { case ARCHIP_OP_READ: data = xseg_get_data(s->xseg, req); segreq = reqdata->segreq; segreq->count += req->serviced; qemu_iovec_from_buf(reqdata->aio_cb->qiov, reqdata->bufidx, data, req->serviced); xseg_put_request(s->xseg, req, s->srcport); if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) { if (!segreq->failed) { reqdata->aio_cb->ret = segreq->count; archipelago_finish_aiocb(reqdata); g_free(segreq); } else { g_free(segreq); g_free(reqdata); } } else { g_free(reqdata); } break; case ARCHIP_OP_WRITE: case ARCHIP_OP_FLUSH: segreq = reqdata->segreq; segreq->count += req->serviced; xseg_put_request(s->xseg, req, s->srcport); if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) { if (!segreq->failed) { reqdata->aio_cb->ret = segreq->count; archipelago_finish_aiocb(reqdata); g_free(segreq); } else { g_free(segreq); g_free(reqdata); } } else { g_free(reqdata); } break; case ARCHIP_OP_VOLINFO: s->is_signaled = true; qemu_cond_signal(&s->archip_cond); break; } } else { xseg_wait_signal(s->xseg, psd, 100000UL); } xseg_cancel_wait(s->xseg, s->srcport); } s->th_is_signaled = true; qemu_cond_signal(&s->request_cond); qemu_mutex_unlock(&s->request_mutex); qemu_thread_exit(NULL); }