/* also detect if there was a timejump, and act accordingly */ static inline void time_update (struct ev_loop *loop, ev_tstamp max_block) { int i; ev_tstamp odiff = loop->rtmn_diff; loop->mn_now = get_clock (); /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */ /* interpolate in the meantime */ if (likely (loop->mn_now - loop->now_floor < MIN_TIMEJUMP * .5)) { loop->ev_rt_now = loop->rtmn_diff + loop->mn_now; return; } loop->now_floor = loop->mn_now; loop->ev_rt_now = ev_time(); /* loop a few times, before making important decisions. * on the choice of "4": one iteration isn't enough, * in case we get preempted during the calls to * ev_time and get_clock. a second call is almost guaranteed * to succeed in that case, though. and looping a few more times * doesn't hurt either as we only do this on time-jumps or * in the unlikely event of having been preempted here. */ for (i = 4; --i; ) { ev_tstamp diff; loop->rtmn_diff = loop->ev_rt_now - loop->mn_now; diff = odiff - loop->rtmn_diff; if (likely ((diff < 0. ? -diff : diff) < MIN_TIMEJUMP)) return; /* all is well */ loop->ev_rt_now = ev_time (); loop->mn_now = get_clock (); loop->now_floor = loop->mn_now; } /* no timer adjustment, as the monotonic clock doesn't jump */ }
static void print_timer() { ev_tstamp now = ev_time(); ev_tstamp total_time = now - start_time; if ( 0 >= total_time ) return; fprintf(stderr, "{ \"posix_time\": %f, \"stdin_wait_ms\": %d, \"stdout_wait_ms\": %d, \"total_time_ms\": %d, \"bytes_out\": %lld }\n", now, (int)(1000 * ( stdin_pipe.time_waiting + ( mode != READING || 0 > stdin_pipe.timer_start ? 0 : now - stdin_pipe.timer_start ) ) ), (int)(1000 * ( stdout_pipe.time_waiting + ( mode != WRITING || 0 > stdout_pipe.timer_start ? 0 : now - stdout_pipe.timer_start) ) ), (int)(1000 * total_time), bytes_out ); }
int main(int argc, char **argv) { int flags; mode = READING; data_size = 0; bytes_out = 0; loop = ev_loop_new( EVBACKEND_SELECT ); start_time = ev_time(); stdout_pipe.time_waiting = 0; stdout_pipe.timer_start = -1; stdin_pipe.time_waiting = 0; stdin_pipe.timer_start = -1; /* flags = fcntl(STDIN_FILENO, F_GETFL, 0); if ( fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | flags ) == -1 ) fprintf(stderr, "{ \"msg\": \"Could not set O_NONBLOCK on stdin\" }\n", data_size, errno); flags = fcntl(STDOUT_FILENO, F_GETFL, 0); if ( fcntl(STDOUT_FILENO, F_SETFL, O_NONBLOCK | flags ) == -1 ) fprintf(stderr, "{ \"msg\": \"Could not set O_NONBLOCK on stdout\" }\n", data_size, errno); */ ev_io_init (&stdout_pipe.watcher, stdout_callback, STDOUT_FILENO, EV_WRITE); ev_io_init (&stdin_pipe.watcher, stdin_callback, STDIN_FILENO, EV_READ); ev_io_start( loop, &stdin_pipe.watcher ); ev_timer_init (&timer, timer_callback, 2.0, 2.0); ev_timer_start (loop, &timer); ev_signal_init (&exitsig, sigint_callback, SIGINT); ev_signal_start (loop, &exitsig); print_timer(); ev_run (loop, 0); }
static void stdin_callback (EV_P_ ev_io *w, int revents) { if ( 0 == data_size ) { if ( 0 >= ( data_size = read( STDIN_FILENO, &data[ 0 ], BUFFER_SIZE ) ) ) { print_timer(); if ( 0 == data_size ) fprintf(stderr, "{ \"posix_time\": %f, \"exit_status\": \"Success\", \"msg\": \"End of file reached\" }\n", ev_time()); else fprintf(stderr, "{ \"posix_time\": %f, \"exit_status\": \"Error\", \"msg\": \"Error reading from stdin\", \"errno\": %d }\n", ev_time(), errno); exit(data_size); } } if( 0 < data_size ) { // switch to write mode ev_tstamp now = ev_now( loop ); mode = WRITING; stdout_pipe.timer_start = now; if( 0 < stdin_pipe.timer_start ) stdin_pipe.time_waiting += now - stdin_pipe.timer_start; ev_io_init (&stdout_pipe.watcher, stdout_callback, STDOUT_FILENO, EV_WRITE); ev_io_start( loop, &stdout_pipe.watcher ); // start stdout ev_io_stop( loop, &stdin_pipe.watcher ); // stop stdin } }
static void sigint_callback (struct ev_loop *loop, ev_signal *w, int revents) { print_timer(); fprintf(stderr, "{ \"posix_time\": %f, \"exit_status\": \"Success\", \"msg\": \"Received SIGINT\" }\n", ev_time() ); exit(0); }
static void timer_callback(struct ev_loop *loop, ev_timer *w, int revents) { static int bytes = 0; if ( bytes > 0 && bytes >= bytes_out ) { if( mode == READING ) fprintf(stderr, "{ \"posix_time\": %f, \"msg\": \"Stalled reading from stdin\" }\n", ev_time()); else fprintf(stderr, "{ \"posix_time\": %f, \"msg\": \"Stalled writing to stdout\" }\n", ev_time()); } bytes = bytes_out; print_timer(); }
static void stdout_callback (EV_P_ ev_io *w, int revents) { if ( 0 < data_size ) { if ( data_size != write( STDOUT_FILENO, &data[ 0 ], data_size ) ) { print_timer(); fprintf(stderr, "{ \"posix_time\": %f, \"exit_status\": \"Error\", \"msg\": \"Error writing to stdout\" }\n", ev_time()); exit(data_size); } bytes_out += data_size; data_size = 0; } if ( 0 == data_size ) { // Switch to read mode ev_tstamp now = ev_now( loop ); mode = READING; stdin_pipe.timer_start = now; if ( 0 < stdout_pipe.timer_start ) stdout_pipe.time_waiting += now - stdout_pipe.timer_start; ev_io_init (&stdin_pipe.watcher, stdin_callback, STDIN_FILENO, EV_READ); ev_io_start( loop, &stdin_pipe.watcher ); ev_io_stop( loop, &stdout_pipe.watcher ); } }
static PyObject * pyev_time(PyObject *module) { return PyFloat_FromDouble(ev_time()); }
int main(int argc, char **argv) { int do_fork = 1; char *config_fn = DEFAULT_CONFIG_FILE; char *pid_fn = DEFAULT_PID_FILE; int c; evloop = EV_DEFAULT; ev_started_at = ev_time(); opterr = 0; while ((c = getopt (argc, argv, "vhdfc:p:s:l:")) != -1) { switch (c) { case 'v': verbose++; break; case 'h': usage(0); return 0; case 'd': debug = 1; do_fork = 0; break; case 'f': do_fork = 0; break; case 'c': config_fn = optarg; break; case 'p': pid_fn = optarg; break; case 's': server_str_id = strdup(optarg); break; case 'l': server_listen_port = atoi(optarg); if (server_listen_port < 1 || server_listen_port > 65534){ fprintf (stderr, "Invalid listen port: %s.\n", optarg); return 1; } break; case '?': if ((optopt == 'c') || (optopt == 'p') || (optopt == 's') || (optopt == 'l')) fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: usage(); return 1; } } if (optind < argc) { fprintf (stderr, "Unknown option: %s.\n", argv[optind]); return 1; } rtsp_server = rtsp_alloc(); if (!rtsp_server){ return 0; } log_to_stderr = !do_fork; if (!log_to_stderr) openlog(PROGRAM_NAME, LOG_PID, LOG_DAEMON); if (load_config(config_fn)) { fprintf (stderr, "Error loading config file.\n"); return 2; } my_random_init(); if (do_fork){ log_debug("forking..."); if (daemon(0, 0)){ log_error("daemonize failed: %s", strerror(errno)); return -1; } if (write_pid_file(pid_fn)){ log_warning("failed to create pid file"); } ev_loop_fork(evloop); } if (!do_fork) { ev_signal_init (&signal_watcher1, sig_term_cb, SIGINT); ev_signal_start (evloop, &signal_watcher1); } ev_signal_init (&signal_watcher2, sig_term_cb, SIGTERM); ev_signal_start (evloop, &signal_watcher2); ev_signal_init (&signal_watcher3, sig_ignore_cb, SIGHUP); ev_signal_start (evloop, &signal_watcher3); ev_signal_init (&signal_watcher4, sig_ignore_cb, SIGPIPE); ev_signal_start (evloop, &signal_watcher4); if (csconv_init()){ return 0; } if (rtsp_init(rtsp_server)){ csconv_cleanup(); return 0; } elevate_privileges(); setup_io_prio(); drop_privileges(); log_info("starting..."); ev_run(evloop, 0); log_info("cleaning up..."); rtsp_cleanup(rtsp_server); csconv_cleanup(); if (server_str_id) free(server_str_id); log_info("exiting..."); if (!log_to_stderr) closelog(); return 0; }