/** * \brief Register an event handler to be notified when messages can be sent * * In the future, call the closure on the given waitset when it is likely that * a message can be sent on the channel. A channel may only be registered * with a single send event handler on a single waitset at any one time. * * \param lc LMP channel * \param ws Waitset * \param closure Event handler */ errval_t lmp_chan_register_send(struct lmp_chan *lc, struct waitset *ws, struct event_closure closure) { assert(lc != NULL); assert(ws != NULL); errval_t err = waitset_chan_register(ws, &lc->send_waitset, closure); if (err_is_fail(err)) { return err; } // enqueue in list of channels with a registered event to retry sending assert(lc->next == NULL && lc->prev == NULL); dispatcher_handle_t handle = disp_disable(); struct dispatcher_generic *dp = get_dispatcher_generic(handle); if (dp->lmp_send_events_list == NULL) { dp->lmp_send_events_list = lc; lc->next = lc->prev = lc; } else { lc->prev = dp->lmp_send_events_list->prev; lc->next = dp->lmp_send_events_list; lc->prev->next = lc; lc->next->prev = lc; } disp_enable(handle); return err; }
static errval_t mp_create(struct descq_binding* b, uint32_t slots, struct capref rx, struct capref tx, bool notifications, uint8_t role, errval_t *err, uint64_t *queue_id) { struct descq* q = (struct descq*) b->st; DESCQ_DEBUG("start %p\n",q); // switch RX/TX for correct setup *err = vspace_map_one_frame_attr((void**) &(q->rx_descs), slots*DESCQ_ALIGNMENT, tx, VREGION_FLAGS_READ_WRITE, NULL, NULL); if (err_is_fail(*err)) { goto end2; } *err = vspace_map_one_frame_attr((void**) &(q->tx_descs), slots*DESCQ_ALIGNMENT, rx, VREGION_FLAGS_READ_WRITE, NULL, NULL); if (err_is_fail(*err)) { goto end1; } q->tx_seq_ack = (void*)q->tx_descs; q->rx_seq_ack = (void*)q->rx_descs; q->tx_descs++; q->rx_descs++; q->slots = slots-1; q->rx_seq = 1; q->tx_seq = 1; devq_init(&q->q, true); q->q.f.enq = descq_enqueue; q->q.f.deq = descq_dequeue; q->q.f.notify = descq_notify; q->q.f.reg = descq_register; q->q.f.dereg = descq_deregister; q->q.f.ctrl = descq_control; q->q.f.destroy = descq_destroy; notificator_init(&q->notificator, q, descq_can_read, descq_can_write); *err = waitset_chan_register(get_default_waitset(), &q->notificator.ready_to_read, MKCLOSURE(mp_notify, q)); assert(err_is_ok(*err)); *err = q->f.create(q, notifications, role, queue_id); if (err_is_ok(*err)) { goto end2; } end1: *err = vspace_unmap(q->rx_descs); assert(err_is_ok(*err)); end2: DESCQ_DEBUG("end \n"); return SYS_ERR_OK; }
errval_t flounder_support_register(struct waitset *ws, struct waitset_chanstate *wc, struct event_closure ec, bool trigger_now) { if (trigger_now) { return waitset_chan_trigger_closure(ws, wc, ec); } else { return waitset_chan_register(ws, wc, ec); } }
/** * @brief initialized a descriptor queue */ errval_t descq_create(struct descq** q, size_t slots, char* name, bool exp, bool notifications, uint8_t role, uint64_t *queue_id, struct descq_func_pointer* f) { DESCQ_DEBUG("create start\n"); errval_t err; struct descq* tmp; struct capref rx; struct capref tx; // Init basic struct fields tmp = malloc(sizeof(struct descq)); assert(tmp != NULL); tmp->name = strdup(name); assert(tmp->name != NULL); if (exp) { // exporting struct descq_endpoint_state* state = malloc(sizeof(struct descq_endpoint_state)); state->name = strdup(name); assert(state->name); state->f.notify = f->notify; state->f.dereg = f->dereg; state->f.reg = f->reg; state->f.create = f->create; state->f.destroy = f->destroy; state->f.control = f->control; err = descq_export(state, export_cb, connect_cb, get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); if (err_is_fail(err)) { goto cleanup1; } while(!state->exp_done) { event_dispatch(get_default_waitset()); } } else { tmp->f.notify = f->notify; tmp->f.dereg = f->dereg; tmp->f.reg = f->reg; tmp->f.create = f->create; tmp->f.destroy = f->destroy; tmp->f.control = f->control; size_t bytes; err = frame_alloc(&rx, DESCQ_ALIGNMENT*slots, &bytes); if (err_is_fail(err)) { goto cleanup1; } assert(bytes >= DESCQ_ALIGNMENT*slots); err = frame_alloc(&tx, DESCQ_ALIGNMENT*slots, &bytes); if (err_is_fail(err)) { goto cleanup2; } assert(bytes >= DESCQ_ALIGNMENT*slots); err = vspace_map_one_frame_attr((void**) &(tmp->rx_descs), slots*DESCQ_ALIGNMENT, rx, VREGION_FLAGS_READ_WRITE, NULL, NULL); if (err_is_fail(err)) { goto cleanup3; } err = vspace_map_one_frame_attr((void**) &(tmp->tx_descs), slots*DESCQ_ALIGNMENT, tx, VREGION_FLAGS_READ_WRITE, NULL, NULL); if (err_is_fail(err)) { goto cleanup4; } memset(tmp->tx_descs, 0, slots*DESCQ_ALIGNMENT); memset(tmp->rx_descs, 0, slots*DESCQ_ALIGNMENT); tmp->bound_done = false; iref_t iref; err = nameservice_blocking_lookup(name, &iref); if (err_is_fail(err)) { goto cleanup5; } err = descq_bind(iref, bind_cb, tmp, get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); if (err_is_fail(err)) { goto cleanup5; } while(!tmp->bound_done) { event_dispatch(get_default_waitset()); } tmp->local_bind = tmp->binding->local_binding != NULL; errval_t err2; err = tmp->binding->rpc_tx_vtbl.create_queue(tmp->binding, slots, rx, tx, notifications, role, &err2, queue_id); if (err_is_fail(err) || err_is_fail(err2)) { err = err_is_fail(err) ? err: err2; goto cleanup5; } tmp->tx_seq_ack = (void*)tmp->tx_descs; tmp->rx_seq_ack = (void*)tmp->rx_descs; tmp->tx_seq_ack->value = 0; tmp->rx_seq_ack->value = 0; tmp->tx_descs++; tmp->rx_descs++; tmp->slots = slots-1; tmp->rx_seq = 1; tmp->tx_seq = 1; devq_init(&tmp->q, false); tmp->q.f.enq = descq_enqueue; tmp->q.f.deq = descq_dequeue; tmp->q.f.notify = descq_notify; tmp->q.f.reg = descq_register; tmp->q.f.dereg = descq_deregister; tmp->q.f.ctrl = descq_control; tmp->notifications = notifications; notificator_init(&tmp->notificator, tmp, descq_can_read, descq_can_write); err = waitset_chan_register(get_default_waitset(), &tmp->notificator.ready_to_read, MKCLOSURE(mp_notify, tmp)); assert(err_is_ok(err)); } *q = tmp; DESCQ_DEBUG("create end %p \n", *q); return SYS_ERR_OK; cleanup5: vspace_unmap(tmp->rx_descs); cleanup4: vspace_unmap(tmp->rx_descs); cleanup3: cap_destroy(tx); cleanup2: cap_destroy(rx); cleanup1: free(tmp->name); free(tmp); return err; }