Beispiel #1
0
event_request_t *event_add( context_t *ctx, const long fd, unsigned int flags )
{
	event_request_t *entry = event_find( ctx,  fd, flags );

	//x_printf(ctx, "EVENT ADD called.  fd = %ld, flags = %02x (%c)\n",fd,flags,flags&EH_READ?'r':(flags&EH_WRITE?'w':(flags&EH_SPECIAL?'S':'?')));
	if( !entry )
		entry = event_find_free_slot();

    if( ! entry )
        return 0L;

	entry->fd = fd;
	entry->flags |= flags;
	entry->ctx = ctx;

	if( flags & EH_SIGNAL ) {
		// For signals, make sure the handler is installed
		if( ! sigismember( &event_signals.event_signal_mask, (int)fd ) ) {
			struct sigaction action_handler;
			memset( &action_handler, 0, sizeof( action_handler ) );
			action_handler.sa_handler = handle_signal_event;
			action_handler.sa_flags = 0; // SA_RESTART;
			sigaction( (int)fd, &action_handler, NULL );
			sigaddset( &event_signals.event_signal_mask, (int) fd );
			sigdelset( &event_signals.event_signal_default, (int) fd );
		}
	} else if( flags & EH_WANT_TICK ) {
		entry->timestamp = rel_time(0L);
	} else
		// For un-special file descriptors, force non-blocking
        if( (flags & (EH_READ|EH_WRITE)) && ! ( flags & EH_SPECIAL ) )
            fcntl((int)fd, F_SETFL, fcntl((int)fd, F_GETFL) | O_NONBLOCK);

	return entry;
}
Beispiel #2
0
ssize_t process_unicorn_packet( context_t *ctx )
{
	unicorn_config_t *cf = ctx->data;

	x_printf(ctx, "Entering process_unicorn_packet()\n");

	size_t ready = u_ringbuf_ready( &cf->input );

	if( !ready )
		return -1;

	if( cf->flags & UNICORN_EXPECTING_DATA ) {
		return process_unicorn_data( ctx, ready );
	} else {
		if( ready >= sizeof( frmHdr_t ) ) {
			u_ringbuf_read( &cf->input, & cf->msgHdr, sizeof( cf->msgHdr ) );
			if( MAGIC_NUMBER != cf->msgHdr.magicNo ) {
				x_printf(ctx,"MAGIC NUMBER FAIL... tossing the baby out with the bathwater..\n");
				u_ringbuf_init( &cf->input );
				cf->flags &= ~(unsigned int)UNICORN_EXPECTING_DATA;
				x_printf(ctx, "Leaving process_unicorn_packet()\n");
				return -1;
			}

			cf->last_message = rel_time(0L);
			x_printf(ctx, "Leaving process_unicorn_packet() via process_unicorn_header()\n");
			return process_unicorn_header( ctx );
		}
	}

	x_printf(ctx, "Leaving process_unicorn_packet()\n");
	// return because there is nothing useful in the buffer..
	return -1;
}
Beispiel #3
0
ssize_t send_unicorn_command( context_t *ctx, cmdHost_t cmd, cmdState_t state, size_t length, void *data )
{
	unicorn_config_t *cf = ctx->data;

	driver_data_t notification = { TYPE_DATA, ctx, {} };

	frmHdr_t *frame = alloca( sizeof( frmHdr_t ) + length );

	if( !frame )
		return -1;

	frame->magicNo = MAGIC_NUMBER;
	frame->cmd = cmd;
	frame->state = state;
	frame->length = (uint16_t) length;

	if( length )
		memmove( &frame[1], data, length );

	notification.event_data.data = frame;
	notification.event_data.bytes = sizeof( frmHdr_t ) + length;

#ifdef KEEPALIVE_INCLUDES_OUTGOING
	cf->last_message = rel_time(0L);
#endif
	return emit( cf->modem, EVENT_DATA_OUTGOING, &notification );
}
Beispiel #4
0
        steady_time_point(std::chrono::time_point<Clock, Duration> const& std_abs_time)
        {
            boost::chrono::nanoseconds rel_time(
                std::chrono::duration_cast<std::chrono::nanoseconds>(
                    std_abs_time - Clock::now()).count());

            _abs_time = boost::chrono::steady_clock::now() + rel_time;
        }
