double rf_zmq_set_tx_srate(void* h, double srate) { double ret = 0.0; if (h) { rf_zmq_handler_t* handler = (rf_zmq_handler_t*)h; update_rates(handler, srate); ret = srate; } return ret; }
int main(int argc, char *argv[]) { double vel_keep = 0.333; double accel_keep = 0.333; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Setup and register algorithm with the server * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ stinger_registered_alg * alg = stinger_register_alg( .name="rate_monitor", .data_per_vertex=sizeof(double)*2, .data_description="dd wgtd_edge_vel wgtd_edge_accel", .host="localhost", ); if(!alg) { LOG_E("Registering algorithm failed. Exiting"); return -1; } bzero(alg->alg_data, sizeof(double) * 2 * alg->stinger->max_nv); double * vel = (double *)alg->alg_data; double * accel = vel + alg->stinger->max_nv; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Initial static computation * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ stinger_alg_begin_init(alg); { } stinger_alg_end_init(alg); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Streaming Phase * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ while(alg->enabled) { /* Pre processing */ if(stinger_alg_begin_pre(alg)) { /* nothing to do */ stinger_alg_end_pre(alg); } /* Post processing */ if(stinger_alg_begin_post(alg)) { update_rates(alg, stinger_max_active_vertex(alg->stinger)+1, vel, accel, vel_keep, accel_keep); stinger_alg_end_post(alg); } } LOG_I("Algorithm complete... shutting down"); }
int rf_zmq_open_multi(char* args, void** h, uint32_t nof_channels) { int ret = SRSLTE_ERROR; if (h) { *h = NULL; if (nof_channels != 1) { printf("rf_zmq only supports single port at the moment.\n"); return SRSLTE_ERROR; } rf_zmq_handler_t* handler = (rf_zmq_handler_t*)malloc(sizeof(rf_zmq_handler_t)); if (!handler) { perror("malloc"); return SRSLTE_ERROR; } bzero(handler, sizeof(rf_zmq_handler_t)); *h = handler; handler->base_srate = 23.04e6; // Sample rate for 100 PRB cell handler->rx_gain = 0.0; handler->info.max_rx_gain = +INFINITY; handler->info.min_rx_gain = -INFINITY; handler->info.max_tx_gain = +INFINITY; handler->info.min_tx_gain = -INFINITY; strcpy(handler->id, "zmq\0"); pthread_mutex_init(&handler->mutex, NULL); pthread_mutex_init(&handler->mutex_tx, NULL); // parse args if (args) { // base_srate { const char config_arg[] = "base_srate="; char config_str[PARAM_LEN] = {0}; char* config_ptr = strstr(args, config_arg); if (config_ptr) { copy_subdev_string(config_str, config_ptr + strlen(config_arg)); printf("Using base rate=%s\n", config_str); handler->base_srate = strtod(config_str, NULL); remove_substring(args, config_arg); remove_substring(args, config_str); } } // rxport { const char config_arg[] = "rx_port="; char config_str[PARAM_LEN] = {0}; char* config_ptr = strstr(args, config_arg); if (config_ptr) { copy_subdev_string(config_str, config_ptr + strlen(config_arg)); printf("Using rx_port=%s\n", config_str); strncpy(handler->rx_port, config_str, PARAM_LEN); handler->rx_port[PARAM_LEN - 1] = 0; remove_substring(args, config_arg); remove_substring(args, config_str); } } // txport { const char config_arg[] = "tx_port="; char config_str[PARAM_LEN] = {0}; char* config_ptr = strstr(args, config_arg); if (config_ptr) { copy_subdev_string(config_str, config_ptr + strlen(config_arg)); printf("Using tx_port=%s\n", config_str); strncpy(handler->tx_port, config_str, PARAM_LEN); handler->tx_port[PARAM_LEN - 1] = 0; remove_substring(args, config_arg); remove_substring(args, config_str); } } // id { const char config_arg[] = "id="; char config_str[PARAM_LEN_SHORT] = {0}; char* config_ptr = strstr(args, config_arg); if (config_ptr) { copy_subdev_string(config_str, config_ptr + strlen(config_arg)); printf("Using ID=%s\n", config_str); strncpy(handler->id, config_str, PARAM_LEN_SHORT); handler->id[PARAM_LEN_SHORT - 1] = 0; remove_substring(args, config_arg); remove_substring(args, config_str); } } } update_rates(handler, 1.92e6); // Create ZMQ context handler->context = zmq_ctx_new(); if (!handler->context) { fprintf(stderr, "[zmq] Error: creating new context\n"); goto clean_exit; } if (strlen(handler->tx_port) != 0) { // Initialise transmitter handler->transmitter = zmq_socket(handler->context, ZMQ_REP); if (!handler->transmitter) { fprintf(stderr, "[zmq] Error: creating transmitter socket\n"); goto clean_exit; } rf_zmq_info(handler, "Binding transmitter: %s\n", handler->tx_port); ret = zmq_bind(handler->transmitter, handler->tx_port); if (ret) { fprintf(stderr, "Error: connecting transmitter socket: %s\n", zmq_strerror(zmq_errno())); goto clean_exit; } #if ZMQ_TIMEOUT_MS // set recv timeout for transmitter int timeout = ZMQ_TIMEOUT_MS; if (zmq_setsockopt(handler->transmitter, ZMQ_RCVTIMEO, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting receive timeout on tx socket\n"); goto clean_exit; } if (zmq_setsockopt(handler->transmitter, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting receive timeout on tx socket\n"); goto clean_exit; } // set linger timeout for transmitter timeout = 0; if (zmq_setsockopt(handler->transmitter, ZMQ_LINGER, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting linger timeout on tx socket\n"); } #endif } else { fprintf(stdout, "[zmq] %s Tx port not specified. Disabling transmitter.\n", handler->id); } // initialize receiver if (strlen(handler->rx_port) != 0) { handler->receiver = zmq_socket(handler->context, ZMQ_REQ); if (!handler->receiver) { fprintf(stderr, "[zmq] Error: creating receiver socket\n"); goto clean_exit; } rf_zmq_info(handler, "Connecting receiver: %s\n", handler->rx_port); ret = zmq_connect(handler->receiver, handler->rx_port); if (ret) { fprintf(stderr, "Error: binding receiver socket: %s\n", zmq_strerror(zmq_errno())); goto clean_exit; } #if ZMQ_TIMEOUT_MS // set recv timeout for receiver int timeout = ZMQ_TIMEOUT_MS; if (zmq_setsockopt(handler->receiver, ZMQ_RCVTIMEO, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting receive timeout on tx socket\n"); goto clean_exit; } if (zmq_setsockopt(handler->receiver, ZMQ_SNDTIMEO, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting receive timeout on tx socket\n"); goto clean_exit; } timeout = 0; // set linger timeout for receiver if (zmq_setsockopt(handler->receiver, ZMQ_LINGER, &timeout, sizeof(timeout)) == -1) { fprintf(stderr, "Error: setting linger timeout on rx socket\n"); } #endif // init rx ringbuffer if (srslte_ringbuffer_init(&handler->rx_ringbuffer, BUFFER_SIZE)) { fprintf(stderr, "Error, initiating rx ringbuffer\n"); goto clean_exit; } } else { fprintf(stdout, "[zmq] %s Rx port not specified. Disabling receiver.\n", handler->id); } if (handler->transmitter == NULL && handler->receiver == NULL) { fprintf(stderr, "[zmq] Error: Neither Tx port nor Rx port specified.\n"); goto clean_exit; } // Create decimation and overflow buffer handler->buffer_decimation = srslte_vec_malloc(ZMQ_MAX_RX_BYTES); if (!handler->buffer_decimation) { fprintf(stderr, "Error: allocating decimation buffer\n"); goto clean_exit; } handler->buffer_tx = srslte_vec_malloc(ZMQ_MAX_RX_BYTES); if (!handler->buffer_tx) { fprintf(stderr, "Error: allocating tx buffer\n"); goto clean_exit; } handler->buffer_rx = srslte_vec_malloc(ZMQ_MAX_RX_BYTES); if (!handler->buffer_rx) { fprintf(stderr, "Error: allocating rx buffer\n"); goto clean_exit; } handler->running = true; if (handler->receiver) { pthread_create(&handler->thread, NULL, rf_zmq_async_rx_thread, handler); } ret = SRSLTE_SUCCESS; clean_exit: if (ret) { rf_zmq_close(handler); } } return ret; }
/* the main loop for the socket worker process */ void *socket_worker_thread(void *arg) { socket_worker_t *self = (socket_worker_t *) arg; queue_t *main_queue = &self->queue; relay_socket_t *sck = NULL; queue_t private_queue; queue_t spill_queue; memset(&private_queue, 0, sizeof(queue_t)); memset(&spill_queue, 0, sizeof(queue_t)); const config_t *config = self->base.config; int join_err; #define RATE_UPDATE_PERIOD 15 time_t last_rate_update = 0; while (!RELAY_ATOMIC_READ(self->base.stopping)) { time_t now = time(NULL); if (!sck) { SAY("Opening forwarding socket"); sck = open_output_socket_eventually(&self->base); if (sck == NULL || !(sck->type == SOCK_DGRAM || sck->type == SOCK_STREAM)) { FATAL_ERRNO("Failed to open forwarding socket"); break; } connected_inc(); } long since_rate_update = now - last_rate_update; if (since_rate_update >= RATE_UPDATE_PERIOD) { last_rate_update = now; update_rates(&self->rates[0], &self->totals, since_rate_update); update_rates(&self->rates[1], &self->totals, since_rate_update); update_rates(&self->rates[2], &self->totals, since_rate_update); } /* if we dont have anything in our local queue we need to hijack the main one */ if (private_queue.head == NULL) { /* hijack the queue - copy the queue state into our private copy * and then reset the queue state to empty. So the formerly * shared queue is now private. We only do this if necessary. */ if (!queue_hijack(main_queue, &private_queue, &GLOBAL.pool.lock)) { /* nothing to do, so sleep a while and redo the loop */ worker_wait_millisec(config->polling_interval_millisec); continue; } } RELAY_ATOMIC_INCREMENT(self->counters.received_count, private_queue.count); /* ok, so we should have something in our queue to process */ if (private_queue.head == NULL) { WARN("Empty private queue"); break; } ssize_t wrote = 0; if (!process_queue(self, sck, &private_queue, &spill_queue, &wrote)) { if (!RELAY_ATOMIC_READ(self->base.stopping)) { WARN("Closing forwarding socket"); close(sck->socket); sck = NULL; connected_dec(); } } accumulate_and_clear_stats(&self->counters, &self->recents, &self->totals); } if (control_is(RELAY_STOPPING)) { SAY("Socket worker stopping, trying forwarding flush"); stats_count_t old_sent = self->totals.sent_count; stats_count_t old_spilled = self->totals.spilled_count; stats_count_t old_dropped = self->totals.dropped_count; if (sck) { ssize_t wrote = 0; if (!process_queue(self, sck, &private_queue, &spill_queue, &wrote)) { WARN_ERRNO("Forwarding flush failed"); } accumulate_and_clear_stats(&self->counters, &self->recents, &self->totals); SAY("Forwarding flush forwarded %zd bytes in %llu events, spilled %llu events, dropped %llu events ", wrote, (unsigned long long) (self->totals.sent_count - old_sent), (unsigned long long) (self->totals.spilled_count - old_spilled), (unsigned long long) (self->totals.dropped_count - old_dropped)); } else { WARN("No forwarding socket to flush to"); } SAY("Socket worker spilling any remaining events to disk"); stats_count_t spilled = spill_all(self, &private_queue, &spill_queue); SAY("Socket worker spilled %llu events to disk", (unsigned long long) spilled); } else { accumulate_and_clear_stats(&self->counters, &self->recents, &self->totals); } SAY("worker[%s] in its lifetime received %lu sent %lu spilled %lu dropped %lu", (sck ? sck->to_string : self->base.arg), (unsigned long) RELAY_ATOMIC_READ(self->totals.received_count), (unsigned long) RELAY_ATOMIC_READ(self->totals.sent_count), (unsigned long) RELAY_ATOMIC_READ(self->totals.spilled_count), (unsigned long) RELAY_ATOMIC_READ(self->totals.dropped_count)); if (sck) { close(sck->socket); connected_dec(); } /* we are done so shut down our "pet" disk worker, and then exit with a message */ RELAY_ATOMIC_OR(self->disk_writer->base.stopping, WORKER_STOPPING); join_err = pthread_join(self->disk_writer->base.tid, NULL); if (join_err) FATAL("shutting down disk_writer thread error: pthread error %d", join_err); free(self->disk_writer); return NULL; }