int client_test(o2_message_ptr data, const char *types, o2_arg_ptr *argv, int argc, void *user_data) { o2_send(server_addresses[msg_count % N_ADDRS], 0, "i", msg_count); if (msg_count % 10000 == 0) { printf("client received %d messages\n", msg_count); } msg_count++; return O2_SUCCESS; }
// o2_ping_send_handler -- handler for /_o2/ps (short for "ping send") // wait for clock sync service to be established, // then send ping every 0.1s CLOCK_SYNC_HISTORY_LEN times, // then every 0.5s for 5s, then every 10s // void o2_ping_send_handler(o2_msg_data_ptr msg, const char *types, o2_arg_ptr *argv, int argc, void *user_data) { // this function gets called periodically to drive the clock sync // protocol, but if the process calls o2_clock_set(), then we // become the master, at which time we stop polling and announce // to all other processes that we know what time it is, and we // return without scheduling another callback. if (is_master) { o2_clock_is_synchronized = TRUE; return; // no clock sync; we're the master } clock_sync_send_time = o2_local_time(); int status = o2_status("_cs"); if (!found_clock_service) { found_clock_service = (status >= 0); if (found_clock_service) { O2_DBc(printf("%s ** found clock service, is_master=%d\n", o2_debug_prefix, is_master)); if (status == O2_LOCAL || status == O2_LOCAL_NOTIME) { assert(is_master); } else { // record when we started to send clock sync messages start_sync_time = clock_sync_send_time; char path[48]; // enough room for !IP:PORT/cs/get-reply snprintf(path, 48, "!%s/cs/get-reply", o2_context->process->proc.name); o2_method_new(path, "it", &cs_ping_reply_handler, NULL, FALSE, FALSE); snprintf(path, 32, "!%s/cs", o2_context->process->proc.name); clock_sync_reply_to = o2_heapify(path); } } } // earliest time to call this action again is clock_sync_send_time + 0.1s: o2_time when = clock_sync_send_time + 0.1; if (found_clock_service) { // found service, but it's non-local if (status < 0) { // we lost the clock service, resume looking for it found_clock_service = FALSE; } else { clock_sync_id++; o2_send("!_cs/get", 0, "is", clock_sync_id, clock_sync_reply_to); // TODO: test return? // run every 0.1 second until at least CLOCK_SYNC_HISTORY_LEN pings // have been sent to get a fast start, then ping every 0.5s until 5s, // then every 10s. o2_time t1 = CLOCK_SYNC_HISTORY_LEN * 0.1 - 0.01; if (clock_sync_send_time - start_sync_time > t1) when += 0.4; if (clock_sync_send_time - start_sync_time > 5.0) when += 9.5; O2_DBk(printf("%s clock request sent at %g\n", o2_debug_prefix, clock_sync_send_time)); } } // schedule another call to o2_ping_send_handler o2_clock_ping_at(when); }
void o2_clockrt_handler(o2_msg_data_ptr msg, const char *types, o2_arg_ptr *argv, int argc, void *user_data) { o2_extract_start(msg); o2_arg_ptr reply_to_arg = o2_get_next('s'); if (!reply_to_arg) return; char *replyto = reply_to_arg->s; int len = (int) strlen(replyto); if (len > 1000) { fprintf(stderr, "o2_clockrt_handler ignoring /cs/rt message with long reply_to argument\n"); return; // address too long - ignore it } char address[1024]; memcpy(address, replyto, len); memcpy(address + len, "/get-reply", 11); // include EOS o2_send(address, 0, "sff", o2_context->process->proc.name, mean_rtt, min_rtt); }
int main(int argc, const char * argv[]) { o2_initialize("test"); o2_add_service("client"); for (int i = 0; i < N_ADDRS; i++) { char path[100]; sprintf(path, "/client/benchmark/%d", i); o2_add_method(path, "i", &client_test, NULL, FALSE, FALSE); } for (int i = 0; i < N_ADDRS; i++) { char path[100]; sprintf(path, "!server/benchmark/%d", i); server_addresses[i] = (char *) O2_MALLOC(strlen(path)); strcpy(server_addresses[i], path); } while (o2_status("server") < O2_LOCAL) { o2_poll(); usleep(2000); // 2ms } printf("We discovered the server.\ntime is %g.\n", o2_get_time()); double now = o2_get_time(); while (o2_get_time() < now + 5) { o2_poll(); usleep(2000); } printf("Here we go! ...\ntime is %g.\n", o2_get_time()); o2_send("!server/benchmark/0", 0, "i", 0); while (1) { o2_poll(); //usleep(2000); // 2ms // as fast as possible } o2_finish(); return 0; }
// cs_ping_handler -- handler for /_cs/get // return the master clock time. Arguments are serial_no and reply_to. // send serial_no and current time to serial_no + "/get-reply" static void cs_ping_handler(o2_msg_data_ptr msg, const char *types, o2_arg_ptr *argv, int argc, void *user_data) { o2_arg_ptr serial_no_arg, reply_to_arg; o2_extract_start(msg); if (!(serial_no_arg = o2_get_next('i')) || !(reply_to_arg = o2_get_next('s'))) { return; } int serial_no = serial_no_arg->i32; char *replyto = reply_to_arg->s; int len = (int) strlen(replyto); if (len > 1000) { fprintf(stderr, "cs_ping_handler ignoring /_cs/get message with long reply_to argument\n"); return; // address too long - ignore it } char address[1024]; memcpy(address, replyto, len); memcpy(address + len, "/get-reply", 11); // include EOS o2_send(address, 0, "it", serial_no, o2_time_get()); }