Beispiel #5
0
int handle_event_set(fd_set * readfds, fd_set * writefds, fd_set * exceptfds)
{
	time_t              now = rel_time(0L);
	int                 i;

	for (i = 0; i < MAX_EVENT_REQUESTS; i++) {
		if (event_table[i].flags && ((event_table[i].flags & EH_SPECIAL) == 0)) {

			driver_data_t       data = { TYPE_FD, 0L, {}
			};
			data.event_request.fd = event_table[i].fd;
			data.event_request.flags = event_table[i].flags;

			if ((event_table[i].flags & EH_EXCEPTION) && FD_ISSET((unsigned int)event_table[i].fd, exceptfds)) {
				//d_printf("Exception event for %s\n",event_table[i].ctx->name);
				event_table[i].ctx->driver->emit(event_table[i].ctx, EVENT_EXCEPTION, &data);
			}

			if ((event_table[i].flags & EH_WRITE) && FD_ISSET((unsigned int)event_table[i].fd, writefds)) {
				//d_printf("Write event for %s\n",event_table[i].ctx->name);
				event_table[i].ctx->driver->emit(event_table[i].ctx, EVENT_WRITE, &data);
			}

			if ((event_table[i].flags & EH_READ) && FD_ISSET((unsigned int)event_table[i].fd, readfds)) {
				//d_printf("Read event for %s\n",event_table[i].ctx->name);
				event_table[i].ctx->driver->emit(event_table[i].ctx, EVENT_READ, &data);
			}

		} else if (event_table[i].flags & EH_TIMER) {

			if (alarm_table[event_table[i].fd].event_time <= now) {
				alarm_table[event_table[i].fd].flags |= ALARM_FIRED;

				//d_printf("Alarm marked as FIRED...\n");

				driver_data_t       data = { TYPE_ALARM, 0, {} };
				data.event_alarm = (int) event_table[i].fd;
				event_table[i].ctx->driver->emit(event_table[i].ctx, EVENT_ALARM, &data);

				// If the event handler changes the alarm in any way, the 'fired' flag is cleared
				if (alarm_table[event_table[i].fd].flags & ALARM_FIRED) {
					//d_printf("ALARM event for %s\n",event_table[i].ctx->name);
					handle_event_alarm(&event_table[i]);
				}
			}

		}
	}
	return 0;
}
Beispiel #6
0
int unicorn_init(context_t * ctx)
{
	unicorn_config_t *cf ;

	if (0 == (cf = (unicorn_config_t *) calloc( sizeof( unicorn_config_t ) , 1 )))
		return 0;

	cf->pending_action_timeout = cf->last_message = rel_time(0L);
	cf->driver_state = CMD_ST_UNKNOWN;

	u_ringbuf_init(&cf->input);
	ctx->data = cf;

	return 1;
}
Beispiel #7
0
int handle_timer_events()
{
	int i;

	driver_data_t tick = { TYPE_TICK, 0L, {} };
	tick.event_tick = rel_time(0L);

	//d_printf("Checking tick requests..\n");
	// All drivers get the same 'tick' timestamp, even if some drivers take time to process the tick
	for(i = 0; i < MAX_EVENT_REQUESTS; i++ )
		if( ((event_table[i].flags & EH_WANT_TICK) == EH_WANT_TICK) && ((event_table[i].flags & EH_SPECIAL) == 0 )) {
			//d_printf("event[%d] Delivering tick to %s if %ld > %ld\n",i, event_table[i].ctx->name, tick.event_tick, event_table[i].timestamp );
			if( tick.event_tick > event_table[i].timestamp ) {
				event_table[i].ctx->driver->emit( event_table[i].ctx, EVENT_TICK, &tick );
				event_table[i].timestamp = tick.event_tick + (time_t) event_table[i].fd;
			}
		}

	return 0;
}
Beispiel #8
0
int event_loop( long timeout )
{
	long max_fd = 0;

	fd_set fds_read, fds_write, fds_exception;
	if( ! create_event_set( &fds_read, &fds_write, &fds_exception, &max_fd ) )
		return -1;

	time_t now = rel_time(0L);
	long alarm_time = alarm_getnext();

	// Reduce 'timeout' to ensure the next scheduled alarm occurs on time
	if( alarm_time >= 0 ) {
		if( alarm_time > now ) {
			if( timeout > ( alarm_time - now ))
				timeout = alarm_time - now;
		} else
			timeout = 0;
	}

#ifdef USE_PSELECT
	// If I know there are signals which need processing, reset the select timeout to 0
	// Signals are normally blocked, so these would be manufactured events.
	struct timespec tm = { timeout / 1000, (timeout % 1000) * 1000 * 1000 };

	if( event_signals.event_signal_pending_count )
		tm.tv_nsec = tm.tv_sec = 0;

	int rc = pselect( (int) max_fd, &fds_read, &fds_write, &fds_exception, &tm, &event_signals.event_signal_default );
#else
	// expect queued signals to occur immediately
	sigprocmask( SIG_SETMASK, &event_signals.event_signal_default, NULL );
	sleep(0);

	if( event_signals.event_signal_pending_count )
		timeout = 0;

	struct timeval tm = { timeout / 1000, (timeout % 1000) * 1000 };

#if 0
#ifndef NDEBUG
	int i = 0;
	printf("READ: ");
	for(i=0;i<64;i++)
		if(FD_ISSET(i,&fds_read)) {
			printf("%d ",i);
			if( fcntl( i, F_GETFL ) < 0 )
				printf("*");
		}
	printf("WRITE: ");
	for(i=0;i<64;i++)
		if(FD_ISSET(i,&fds_write)) {
			printf("%d ",i);
			if( fcntl( i, F_GETFL ) < 0 )
				printf("*");
		}
	printf("EXCEPTION: ");
	for(i=0;i<64;i++)
		if(FD_ISSET(i,&fds_exception)) {
			printf("%d ",i);
			if( fcntl( i, F_GETFL ) < 0 )
				printf("*");
		}
	printf("\n");
#endif
#endif

#ifndef NDEBUG
	//printf("calling select...");fflush(stdout);
#endif
	int rc = select( max_fd, &fds_read, &fds_write, &fds_exception, &tm );
#ifndef NDEBUG
	//printf("done\n");fflush(stdout);
#endif
#endif

	sigprocmask(SIG_BLOCK, &event_signals.event_signal_mask, NULL);

	if( rc < 0 ) {
		if( (errno != EINTR)
#ifdef mips
				&& (errno != ENOENT)
#endif
		  ) {
			d_printf("(p)select returned %d (errno = %d - %s)\n",rc, errno, strerror(errno));
			exit(0);
			return -1;
		} else {
			return 0;  // timeout - nothing to do
		}
	}

	if( event_signals.event_signal_pending_count ) {
		//d_printf("Calling handle_pending_signals()\n");
		handle_pending_signals();
	}

	//d_printf("Calling handle_event_set()\n");
	rc = handle_event_set( &fds_read, &fds_write, &fds_exception );

	if( !rc ) {
		//d_printf("Calling handle_timer_events()\n");
		handle_timer_events();
	}

	return 0;
}
Beispiel #9
0
ssize_t unicorn_handler(context_t *ctx, event_t event, driver_data_t *event_data)
{
	event_data_t   *data = 0L;
	event_child_t *child = 0L;

	unicorn_config_t *cf = (unicorn_config_t *) ctx->data;

	//x_printf(ctx, "<%s> Event = \"%s\" (%d)\n", ctx->name, event_map[event], event);

	if (event_data->type == TYPE_DATA)
		data = &event_data->event_data;
	else if( event_data->type == TYPE_CHILD )
		child = & event_data->event_child;

	switch (event) {
		case EVENT_INIT:
			{
				x_printf(ctx,"calling event add SIGQUIT\n");
				event_add( ctx, SIGQUIT, EH_SIGNAL );
				x_printf(ctx,"calling event add SIGTERM\n");
				event_add( ctx, SIGTERM, EH_SIGNAL );
				x_printf(ctx,"calling event 1000 EH_WANT_TICK\n");
				event_add( ctx, 1000, EH_WANT_TICK );

				cf->driver = config_get_item( ctx->config, "endpoint" );

				if( ! config_get_timeval( ctx->config, "retry", &cf->retry_time ) )
					cf->retry_time = 120*1000;

				if( cf->driver )
					start_service( &cf->modem, cf->driver, ctx->config, ctx, 0L );

				if( !cf->modem ) {
					logger( ctx, "Unable to launch modem driver. Exiting\n" );
					cf->state = UNICORN_STATE_ERROR;
					context_terminate( ctx );
					return -1;
				}

				cf->state = UNICORN_STATE_IDLE;
			}
			break;

		case EVENT_TERMINATE:
			{
				cf->pending_action_timeout = rel_time(0L);

				cf->flags |= UNICORN_TERMINATING; // In process of terminating the modem driver
				cf->state  = UNICORN_STATE_STOPPING; // In process of terminating self

				// Ensure 'exec' driver known not to restart when the modem driver terminates.
				// If the modem driver is something other than 'exec', this should be ignored.
				uint8_t flag = 0;
				driver_data_t notification = { TYPE_CUSTOM, ctx, {} };
				notification.event_custom = &flag;
				emit(cf->modem, EXEC_SET_RESPAWN, &notification);

				if( cf->driver_state == CMD_ST_ONLINE ) {
					x_printf(ctx,"Driver is online - sending disconnect\n");
					send_unicorn_command( ctx, CMD_DISCONNECT, CMD_ST_OFFLINE, 0, 0L );
				} else {
					x_printf(ctx,"Driver is offline - sending shutdown\n");
					send_unicorn_command( ctx, CMD_STATE, CMD_ST_OFFLINE, 0, 0L );
				}
			}
			break;

		case EVENT_RESTART:
			// This event is used to signal that the modem driver needs to resync.
			// set the 'reconnecting' flag and send a disconnect
			x_printf(ctx,"EVENT_RESTART: - sending disconnect to modem\n");
			//logger(ctx, "Sending disconnect command to modem driver");
			if( event_data->source == ctx->owner ) {
				cf->pending_action_timeout = rel_time(0L);
				cf->flags |= UNICORN_WAITING_FOR_CONNECT;
				if( cf->modem ) {
					x_printf(ctx, "Sending CMD_DISCONNECT to modem driver (%s)\n",cf->modem->name);
					if( (event_data->type == TYPE_CUSTOM) && event_data->event_custom ) {
						logger(ctx, "Sending abort command to modem driver due to unexpected disconnect");
						send_unicorn_command( ctx, CMD_ABORT, CMD_ST_OFFLINE, 0, 0L );
					} else {
						logger(ctx, "Sending disconnect command to modem driver");
						send_unicorn_command( ctx, CMD_DISCONNECT, CMD_ST_OFFLINE, 0, 0L );
					}
				} else {
					x_printf(ctx, "Modem driver not running.. doing nothing.\n");
				}
			} else {
				x_printf(ctx,"Forwarding EVENT_RESTART to owner (%s)\n",ctx->name);
				emit2( ctx, EVENT_RESTART, event_data);
			}
			break;

		case EVENT_CHILD:
			x_printf(ctx,"Got a message from a child (%s:%d).. probably starting\n", child->ctx->name, child->action);
			if ( child->ctx == cf->modem ) {
				if( child->action == CHILD_STARTING ) {
					cf->state = UNICORN_STATE_RUNNING;
					cf->flags &= ~(unsigned int) UNICORN_RESTARTING;
					// Assume ensure the first time the modem driver starts it skips the connection delay
					cf->flags |= UNICORN_FIRST_START;
				}

				if ( child->action == CHILD_STOPPED ) {
					x_printf(ctx,"Modem driver terminated - restart or terminate\n");
					// modem driver terminated.  Restart or exit.
					cf->state = UNICORN_STATE_IDLE;
					if ( cf->flags & UNICORN_TERMINATING ) {
						x_printf(ctx,"Terminating immediately\n");
						context_terminate( ctx );
					} else {
						x_printf(ctx,"Need to restart modem driver\n");
						cf->flags |= UNICORN_RESTARTING;
						cf->pending_action_timeout = rel_time(0L);
						// Reset the driver state, and notify the parent that we are offline
						cf->driver_state = CMD_ST_UNKNOWN;
						context_owner_notify( ctx, CHILD_EVENT, UNICORN_MODE_OFFLINE );
					}
				}
			}
			break;

		case EVENT_DATA_INCOMING:
		case EVENT_DATA_OUTGOING:
			if( event_data->source == cf->modem ) {

				size_t bytes = data->bytes;
				size_t offset = 0;

				while( bytes ) {

					size_t to_read = u_ringbuf_avail( &cf->input );
					if( to_read > bytes )
						to_read = bytes;

					u_ringbuf_write( &cf->input, &((char *)data->data)[offset], to_read );

					bytes -= to_read;
					offset += to_read;

					while(process_unicorn_packet(ctx) >= 0);
				}

				return (ssize_t) offset;
			} else {
				send_unicorn_command( ctx, CMD_DATA, CMD_ST_ONLINE, data->bytes,data->data);
				return (ssize_t) data->bytes;
			}

			break;

		case EVENT_READ:
			break;

		case EVENT_EXCEPTION:
			break;

		case EVENT_SIGNAL:
			x_printf(ctx,"Woa! Got a sign from the gods... %d\n", event_data->event_signal);
			if( event_data->event_signal == SIGQUIT || event_data->event_signal == SIGTERM )
				emit( ctx, EVENT_TERMINATE, 0L );
			break;

		case EVENT_TICK:
			{
				time_t now = rel_time(0L);

				// Handle case where a massive time shift due to NTP resync causes all timeouts to fire simultaneously
				// This is technically deprecated due to the use of rel_time()
				if( (now - cf->last_message) > MAXIMUM_SAFE_TIMEDELTA ) {
					logger(ctx, "WARNING: Resetting timeout due to RTC time change");
					cf->last_message = now;
				}

				if( ((now - cf->last_message) > UNICORN_KEEPALIVE_TIMEOUT ) && ( cf->driver_state != CMD_ST_UNKNOWN )) {

					if( ~ cf->flags & UNICORN_LAGGED ) {
						// Its been a couple of minutes since the last keepalive, reset the driver_state
						// to unknown and prompt for one.
						logger(ctx,"Forcing connection state request due to communications timeout.\n");
						cf->flags |= UNICORN_LAGGED;
						cf->retry_count = UNICORN_KEEPALIVE_RETRY_MAX;
					}

					if( cf->retry_count ) {
						send_unicorn_command( ctx, CMD_STATE, CMD_ST_OFFLINE, 0, 0L );
						cf->retry_count --;
					} else {
						// Its been a long time since the last message, despite prompting for one
						// restart the modem driver

						logger(ctx, "Communications timeout. Restarting modem driver.");
						uint8_t sig = SIGHUP;
						driver_data_t notification = { TYPE_CUSTOM, ctx, {} };
						notification.event_custom = &sig;

						emit( cf->modem, EVENT_RESTART, &notification );
					}
					cf->last_message = now;
				}

				if( (cf->flags & UNICORN_RESTARTING) && ((now - cf->pending_action_timeout) > UNICORN_RESTART_DELAY )) {
					x_printf(ctx,"Restart delay expired - restarting modem driver\n");
					cf->pending_action_timeout = rel_time(0L);
					if( cf->driver )
						start_service( &cf->modem, cf->driver, ctx->config, ctx, 0L );
				} else if( (cf->flags & UNICORN_RECONNECTING) && ((now - cf->pending_action_timeout) > cf->retry_time )) {
					x_printf(ctx,"Reconnect delay expired - attempting reconnect\n");
					cf->pending_action_timeout = rel_time(0L);
					cf->flags &= ~(unsigned int)UNICORN_RECONNECTING;
					if( cf->modem )
						send_unicorn_command(ctx, CMD_CONNECT, CMD_ST_ONLINE, 0, 0 );
				} else if( (cf->flags & UNICORN_WAITING_FOR_CONNECT) && ((now - cf->pending_action_timeout) > UNICORN_CONNECT_TIMEOUT )) {
					x_printf(ctx,"Timeout during connect - terminating modem driver\n");
					cf->flags &= ~(unsigned int) UNICORN_WAITING_FOR_CONNECT;
					cf->state = UNICORN_STATE_IDLE;
					if( cf->modem )
						emit( cf->modem, EVENT_TERMINATE, 0L );
				}

				if( (cf->flags & UNICORN_TERMINATING) && ((now - cf->pending_action_timeout) > UNICORN_PROCESS_TERMINATION_TIMEOUT)) {
					x_printf(ctx,"termination timeout - killing the modem driver with prejudice\n");
					cf->state = UNICORN_STATE_IDLE;
					if( cf->modem )
						context_terminate( cf->modem );
					context_terminate( ctx );
				}

				// Special case.. If I am expecting a data frame, and it takes too long to arrive,
				// reset state.
				if( (cf->flags & UNICORN_EXPECTING_DATA) && ((now - cf->last_message) > FRAME_TIMEOUT)) {
					x_printf(ctx,"FRAME TIMEOUT - resetting input buffer\n");
					u_ringbuf_init( &cf->input );
					cf->flags &= ~(unsigned int)UNICORN_EXPECTING_DATA;
				}

#ifndef NDEBUG
				size_t bytes = u_ringbuf_ready( &cf->input );
				if( bytes )
					x_printf(ctx,"Un-processed data in ring buffer... %d bytes\n",(int)bytes);
#endif
			}
			break;

		default:
			x_printf(ctx,"\n *\n *\n * Emitted some kind of event \"%s\" (%d)\n *\n *\n", event_map[event], event);
	}
	return 0;
}
Beispiel #10
0
ssize_t process_unicorn_header( context_t *ctx )
{
	unicorn_config_t *cf = ctx->data;

	switch( cf->msgHdr.cmd ) {
		case CMD_READY:
			// If the driver has JUST STARTED, then it bring the network online immediately, otherwise
			// the retry delay takes effect
			cf->flags |= UNICORN_FIRST_START;
			cf->driver_state = CMD_ST_UNKNOWN;
		case CMD_KEEPALIVE:
		case CMD_STATE:
			cf->flags &= ~(unsigned int)UNICORN_LAGGED;

			if( cf->msgHdr.state != cf->driver_state ) {

				if( cf->msgHdr.state == CMD_ST_ONLINE || cf->msgHdr.state == CMD_ST_OFFLINE || cf->msgHdr.state == CMD_ST_ERROR ) {
					x_printf(ctx,"Notifying parent that the network state has changed to %s\n",cf->msgHdr.state == CMD_ST_ONLINE ? "online":"offline");
					context_owner_notify( ctx, CHILD_EVENT, (child_status_t) (cf->msgHdr.state == CMD_ST_ONLINE ? UNICORN_MODE_ONLINE : UNICORN_MODE_OFFLINE) );
				}

				if( cf->flags & UNICORN_TERMINATING ) {
					x_printf(ctx,"State = TERMINATING, need to shutdown driver\n");
					if( cf->msgHdr.state == CMD_ST_OFFLINE )
						send_unicorn_command( ctx, CMD_SHUTDOWN, CMD_ST_OFFLINE, 0, 0L );
					else
						send_unicorn_command( ctx, CMD_DISCONNECT, CMD_ST_OFFLINE, 0, 0L );
				} else {
					switch( cf->msgHdr.state ) {
						case CMD_ST_ONLINE:
							x_printf(ctx,"State is Online - resetting WAITING_FOR_CONNECT/RECONNECTING status\n");
							cf->flags &= ~(unsigned int) (UNICORN_WAITING_FOR_CONNECT|UNICORN_RECONNECTING|UNICORN_FIRST_START);
							break;
						case CMD_ST_OFFLINE:
							x_printf(ctx,"Sending CONNECT command (Setting WAITING_FOR_CONNECT/RECONNECTING FLAG)\n");
							// RECONNECTING causes a CMD_CONNECT to be sent after the RETRY delay
							// WAITING_FOR_CONNECT causes the timeout handler to kill the modem driver if a
							// connect does not occur before a specified window of time has elapsed
							cf->pending_action_timeout = cf->last_message;
							// Special case, in a first start scenario, don't wait retry
							if( cf->flags & UNICORN_FIRST_START) {
								x_printf(ctx,"Forcing connection - FIRST_START is set\n");
								send_unicorn_command(ctx, CMD_CONNECT, CMD_ST_ONLINE, 0, 0 );
								cf->flags &= ~(unsigned int) (UNICORN_FIRST_START);
								cf->flags |= UNICORN_WAITING_FOR_CONNECT;
							} else {
								x_printf(ctx,"Setting up for delayed connection\n");
								cf->flags |= UNICORN_WAITING_FOR_CONNECT|UNICORN_RECONNECTING;
							}
							break;
						case CMD_ST_ERROR:
							break;
						default:
							break;
					}
				}
				cf->driver_state = cf->msgHdr.state;
			}
			break;
		case CMD_DATA:
			cf->flags |= UNICORN_EXPECTING_DATA;
			cf->data_length = cf->msgHdr.length;
			cf->last_message = rel_time(0L);
			break;
		default:
			x_printf(ctx,"Not ready to deal with cmd %d\n",cf->msgHdr.cmd);
			break;

	}

	return 0;
}
Beispiel #11
0
void logger::run()
{
    utxx::signal_block block_signals(m_block_signals);

    if (m_on_before_run)
        m_on_before_run();

    if (!m_ident.empty())
        pthread_setname_np(pthread_self(), m_ident.c_str());

    int event_val;
    do
    {
        event_val = m_event.value();
        //wakeup_result rc = wakeup_result::TIMEDOUT;

        while (!m_abort && m_queue.empty()) {
            m_event.wait(&m_wait_timeout, &event_val);

            ASYNC_DEBUG_TRACE(
                ("  %s LOGGER awakened (res=%s, val=%d, futex=%d), abort=%d, head=%s\n",
                 timestamp::to_string().c_str(), to_string(rc).c_str(),
                 event_val, m_event.value(), m_abort,
                 m_queue.empty() ? "empty" : "data")
            );
        }

        // When running with maximum priority, occasionally excessive use of
        // sched_yield may use to system slowdown, so this option is
        // configurable by m_sched_yield_us:
        if (m_queue.empty() && m_sched_yield_us >= 0) {
            time_val deadline(rel_time(0, m_sched_yield_us));
            while (m_queue.empty()) {
                if (m_abort)
                    goto DONE;
                if (now_utc() > deadline)
                    break;
                sched_yield();
            }
        }

        // Get all pending items from the queue
        for (auto* item = m_queue.pop_all(), *next=item; item; item = next) {
            next = item->next();

            try   {
                dolog_msg(item->data());
            }
            catch ( std::exception const& e  )
            {
                // Unhandled error writing data to some destination
                // Print error report to stderr (can't do anything better --
                // the error happened in the m_on_error callback!)
                const msg msg(LEVEL_INFO, "",
                              std::string("Fatal exception in logger"),
                              UTXX_LOG_SRCINFO);
                detail::basic_buffered_print<1024> buf;
                char  pfx[256], sfx[256];
                char* p = format_header(msg, pfx, pfx + sizeof(pfx));
                char* q = format_footer(msg, sfx, sfx + sizeof(sfx));
                auto ps = p - pfx;
                auto qs = q - sfx;
                buf.reserve(msg.m_fun.str.size() + ps + qs + 1);
                buf.sprint(pfx, ps);
                buf.print(msg.m_fun.str);
                buf.sprint(sfx, qs);
                std::cerr << buf.str() << std::endl;

                m_abort = true;

                // TODO: implement attempt to store transient messages to some
                // other medium

                // Free all pending messages
                while (item) {
                    m_queue.free(item);
                    item = next;
                    next = item->next();
                }

                goto DONE;
            }

            m_queue.free(item);
            item = next;
        }
    } while (!m_abort);

DONE:
    if (!m_silent_finish) {
        const msg msg(LEVEL_INFO, "", std::string("Logger thread finished"),
                      UTXX_LOG_SRCINFO);
        try {
            dolog_msg(msg);
        }
        catch (...) {}
    }

    if (m_on_after_run)
        m_on_after_run();
}