/** * \brief Subscribe for a given type of message. * * \param[in] function Handler function in case a matching record is * published. * \param[in] state State passed on to handler function. * \param[out] id Id of the subscription. In case of the value is undefined. * \param query What type of records you want to subscribe. * \param ... Additional arguments to format the record using vsprintf. * * \retval SYS_ERR_OK * \retval OCT_ERR_MAX_SUBSCRIPTIONS * \retval OCT_ERR_PARSER_FAIL * \retval OCT_ERR_ENGINE_FAIL */ errval_t oct_subscribe(subscription_handler_fn function, const void *state, subscription_t *id, const char *query, ...) { assert(function != NULL); assert(query != NULL); assert(id != NULL); va_list args; errval_t err = SYS_ERR_OK; char* buf = NULL; FORMAT_QUERY(query, args, buf); // send to skb struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); errval_t error_code; uint64_t fl_function = 0; uint64_t fl_state = 0; fl_function = (uint64_t)(uintptr_t)function; fl_state = (uint64_t)(uintptr_t)state; err = cl->call_seq.subscribe(cl, buf, fl_function, fl_state, id, &error_code); // XXX: Sending Pointer as uint64 if (err_is_ok(err)) { err = error_code; } free(buf); return err; }
/** * \brief Client enters a barrier. Blocks until all clients have entered the * barrier. * * Each client creates a (sequential record) based on the provided name. * Once a client sees the specified amount (wait_for) of records it * creates a record that wakes up all waiting clients. * * \param[in] name Name of the barrier. * \param[out] barrier_record Record created for each client. * \param[in] wait_for Number of clients entering the barrier. */ errval_t oct_barrier_enter(const char* name, char** barrier_record, size_t wait_for) { errval_t err; errval_t exist_err; char* record = NULL; char** names = NULL; uint64_t mode = 0; uint64_t state = 0; uint64_t fn = 0; octopus_trigger_id_t tid; size_t current_barriers = 0; octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD, octopus_BINDING_RPC, OCT_ON_SET, NULL, NULL); err = oct_set_get(SET_SEQUENTIAL, barrier_record, "%s_ { barrier: '%s' }", name, name); err = oct_get_names(&names, ¤t_barriers, "_ { barrier: '%s' }", name); oct_free_names(names, current_barriers); if (err_is_fail(err)) { return err; } //debug_printf("current_barriers: %lu wait_for: %lu\n", current_barriers, // wait_for); if (current_barriers != wait_for) { struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); err = cl->call_seq.exists(cl, name, t, &tid, &exist_err); if (err_is_fail(err)) { return err; } err = exist_err; if (err_is_ok(err)) { // Barrier already exists } if (err_no(err) == OCT_ERR_NO_RECORD) { // Wait until barrier record is created err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state); free(record); assert(mode & OCT_REMOVED); err = SYS_ERR_OK; } else { // Some other error happend, return it } } else { // We are the last to enter the barrier, // wake up the others err = oct_set(name); } return err; }
/** * \brief looks up the name and registers a callback * * \param iface Name of the domain * \param retdomid returns the Xeon Phi Domain ID */ errval_t domain_wait(const char *iface, struct xnode *node, void *state, xphi_dom_id_t *retdom) { errval_t err; struct octopus_thc_client_binding_t* c = oct_get_thc_client(); if (c == NULL) { return LIB_ERR_NAMESERVICE_NOT_BOUND; } struct wait_state *ws = malloc(sizeof(*ws)); if (ws == NULL) { return LIB_ERR_MALLOC_FAIL; } ws->usr_state = state; ws->node = node; octopus_mode_t m = OCT_ON_SET; octopus_trigger_t iface_set_trigger = oct_mktrigger( OCT_ERR_NO_RECORD, octopus_BINDING_EVENT, m, domain_wait_trigger_handler, ws); char* record = NULL; errval_t error_code; err = c->call_seq.get(c, iface, iface_set_trigger, &record, &ws->tid, &error_code); if (err_is_fail(err)) { free(record); return err; } if (err_is_fail(error_code)) { free(record); return error_code; } free(ws); xphi_dom_id_t domid = 0; err = oct_read(record, "_ { domid: %d }", &domid); if (err_is_fail(err) || domid == 0) { err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID); free(record); return err; } if (retdom) { *retdom = domid; } return err; }
/** * \brief Unsubscribes a subscription. * * \param id Id of the subscription (as provided by oct_subscribe). * * \retval SYS_ERR_OK * \retval OCT_ERR_PARSER_FAIL * \retval OCT_ERR_ENGINE_FAIL */ errval_t oct_unsubscribe(subscription_t id) { // send to skb struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); errval_t error_code; errval_t err = cl->call_seq.unsubscribe(cl, id, &error_code); if (err_is_ok(err)) { err = error_code; } return err; }
errval_t oct_sem_wait(uint32_t id) { errval_t err = SYS_ERR_OK; char* result = NULL; octopus_trigger_id_t tid; octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD, octopus_BINDING_RPC, OCT_ON_SET, NULL, NULL); struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); char query[100]; snprintf(query, 99, "r'sem\\.%"PRIu32"\\.[0-9]+' { sem: %"PRIu32" }", id, id); char lock_name[100]; snprintf(lock_name, 99, "sem.%"PRIu32"", id); // XXX: The current implementation suffers from a herd effect, // may be worth it to use locks for this critical section while (1) { cl->call_seq.get(cl, query, t, &result, &tid, &err); if (err_is_ok(err)) { errval_t del_err = oct_del(result); free(result); result = NULL; if (err_is_ok(del_err)) { break; // Decreased successfully } else if (err_no(del_err) == OCT_ERR_NO_RECORD) { continue; // Need to start over } else { err = del_err; break; // Unexpected error } } else if (err_no(err) == OCT_ERR_NO_RECORD) { // No record found, wait until one is posted char* trigger_result = NULL; uint64_t fn, mode, state; cl->recv.trigger(cl, &tid, &fn, &mode, &trigger_result, &state); free(trigger_result); } else { break; // Unexpected error } } free(result); return err; }
/** * \brief Publishes a record. * * \param record The record to publish. * \param ... Additional arguments to format the record using vsprintf. * * \retval SYS_ERR_OK * \retval OCT_ERR_PARSER_FAIL * \retval OCT_ERR_ENGINE_FAIL */ errval_t oct_publish(const char *record, ...) { assert(record != NULL); va_list args; errval_t err = SYS_ERR_OK; char *buf = NULL; FORMAT_QUERY(record, args, buf); struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); errval_t error_code; err = cl->call_seq.publish(cl, buf, &error_code); if(err_is_ok(err)) { err = error_code; } free(buf); return err; }
/** * \brief Leave a barrier. Blocks until all involved parties have * called oct_barrier_leave(). * * Client deletes its barrier record. In case the client * was the last one we delete the special record which * wakes up all other clients. * * \param barrier_record Clients own record as provided by * oct_barrier_enter. */ errval_t oct_barrier_leave(const char* barrier_record) { errval_t exist_err; errval_t err; char* rec_name = NULL; char* barrier_name = NULL; char* record = NULL; char** names = NULL; size_t remaining_barriers = 0; uint64_t mode = 0; uint64_t state = 0; uint64_t fn = 0; octopus_trigger_id_t tid; octopus_trigger_t t = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_RPC, OCT_ON_DEL, NULL, NULL); //debug_printf("leaving: %s\n", barrier_record); err = oct_read(barrier_record, "%s { barrier: %s }", &rec_name, &barrier_name); if (err_is_ok(err)) { err = oct_del(rec_name); if (err_is_fail(err)) { goto out; } err = oct_get_names(&names, &remaining_barriers, "_ { barrier: '%s' }", barrier_name); oct_free_names(names, remaining_barriers); //debug_printf("remaining barriers is: %lu\n", remaining_barriers); if (err_is_ok(err)) { struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); err = cl->call_seq.exists(cl, barrier_name, t, &tid, &exist_err); if (err_is_fail(err)) { goto out; } err = exist_err; if (err_is_ok(err)) { // Wait until everyone has left the barrier err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state); assert(mode & OCT_REMOVED); } else if (err_no(err) == OCT_ERR_NO_RECORD) { // barrier already deleted err = SYS_ERR_OK; } } else if (err_no(err) == OCT_ERR_NO_RECORD) { // We are the last one to leave the barrier, // wake-up all others err = oct_del("%s", barrier_name); } else { // Just return the error } } out: free(record); free(rec_name); free(barrier_name); return err; }
int main(int argc, char *argv[]) { oct_init(); errval_t err = SYS_ERR_OK; octopus_trigger_id_t tid; size_t received = 0; err = oct_set("obj1 { attr: 1 }"); ASSERT_ERR_OK(err); err = oct_set("obj2 { attr: 2 }"); ASSERT_ERR_OK(err); err = oct_set("obj3 { attr: 3 }"); ASSERT_ERR_OK(err); struct octopus_thc_client_binding_t* c = oct_get_thc_client(); octopus_trigger_t record_deleted = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_EVENT, OCT_ON_DEL, trigger_handler, &received); errval_t error_code = SYS_ERR_OK; char* output = NULL; err = c->call_seq.get(c, "r'^obj.$' { attr: 3 } ", record_deleted, &output, &tid, &error_code); ASSERT_ERR_OK(err); ASSERT_ERR_OK(error_code); ASSERT_STRING(output, "obj3 { attr: 3 }"); debug_printf("tid is: %lu\n", tid); free(output); oct_del("obj3"); while (received != 1) { messages_wait_and_handle_next(); } received = 0; tid = 0; octopus_mode_t m = OCT_ON_SET | OCT_ON_DEL | OCT_PERSIST; octopus_trigger_t ptrigger = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_EVENT, m, persistent_trigger, &received); output = NULL; err = c->call_seq.get(c, "obj2", ptrigger, &output, &tid, &error_code); ASSERT_ERR_OK(err); ASSERT_ERR_OK(error_code); debug_printf("tid is: %lu\n", tid); ASSERT_STRING(output, "obj2 { attr: 2 }"); oct_del("obj2"); while (received != 1) { messages_wait_and_handle_next(); } received = 0; oct_set("obj2 { attr: 'asdf' }"); while (received != 1) { messages_wait_and_handle_next(); } received = 0; err = oct_remove_trigger(tid); DEBUG_ERR(err, "remove trigger"); ASSERT_ERR_OK(err); while (received != 1) { messages_wait_and_handle_next(); } printf("d2trigger SUCCESS!\n"); return EXIT_SUCCESS; }