Beispiel #1
0
int event_init_platform(void) {
	int phase = 0;

	// create read set
	if (event_reserve_socket_set(&_socket_read_set, 32) < 0) {
		log_error("Could not create socket read set: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 1;

	// create write set
	if (event_reserve_socket_set(&_socket_write_set, 32) < 0) {
		log_error("Could not create socket write set: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 2;

	// create error set
	if (event_reserve_socket_set(&_socket_error_set, 32) < 0) {
		log_error("Could not create socket error set: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 3;

	// create stop pipe
	if (pipe_create(&_stop_pipe, 0) < 0) {
		log_error("Could not create stop pipe: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 4;

	if (event_add_source(_stop_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC,
	                     EVENT_READ, NULL, NULL) < 0) {
		goto cleanup;
	}

	phase = 5;

	// create USB poll thread
	_usb_poll_running = false;
	_usb_poll_stuck = false;

	if (usbi_pipe(_usb_poll_suspend_pipe) < 0) {
		log_error("Could not create USB suspend pipe");

		goto cleanup;
	}

	phase = 6;

	if (pipe_create(&_usb_poll_ready_pipe, 0) < 0) {
		log_error("Could not create USB ready pipe: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 7;

	if (array_create(&_usb_poll_pollfds, 32, sizeof(struct usbi_pollfd), true) < 0) {
		log_error("Could not create USB pollfd array: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 8;

	if (semaphore_create(&_usb_poll_resume) < 0) {
		log_error("Could not create USB resume semaphore: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 9;

	if (semaphore_create(&_usb_poll_suspend) < 0) {
		log_error("Could not create USB suspend semaphore: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 10;

cleanup:
	switch (phase) { // no breaks, all cases fall through intentionally
	case 9:
		semaphore_destroy(&_usb_poll_suspend);

	case 8:
		semaphore_destroy(&_usb_poll_resume);

	case 7:
		pipe_destroy(&_usb_poll_ready_pipe);

	case 6:
		usbi_close(_usb_poll_suspend_pipe[0]);
		usbi_close(_usb_poll_suspend_pipe[1]);

	case 5:
		event_remove_source(_stop_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC);

	case 4:
		pipe_destroy(&_stop_pipe);

	case 3:
		free(_socket_error_set);

	case 2:
		free(_socket_write_set);

	case 1:
		free(_socket_read_set);

	default:
		break;
	}

	return phase == 10 ? 0 : -1;
}
Beispiel #2
0
int event_run_platform(Array *event_sources, bool *running, EventCleanupFunction cleanup) {
	int result = -1;
	int i;
	EventSource *event_source;
	fd_set *fd_read_set;
	fd_set *fd_write_set;
	fd_set *fd_error_set;
	int ready;
	int handled;
	uint8_t byte = 1;
	int rc;
	int event_source_count;
	uint32_t received_events;

	if (event_add_source(_usb_poll_ready_pipe.read_end,
	                     EVENT_SOURCE_TYPE_GENERIC, EVENT_READ,
	                     event_forward_usb_events, event_sources) < 0) {
		return -1;
	}

	*running = true;
	_usb_poll_running = true;

	thread_create(&_usb_poll_thread, event_poll_usb_events, event_sources);

	cleanup();
	event_cleanup_sources();

	while (*running) {
		// update SocketSet arrays
		if (event_reserve_socket_set(&_socket_read_set, // FIXME: this over-allocates
		                             event_sources->count) < 0) {
			log_error("Could not resize socket read set: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		if (event_reserve_socket_set(&_socket_write_set, // FIXME: this over-allocates
		                             event_sources->count) < 0) {
			log_error("Could not resize socket write set: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		if (event_reserve_socket_set(&_socket_error_set, // FIXME: this over-allocates
		                             event_sources->count) < 0) {
			log_error("Could not resize socket error set: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		_socket_read_set->count = 0;
		_socket_write_set->count = 0;
		_socket_error_set->count = 0;

		for (i = 0; i < event_sources->count; ++i) {
			event_source = array_get(event_sources, i);

			if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) {
				continue;
			}

			if ((event_source->events & EVENT_READ) != 0) {
				_socket_read_set->sockets[_socket_read_set->count++] = event_source->handle;
			}

			if ((event_source->events & EVENT_WRITE) != 0) {
				_socket_write_set->sockets[_socket_write_set->count++] = event_source->handle;
			}

			if ((event_source->events & EVENT_PRIO) != 0) {
				log_error("Event prio is not supported");
			}

			if ((event_source->events & EVENT_ERROR) != 0) {
				_socket_error_set->sockets[_socket_error_set->count++] = event_source->handle;
			}
		}

		// start to select
		log_event_debug("Starting to select on %d + %d + %d %s event source(s)",
		                _socket_read_set->count, _socket_write_set->count, _socket_error_set->count,
		                event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false));

		semaphore_release(&_usb_poll_resume);

		fd_read_set = event_get_socket_set_as_fd_set(_socket_read_set);
		fd_write_set = event_get_socket_set_as_fd_set(_socket_write_set);
		fd_error_set = event_get_socket_set_as_fd_set(_socket_error_set);

		ready = select(0, fd_read_set, fd_write_set, fd_error_set, NULL);

		if (_usb_poll_running) {
			log_event_debug("Sending suspend signal to USB poll thread");

			if (usbi_write(_usb_poll_suspend_pipe[1], &byte, 1) < 0) {
				log_error("Could not write to USB suspend pipe");

				_usb_poll_stuck = true;

				goto cleanup;
			}

			semaphore_acquire(&_usb_poll_suspend);

			if (usbi_read(_usb_poll_suspend_pipe[0], &byte, 1) < 0) {
				log_error("Could not read from USB suspend pipe");

				_usb_poll_stuck = true;

				goto cleanup;
			}
		}

		if (ready == SOCKET_ERROR) {
			rc = ERRNO_WINAPI_OFFSET + WSAGetLastError();

			if (rc == ERRNO_WINAPI_OFFSET + WSAEINTR) {
				continue;
			}

			log_error("Could not select on %s event sources: %s (%d)",
			          event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false),
			          get_errno_name(rc), rc);

			goto cleanup;
		}

		// handle select result
		log_event_debug("Select returned %d %s event source(s) as ready",
		                ready, event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false));

		handled = 0;

		// cache event source count here to avoid looking at new event
		// sources that got added during the event handling
		event_source_count = event_sources->count;

		for (i = 0; *running && i < event_source_count && ready > handled; ++i) {
			event_source = array_get(event_sources, i);
			received_events = 0;

			if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) {
				continue;
			}

			if (FD_ISSET(event_source->handle, fd_read_set)) {
				received_events |= EVENT_READ;
			}

			if (FD_ISSET(event_source->handle, fd_write_set)) {
				received_events |= EVENT_WRITE;
			}

			if (FD_ISSET(event_source->handle, fd_error_set)) {
				received_events |= EVENT_ERROR;
			}

			if (received_events == 0) {
				continue;
			}

			event_handle_source(event_source, received_events);

			++handled;
		}

		if (ready == handled) {
			log_event_debug("Handled all ready %s event sources",
			                event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false));
		} else if (*running) {
			log_warn("Handled only %d of %d ready %s event source(s)",
			         handled, ready,
			         event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, false));
		}

		// now cleanup event sources that got marked as disconnected/removed
		// during the event handling
		cleanup();
		event_cleanup_sources();
	}

	result = 0;

cleanup:
	*running = false;

	if (_usb_poll_running && !_usb_poll_stuck) {
		_usb_poll_running = false;

		log_debug("Stopping USB poll thread");

		if (usbi_write(_usb_poll_suspend_pipe[1], &byte, 1) < 0) {
			log_error("Could not write to USB suspend pipe");
		} else {
			semaphore_release(&_usb_poll_resume);
			thread_join(&_usb_poll_thread);
		}
	}

	thread_destroy(&_usb_poll_thread);

	event_remove_source(_usb_poll_ready_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC);

	return result;
}
Beispiel #3
0
int event_run_platform(Array *event_sources, int *running) {
	int result = -1;
	int i;
	EventSource *event_source;
	fd_set *fd_read_set;
	fd_set *fd_write_set;
	int ready;
	int handled;
	uint8_t byte = 1;
	int rc;
	int event_source_count;
	int received_events;

	if (event_add_source(_usb_poller.ready_pipe[0], EVENT_SOURCE_TYPE_GENERIC,
	                     EVENT_READ, event_forward_usb_events,
	                     event_sources) < 0) {
		return -1;
	}

	*running = 1;

	_usb_poller.running = 1;

	thread_create(&_usb_poller.thread, event_poll_usb_events, event_sources);

	event_cleanup_sources();

	while (*running) {
		// update SocketSet arrays
		if (event_reserve_socket_set(&_socket_read_set, // FIXME: this over allocates
		                             event_sources->count) < 0) {
			log_error("Could not resize socket read set: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		if (event_reserve_socket_set(&_socket_write_set, // FIXME: this over allocates
		                             event_sources->count) < 0) {
			log_error("Could not resize socket write set: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		_socket_read_set->count = 0;
		_socket_write_set->count = 0;

		for (i = 0; i < event_sources->count; i++) {
			event_source = array_get(event_sources, i);

			if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) {
				continue;
			}

			if (event_source->events & EVENT_READ) {
				_socket_read_set->sockets[_socket_read_set->count++] = event_source->handle;
			}

			if (event_source->events & EVENT_WRITE) {
				_socket_write_set->sockets[_socket_write_set->count++] = event_source->handle;
			}
		}

		// start to select
		log_debug("Starting to select on %d + %d %s event source(s)",
		          _socket_read_set->count, _socket_write_set->count,
		          event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0));

		semaphore_release(&_usb_poller.resume);

		fd_read_set = event_get_socket_set_as_fd_set(_socket_read_set);
		fd_write_set = event_get_socket_set_as_fd_set(_socket_write_set);

		ready = select(0, fd_read_set, fd_write_set, NULL, NULL);

		if (_usb_poller.running) {
			log_debug("Sending suspend signal to USB poll thread");

			if (usbi_write(_usb_poller.suspend_pipe[1], &byte, 1) < 0) {
				log_error("Could not write to USB suspend pipe");

				_usb_poller.stuck = 1;
				*running = 0;

				goto cleanup;
			}

			semaphore_acquire(&_usb_poller.suspend);

			if (usbi_read(_usb_poller.suspend_pipe[0], &byte, 1) < 0) {
				log_error("Could not read from USB suspend pipe");

				_usb_poller.stuck = 1;
				*running = 0;

				goto cleanup;
			}
		}

		if (ready < 0) {
			rc = ERRNO_WINAPI_OFFSET + WSAGetLastError();

			if (rc == ERRNO_WINAPI_OFFSET + WSAEINTR) {
				continue;
			}

			log_error("Could not select on %s event sources: %s (%d)",
			          event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0),
			          get_errno_name(rc), rc);

			*running = 0;

			goto cleanup;
		}

		// handle select result
		log_debug("Select returned %d %s event source(s) as ready",
		          ready,
		          event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0));

		handled = 0;

		// cache event source count here to avoid looking at new event
		// sources that got added during the event handling
		event_source_count = event_sources->count;

		for (i = 0; i < event_source_count && ready > handled; ++i) {
			event_source = array_get(event_sources, i);
			received_events = 0;

			if (event_source->type != EVENT_SOURCE_TYPE_GENERIC) {
				continue;
			}

			if (FD_ISSET(event_source->handle, fd_read_set)) {
				received_events |= EVENT_READ;
			}

			if (FD_ISSET(event_source->handle, fd_write_set)) {
				received_events |= EVENT_WRITE;
			}

			if (received_events == 0) {
				continue;
			}

			if (event_source->state != EVENT_SOURCE_STATE_NORMAL) {
				log_debug("Ignoring %s event source (handle: %d, received events: %d) marked as removed at index %d",
				          event_get_source_type_name(event_source->type, 0),
				          event_source->handle, received_events, i);
			} else {
				log_debug("Handling %s event source (handle: %d, received events: %d) at index %d",
				          event_get_source_type_name(event_source->type, 0),
				          event_source->handle, received_events, i);

				if (event_source->function != NULL) {
					event_source->function(event_source->opaque);
				}
			}

			++handled;

			if (!*running) {
				break;
			}
		}

		if (ready == handled) {
			log_debug("Handled all ready %s event sources",
			          event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0));
		} else {
			log_warn("Handled only %d of %d ready %s event source(s)",
			         handled, ready,
			         event_get_source_type_name(EVENT_SOURCE_TYPE_GENERIC, 0));
		}

		// now remove event sources that got marked as removed during the
		// event handling
		event_cleanup_sources();
	}

	result = 0;

cleanup:
	if (_usb_poller.running && !_usb_poller.stuck) {
		_usb_poller.running = 0;

		log_debug("Stopping USB poll thread");

		if (usbi_write(_usb_poller.suspend_pipe[1], &byte, 1) < 0) {
			log_error("Could not write to USB suspend pipe");
		} else {
			semaphore_release(&_usb_poller.resume);
			thread_join(&_usb_poller.thread);
		}
	}

	event_remove_source(_usb_poller.ready_pipe[0], EVENT_SOURCE_TYPE_GENERIC);

	return result;
}