Ejemplo n.º 1
0
void pipe_initialize( stream_pipe_t* pipestream )
{
	stream_t* stream = (stream_t*)pipestream;

	memset( stream, 0, sizeof( stream_pipe_t ) );

	stream_initialize( stream, system_byteorder() );

	pipestream->type = STREAMTYPE_PIPE;
	pipestream->path = string_format( "pipe://0x" PRIfixPTR, pipestream );
	pipestream->mode = STREAM_OUT | STREAM_IN | STREAM_BINARY;
	pipestream->sequential = true;

#if FOUNDATION_PLATFORM_WINDOWS
	{
		//Inheritable by default so process can use for stdstreams
		SECURITY_ATTRIBUTES security_attribs = {0};
		security_attribs.nLength = sizeof( SECURITY_ATTRIBUTES );
		security_attribs.bInheritHandle = TRUE;
		security_attribs.lpSecurityDescriptor = 0;

		if( !CreatePipe( &pipestream->handle_read, &pipestream->handle_write, &security_attribs, 0 ) )
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create unnamed pipe: %s", system_error_message( GetLastError() ) );
	}
#elif FOUNDATION_PLATFORM_POSIX || FOUNDATION_PLATFORM_PNACL
	int fds[2] = { 0, 0 };
	if( pipe( fds ) < 0 )
		log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create unnamed pipe: %s", system_error_message( 0 ) );
	pipestream->fd_read = fds[0];
	pipestream->fd_write = fds[1];
#endif

	pipestream->vtable = &_pipe_stream_vtable;
}
Ejemplo n.º 2
0
bool _initialize_stackwalker()
{
	if( _stackwalk_initialized )
		return true;
		
#if FOUNDATION_PLATFORM_WINDOWS
	{
		void* dll = LoadLibraryA( "DBGHELP.DLL" );
		CallStackWalk64 = dll ? (StackWalk64Fn)GetProcAddress( dll, "StackWalk64" ) : 0;
		if( !CallStackWalk64 )
		{
			log_warnf( WARNING_SYSTEM_CALL_FAIL, "Unable to load dbghelp DLL for StackWalk64" );
			return false;
		}

		dll = LoadLibraryA( "NTDLL.DLL" );
		CallRtlCaptureStackBackTrace = dll ? (RtlCaptureStackBackTraceFn)GetProcAddress( dll, "RtlCaptureStackBackTrace" ) : 0;
		if( !CallRtlCaptureStackBackTrace )
		{
			log_warnf( WARNING_SYSTEM_CALL_FAIL, "Unable to load ntdll DLL for RtlCaptureStackBackTrace" );
			return false;
		}
	}
#endif

	_stackwalk_initialized = true;
	return true;
}
Ejemplo n.º 3
0
int
blast_client(network_address_t** * target, string_t* files) {
	int itarg, tsize = 0;
	int iclient, csize = 0;
	int ifile, fsize = 0;
	bool running = true;
	int result = BLAST_RESULT_OK;
	blast_reader_t* reader = 0;
	blast_reader_t** readers = 0;

	for (ifile = 0, fsize = array_size(files); ifile < fsize; ++ifile) {
		reader = blast_reader_open(files[ifile]);
		if (!reader) {
			log_warnf(HASH_BLAST, WARNING_SUSPICIOUS, STRING_CONST("Unable to open reader for: %.*s"),
			          STRING_ARGS(files[ifile]));
			return BLAST_ERROR_UNABLE_TO_OPEN_FILE;
		}

		array_push(readers, reader);
	}

	if (array_size(readers) == 0) {
		log_warnf(HASH_BLAST, WARNING_INVALID_VALUE, STRING_CONST("No input files given"));
		return BLAST_ERROR_UNABLE_TO_OPEN_FILE;
	}

	for (itarg = 0, tsize = array_size(target); itarg < tsize; ++itarg) {
		blast_client_t client;
		if (blast_client_initialize(&client, target[itarg]) == BLAST_RESULT_OK) {
			client.readers = readers;
			array_push(clients, client);
		}
	}

	while (running && !blast_should_exit()) {
		running = false;

		for (iclient = 0, csize = array_size(clients); iclient < csize; ++iclient)
			running |= blast_client_process(clients + iclient);

		blast_process_system_events();
	}

	for (iclient = 0, csize = array_size(clients); iclient < csize; ++iclient)
		blast_client_deallocate(&clients[iclient]);
	array_deallocate(clients);

	for (ifile = 0, fsize = array_size(readers); ifile < fsize; ++ifile)
		blast_reader_close(readers[ifile]);
	array_deallocate(readers);

	return result;
}
Ejemplo n.º 4
0
int bin2hex_process_files( char const* const* input, char const* const* output, int columns )
{
    int result = BIN2HEX_RESULT_OK;
    unsigned int ifile, files_size;
    for( ifile = 0, files_size = array_size( input ); ( result == BIN2HEX_RESULT_OK ) && ( ifile < files_size ); ++ifile )
    {
        char* input_filename = 0;
        char* output_filename = 0;

        stream_t* input_file = 0;
        stream_t* output_file = 0;

        input_filename = path_clean( string_clone( input[ifile] ), path_is_absolute( input[ifile] ) );
        error_context_push( "parsing file", input_filename );

        output_filename = path_clean( string_clone( output[ifile] ), path_is_absolute( output[ifile] ) );

        log_infof( 0, "bin2hex %s -> %s", input_filename, output_filename );

        input_file = stream_open( input_filename, STREAM_IN | STREAM_BINARY );

        if( !input_file )
        {
            log_warnf( 0, WARNING_BAD_DATA, "Unable to open input file: %s", input_filename );
            result = BIN2HEX_RESULT_MISSING_INPUT_FILE;
        }
        else
        {
            output_file = stream_open( output_filename, STREAM_OUT );
            if( !output_file )
            {
                log_warnf( 0, WARNING_BAD_DATA, "Unable to open output file: %s", output_filename );
                result = BIN2HEX_RESULT_UNABLE_TO_OPEN_OUTPUT_FILE;
            }
        }

        if( input_file && output_file )
            result = bin2hex_process_file( input_file, output_file, columns );

        stream_deallocate( input_file );
        stream_deallocate( output_file );

        string_deallocate( output_filename );

        error_context_pop();
        string_deallocate( input_filename );
    }

    if( ( result == BIN2HEX_RESULT_OK ) && ( files_size > 0 ) )
        log_info( 0, "All files generated" );

    return result;
}
Ejemplo n.º 5
0
static void
_memory_deallocate_malloc(void* p) {
#if FOUNDATION_SIZE_POINTER == 4
	if (!p)
		return;
#  if BUILD_ENABLE_MEMORY_GUARD
	p = _memory_guard_verify(p);
#  endif
#  if FOUNDATION_PLATFORM_WINDOWS
	_aligned_free(p);
#  else
	free(*((void**)p - 1));
#  endif

#else

	uintptr_t raw_ptr;

	if (!p)
		return;

#  if BUILD_ENABLE_MEMORY_GUARD
	p = _memory_guard_verify(p);
#  endif
	raw_ptr = *((uintptr_t*)p - 1);
	if (raw_ptr & 1) {
		raw_ptr &= ~(uintptr_t)1;
#  if FOUNDATION_PLATFORM_WINDOWS
		if (VirtualFree((void*)raw_ptr, 0, MEM_RELEASE) == 0)
			log_warnf(HASH_MEMORY, WARNING_SYSTEM_CALL_FAIL,
				STRING_CONST("Failed to VirtualFree 0x%" PRIfixPTR),
				(uintptr_t)raw_ptr);
#  else
		uintptr_t raw_size = *((uintptr_t*)p - 2);
		if (munmap((void*)raw_ptr, raw_size) < 0)
			log_warnf(HASH_MEMORY, WARNING_SYSTEM_CALL_FAIL,
			          STRING_CONST("Failed to munmap 0x%" PRIfixPTR " size %" PRIsize),
			          (uintptr_t)raw_ptr, raw_size);
#  endif
	}
	else {
#  if FOUNDATION_PLATFORM_WINDOWS
		_aligned_free((void*)raw_ptr);
#  else
		free((void*)raw_ptr);
#  endif
	}

#endif
}
Ejemplo n.º 6
0
int
main_run(void* main_arg) {
	int result = RENDERCOMPILE_RESULT_OK;
	rendercompile_input_t input = rendercompile_parse_command_line(environment_command_line());

	FOUNDATION_UNUSED(main_arg);

	if (input.display_help) {
		rendercompile_print_usage();
		goto exit;
	}

	resource_source_set_path(STRING_ARGS(input.source_path));
	resource_compile_register(render_compile);

	size_t ifile, fsize;
	for (ifile = 0, fsize = array_size(input.input_files); ifile < fsize; ++ifile) {
		uuid_t uuid = string_to_uuid(STRING_ARGS(input.input_files[ifile]));
		if (uuid_is_null(uuid)) {
			char buffer[BUILD_MAX_PATHLEN];
			string_t pathstr = string_copy(buffer, sizeof(buffer), STRING_ARGS(input.input_files[ifile]));
			pathstr = path_clean(STRING_ARGS(pathstr), sizeof(buffer));
			pathstr = path_absolute(STRING_ARGS(pathstr), sizeof(buffer));
			uuid = resource_import_map_lookup(STRING_ARGS(pathstr));
		}
		if (uuid_is_null(uuid)) {
			log_warnf(HASH_RESOURCE, WARNING_INVALID_VALUE, STRING_CONST("Failed to lookup: %.*s"), STRING_FORMAT(input.input_files[ifile]));
			result = RENDERCOMPILE_RESULT_INVALID_INPUT;
			break;
		}

		if (resource_compile(uuid, RESOURCE_PLATFORM_ALL)) {
			string_const_t uuidstr = string_from_uuid_static(uuid);
			log_infof(HASH_RESOURCE, STRING_CONST("Successfully compiled: %.*s (%.*s)"),
			          STRING_FORMAT(uuidstr), STRING_FORMAT(input.input_files[ifile]));
		}
		else {
			string_const_t uuidstr = string_from_uuid_static(uuid);
			log_warnf(HASH_RESOURCE, WARNING_UNSUPPORTED, STRING_CONST("Failed to compile: %.*s (%.*s)"),
			          STRING_FORMAT(uuidstr), STRING_FORMAT(input.input_files[ifile]));
		}
	}

exit:

	array_deallocate(input.input_files);

	return result;
}
Ejemplo n.º 7
0
static lua_module_t
lua_module_load_resource(const uuid_t uuid) {
	lua_module_t module = {0, 0};
	bool success = false;
	const uint32_t expected_version = 1;
	uint64_t platform = 0;
	stream_t* stream;

	stream = resource_stream_open_static(uuid, platform);
	if (stream) {
		resource_header_t header = resource_stream_read_header(stream);
		if ((header.type == HASH_LUA) && (header.version == expected_version)) {
			success = true;
		}
		else {
			log_warnf(HASH_LUA, WARNING_INVALID_VALUE,
			          STRING_CONST("Got unexpected type/version when loading Lua module: %" PRIx64 " : %u"),
			          header.type, header.version);
		}
		stream_deallocate(stream);
		stream = nullptr;
	}
	if (success)
		stream = resource_stream_open_dynamic(uuid, platform);
	if (stream) {
		uint32_t version = stream_read_uint32(stream);
		size_t size = (size_t)stream_read_uint64(stream);
		if (version == expected_version) {
			void* buffer = memory_allocate(HASH_LUA, size, 0, MEMORY_TEMPORARY);
			if (stream_read(stream, buffer, size) == size) {
				module.bytecode = buffer;
				module.size = size;
			}
			else {
				memory_deallocate(buffer);
			}
		}
		else {
			log_warnf(HASH_LUA, WARNING_INVALID_VALUE,
			          STRING_CONST("Got unexpected type/version when loading Lua module blob: %u"),
			          version);
		}
		stream_deallocate(stream);
		stream = nullptr;
	}

	return module;
}
Ejemplo n.º 8
0
void mutex_signal( mutex_t* mutex )
{
	FOUNDATION_ASSERT( mutex );

#if !BUILD_DEPLOY
	profile_signal( mutex->name );
#endif

#if FOUNDATION_PLATFORM_WINDOWS

	SetEvent( mutex->event );

#elif FOUNDATION_PLATFORM_POSIX

	mutex_lock( mutex );
	mutex->pending = true;

	int ret = pthread_cond_broadcast( &mutex->cond );
	if( ret != 0 )
		log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to signal mutex '%s': %s (%d)", mutex->name, system_error_message( ret ), ret );

	mutex_unlock( mutex );

#else
#  error mutex_signal not implemented
#endif
}
Ejemplo n.º 9
0
static int
_x11_error_handler(Display* display, XErrorEvent* event) {
	char errmsg[512];
	XGetErrorText(display, event->error_code, errmsg, sizeof(errmsg));
	log_warnf(HASH_WINDOW, WARNING_SYSTEM_CALL_FAIL, STRING_CONST("X error event occurred: %s"), errmsg);
	return 0;
}
Ejemplo n.º 10
0
bool
mutex_unlock(mutex_t* mutex) {
	if (!mutex->lockcount) {
		log_warnf(0, WARNING_SUSPICIOUS, STRING_CONST("Unable to unlock unlocked mutex %.*s"),
		          (int)mutex->name.length, mutex->name.str);
		return false;
	}

	FOUNDATION_ASSERT(mutex->lockedthread == thread_id());
	--mutex->lockcount;

#if !BUILD_DEPLOY
	profile_unlock(mutex->name.str, mutex->name.length);
#endif

#if FOUNDATION_PLATFORM_WINDOWS
	LeaveCriticalSection((CRITICAL_SECTION*)mutex->csection);
#elif FOUNDATION_PLATFORM_POSIX || FOUNDATION_PLATFORM_PNACL
	if (pthread_mutex_unlock(&mutex->mutex) != 0) {
		FOUNDATION_ASSERT_FAILFORMAT("unable to unlock mutex %s", mutex->name.str);
		return false;
	}
#else
#  error mutex_unlock not implemented
#endif
	return true;
}
Ejemplo n.º 11
0
static void _memory_tracker_shutdown( void )
{
	if( _memory_table )
		hashtable_deallocate( _memory_table );
	if( _memory_tags )
	{
		bool got_leaks = false;

		log_debug( "Checking for memory leaks" );
		for( unsigned int it = 0; it < MAX_CONCURRENT_ALLOCATIONS; ++it )
		{
			memory_tag_t* tag = _memory_tags + it;
			if( tag->address )
			{
				char* trace = stacktrace_resolve( tag->trace, 14, 0 );
				log_warnf( WARNING_MEMORY, "Memory leak: %d bytes @ " STRING_FORMAT_POINTER " : tag %d\n%s", (unsigned int)tag->size, tag->address, it, trace );
				string_deallocate( trace );
				got_leaks = true;
			}
		}
		memory_deallocate( _memory_tags );

		if( !got_leaks )
			log_debug( "No memory leaks detected" );
	}
}
Ejemplo n.º 12
0
static void
blast_client_read_ack(blast_client_t* client) {
	const network_address_t* address = 0;
	char databuf[PACKET_DATABUF_SIZE];
	size_t size = udp_socket_recvfrom(client->sock, databuf, sizeof(databuf), &address);
	while (size > 0) {
		packet_t* packet = (packet_t*)databuf;
		if (network_address_equal(address, socket_address_remote(client->sock))) {
			if (packet->type == PACKET_ACK) {
				packet_ack_t* ack = (packet_ack_t*)packet;
				blast_client_process_ack(client, ack->ack, packet->timestamp);
			}
			else if (packet->type == PACKET_TERMINATE) {
				log_info(HASH_BLAST, STRING_CONST("Client terminating due to TERMINATE packet from server"));
				client->state = BLAST_STATE_FINISHED;
				break;
			}
		}
		else {
			char buffer[NETWORK_ADDRESS_NUMERIC_MAX_LENGTH];
			string_t addr = network_address_to_string(buffer, sizeof(buffer), address, true);
			log_warnf(HASH_BLAST, WARNING_SUSPICIOUS, STRING_CONST("Ignoring datagram from unknown host %.*s"),
			          STRING_FORMAT(addr));
		}

		size = udp_socket_recvfrom(client->sock, databuf, sizeof(databuf), &address);
	}
}
Ejemplo n.º 13
0
int
hashify_write_file(stream_t* generated_file, string_t output_filename) {
	bool need_update = false;
	stream_t* output_file = 0;
	int result = HASHIFY_RESULT_OK;

	output_file = stream_open(STRING_ARGS(output_filename), STREAM_OUT | STREAM_IN);
	if (!output_file) {
		need_update = true;
		output_file = stream_open(STRING_ARGS(output_filename), STREAM_OUT);
		if (!output_file) {
			log_warnf(0, WARNING_INVALID_VALUE, STRING_CONST("Unable to open output file: %.*s"),
			          STRING_FORMAT(output_filename));
			return HASHIFY_RESULT_MISSING_OUTPUT_FILE;
		}
	}

	if (!need_update)
		need_update = !uint128_equal(stream_md5(generated_file), stream_md5(output_file));

	if (need_update) {
		char local_buffer[1024];
		size_t read = 0;
		size_t written = 0;
		uint64_t total_written = 0;

		stream_seek(generated_file, 0, STREAM_SEEK_BEGIN);
		stream_seek(output_file, 0, STREAM_SEEK_BEGIN);

		while (!stream_eos(generated_file)) {
			read = stream_read(generated_file, local_buffer, 1024);
			if (!read)
				break;

			written = stream_write(output_file, local_buffer, read);
			total_written += written;

			if (written != read) {
				log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
				           STRING_CONST("Unable to write to output file '%.*s': %" PRIsize " of %" PRIsize " bytes written"),
				           STRING_FORMAT(output_filename), written, read);
				result = HASHIFY_RESULT_OUTPUT_FILE_WRITE_FAIL;
				break;
			}
		}

		if (result == HASHIFY_RESULT_OK) {
			stream_truncate(output_file, (size_t)total_written);
			log_infof(0, STRING_CONST("  wrote %.*s : %" PRIu64 " bytes"), STRING_FORMAT(output_filename),
			          total_written);
		}
	}
	else {
		log_info(0, STRING_CONST("  hash file already up to date"));
	}

	stream_deallocate(output_file);

	return result;
}
Ejemplo n.º 14
0
void _profile_thread_finalize( void )
{
#if BUILD_ENABLE_PROFILE
	uint32_t block_index, last_block = 0;
	while( ( block_index = get_thread_profile_block() ) )
	{
		log_warnf( 0, WARNING_SUSPICIOUS, "Profile thread cleanup, free block %u", block_index );
		if( last_block == block_index )
		{
			log_warnf( 0, WARNING_SUSPICIOUS, "Unrecoverable error, self reference in block %u", block_index );
			break;
		}
		profile_end_block();
	}
#endif
}
Ejemplo n.º 15
0
static size_t
_socket_stream_write(stream_t* stream, const void* buffer, size_t size) {
	socket_stream_t* sockstream;
	socket_t* sock;
	size_t was_written = 0;
	size_t remain;

	sockstream = (socket_stream_t*)stream;
	sock = sockstream->socket;
	
	if ((sock->fd == NETWORK_SOCKET_INVALID) ||
	    (sock->state != SOCKETSTATE_CONNECTED) ||
	    !size || !buffer)
		goto exit;

	remain = sockstream->buffer_out_size - sockstream->write_out;

	do {
		if (size <= remain) {
			memcpy(sockstream->buffer_out + sockstream->write_out, buffer, (size_t)size);

			sockstream->write_out += (unsigned int)size;
			was_written += size;
			size = 0;

			break;
		}

		if (remain) {
			memcpy(sockstream->buffer_out + sockstream->write_out, buffer, remain);
			buffer = pointer_offset_const(buffer, remain);

			size -= remain;
			was_written += remain;
			sockstream->write_out += remain;
		}

		_socket_stream_doflush(sockstream);

		if (sock->state != SOCKETSTATE_CONNECTED) {
			log_warnf(HASH_NETWORK, WARNING_SUSPICIOUS,
			          STRING_CONST("Socket stream (0x%" PRIfixPTR " : %d): partial write %" PRIsize " of %" PRIsize " bytes"),
			          (uintptr_t)sock, sock->fd, was_written, size);
			break;
		}

		remain = sockstream->buffer_out_size - sockstream->write_out;

	}
	while (remain);

exit:

	return was_written;
}
Ejemplo n.º 16
0
void environment_set_current_working_directory( const char* path )
{
	if( !path )
		return;
	log_debugf( "Setting current working directory to: %s", path );
#if FOUNDATION_PLATFORM_WINDOWS
	{
		wchar_t* wpath = wstring_allocate_from_string( path, 0 );
		if( !SetCurrentDirectoryW( wpath ) )
			log_warnf( WARNING_SUSPICIOUS, "Unable to set working directory: %ls", wpath );
		wstring_deallocate( wpath );
	}
#elif FOUNDATION_PLATFORM_POSIX
	if( chdir( path ) < 0 )
		log_warnf( WARNING_SYSTEM_CALL_FAIL, "Unable to set working directory: %s", path );
#else
#  error Not implemented
#endif
	_environment_current_working_dir[0] = 0;
}
Ejemplo n.º 17
0
stream_t* pipe_allocate( void )
{
	stream_pipe_t* pipestream = memory_allocate_zero_context( MEMORYCONTEXT_STREAM, sizeof( stream_pipe_t ), 0, MEMORY_PERSISTENT );
	stream_t* stream = (stream_t*)pipestream;

	_stream_initialize( stream, system_byteorder() );

	pipestream->type = STREAMTYPE_PIPE;
	pipestream->path = string_format( "pipe://" STRING_FORMAT_POINTER, pipestream );
	pipestream->mode = STREAM_OUT | STREAM_IN | STREAM_BINARY;
	pipestream->sequential = true;

#if FOUNDATION_PLATFORM_WINDOWS
	{
		//Inheritable by default so process can use for stdstreams
		SECURITY_ATTRIBUTES security_attribs = {0};
		security_attribs.nLength = sizeof( SECURITY_ATTRIBUTES ); 
		security_attribs.bInheritHandle = TRUE; 
		security_attribs.lpSecurityDescriptor = 0;

		if( !CreatePipe( &pipestream->handle_read, &pipestream->handle_write, &security_attribs, 0 ) )
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create unnamed pipe: %s", system_error_message( GetLastError() ) );
	}
#elif FOUNDATION_PLATFORM_POSIX
	int fds[2] = { 0, 0 };
	if( pipe( fds ) < 0 )
		log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create unnamed pipe: %s", system_error_message( 0 ) );
	else
	{
		pipestream->fd_read = fds[0];
		pipestream->fd_write = fds[1];
	}
#endif

	pipestream->vtable = &_pipe_stream_vtable;

	return stream;
}
Ejemplo n.º 18
0
static uint64_t _pipe_stream_read( stream_t* stream, void* dest, uint64_t num )
{
	stream_pipe_t* pipestream = (stream_pipe_t*)stream;
	FOUNDATION_ASSERT( stream->type == STREAMTYPE_PIPE );
#if FOUNDATION_PLATFORM_WINDOWS
	if( pipestream->handle_read && ( ( pipestream->mode & STREAM_IN ) != 0 ) )
	{
		uint64_t total_read = 0;
		do
		{
			unsigned long num_read = 0;
			if( !ReadFile( pipestream->handle_read, pointer_offset( dest, total_read ), (unsigned int)( num - total_read ), &num_read, 0 ) )
			{
				int err = GetLastError();
				if( err == ERROR_BROKEN_PIPE )
				{
					pipestream->eos = true;
					break;
				}
				log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to read from pipe: %s (%d)", system_error_message( err ), err );
			}
			else
			{
				total_read += num_read;
			}
		} while( total_read < num );
		return total_read;
	}
#elif FOUNDATION_PLATFORM_POSIX || FOUNDATION_PLATFORM_PNACL
	if( pipestream->fd_read && ( ( pipestream->mode & STREAM_IN ) != 0 ) )
	{
		uint64_t total_read = 0;
		do
		{
			ssize_t num_read = read( pipestream->fd_read, pointer_offset( dest, total_read ), (size_t)( num - total_read ) );
			if( num_read <= 0 )
			{
				pipestream->eos = true;
				break;
			}
			total_read += num_read;
		} while( total_read < num );
		return total_read;
	}
#endif

	return 0;
}
Ejemplo n.º 19
0
void*
_allocate_thread_local_block(size_t size) {
	void* block = memory_allocate(0, size, 0, MEMORY_PERSISTENT | MEMORY_ZERO_INITIALIZED);

	for (int i = 0; i < 1024; ++i) {
		if (!atomic_loadptr(&_thread_local_blocks[i].block)) {
			if (atomic_cas_ptr(&_thread_local_blocks[i].block, block, 0)) {
				_thread_local_blocks[i].thread = thread_id();
				return block;
			}
		}
	}

	log_warnf(0, WARNING_MEMORY,
	          STRING_CONST("Unable to locate thread local memory block slot, will leak %" PRIsize " bytes"),
	          size);
	return block;
}
Ejemplo n.º 20
0
int main_run( void* main_arg )
{
#if !BUILD_MONOLITHIC
	const char* pattern = 0;
	char** exe_paths = 0;
	unsigned int iexe, exesize;
	process_t* process = 0;
	char* process_path = 0;
	unsigned int* exe_flags = 0;
#endif
#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL
	int remain_counter = 0;
#endif
#if BUILD_DEBUG
	const char* build_name = "debug";
#elif BUILD_RELEASE
	const char* build_name = "release";
#elif BUILD_PROFILE
	const char* build_name = "profile";
#elif BUILD_DEPLOY
	const char* build_name = "deploy";
#endif
	int process_result = 0;
	object_t thread = 0;
	FOUNDATION_UNUSED( main_arg );
	FOUNDATION_UNUSED( build_name );

	log_set_suppress( HASH_TEST, ERRORLEVEL_DEBUG );

	log_infof( HASH_TEST, "Foundation library v%s built for %s using %s (%s)", string_from_version_static( foundation_version() ), FOUNDATION_PLATFORM_DESCRIPTION, FOUNDATION_COMPILER_DESCRIPTION, build_name );

	thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 );
	thread_start( thread, 0 );
	while( !thread_is_running( thread ) )
		thread_sleep( 10 );

#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID
	while( !_test_should_start )
	{
#if FOUNDATION_PLATFORM_ANDROID
		system_process_events();
#endif
		thread_sleep( 100 );
	}
#endif

	fs_remove_directory( environment_temporary_directory() );

#if BUILD_MONOLITHIC

	test_run_fn tests[] = {
		test_app_run,
		test_array_run,
		test_atomic_run,
		test_base64_run,
		test_bitbuffer_run,
		test_blowfish_run,
		test_bufferstream_run,
		test_config_run,
		test_crash_run,
		test_environment_run,
		test_error_run,
		test_event_run,
		test_fs_run,
		test_hash_run,
		test_hashmap_run,
		test_hashtable_run,
		test_library_run,
		test_math_run,
		test_md5_run,
		test_mutex_run,
		test_objectmap_run,
		test_path_run,
		test_pipe_run,
		test_process_run,
		test_profile_run,
		test_radixsort_run,
		test_random_run,
		test_regex_run,
		test_ringbuffer_run,
		test_semaphore_run,
		test_stacktrace_run,
		test_stream_run, //stream test closes stdin
		test_string_run,
		test_system_run,
		test_time_run,
		test_uuid_run,
		0
	};

#if FOUNDATION_PLATFORM_ANDROID

	object_t test_thread = thread_create( test_runner, "test_runner", THREAD_PRIORITY_NORMAL, 0 );
	thread_start( test_thread, tests );

	log_debug( HASH_TEST, "Starting test runner thread" );

	while( !thread_is_running( test_thread ) )
	{
		system_process_events();
		thread_sleep( 10 );
	}

	while( thread_is_running( test_thread ) )
	{
		system_process_events();
		thread_sleep( 10 );
	}

	process_result = (int)(intptr_t)thread_result( test_thread );
	thread_destroy( test_thread );

	while( thread_is_thread( test_thread ) )
	{
		system_process_events();
		thread_sleep( 10 );
	}

#else

	process_result = (int)(intptr_t)test_runner( 0, tests );

#endif

	if( process_result != 0 )
		log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result );

#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL

	while( !_test_should_terminate && _test_have_focus && ( remain_counter < 50 ) )
	{
		system_process_events();
		thread_sleep( 100 );
		++remain_counter;
	}

#endif

	log_debug( HASH_TEST, "Exiting main loop" );

#else // !BUILD_MONOLITHIC

	//Find all test executables in the current executable directory
#if FOUNDATION_PLATFORM_WINDOWS
	pattern = "^test-.*\\.exe$";
#elif FOUNDATION_PLATFORM_MACOSX
	pattern = "^test-.*$";
#elif FOUNDATION_PLATFORM_POSIX
	pattern = "^test-.*$";
#else
#  error Not implemented
#endif
	exe_paths = fs_matching_files( environment_executable_directory(), pattern, false );
	array_resize( exe_flags, array_size( exe_paths ) );
	memset( exe_flags, 0, sizeof( unsigned int ) * array_size( exe_flags ) );
#if FOUNDATION_PLATFORM_MACOSX
	//Also search for test applications
	const char* app_pattern = "^test-.*\\.app$";
	regex_t* app_regex = regex_compile( app_pattern );
	char** subdirs = fs_subdirs( environment_executable_directory() );
	for( int idir = 0, dirsize = array_size( subdirs ); idir < dirsize; ++idir )
	{
		if( regex_match( app_regex, subdirs[idir], string_length( subdirs[idir] ), 0, 0 ) )
		{
			array_push( exe_paths, string_substr( subdirs[idir], 0, string_length( subdirs[idir] ) - 4 ) );
			array_push( exe_flags, PROCESS_MACOSX_USE_OPENAPPLICATION );
		}
	}
	string_array_deallocate( subdirs );
	regex_deallocate( app_regex );
#endif
	for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe )
	{
		bool is_self = false;
		char* exe_file_name = path_base_file_name( exe_paths[iexe] );
		if( string_equal( exe_file_name, environment_executable_name() ) )
			is_self = true;
		string_deallocate( exe_file_name );
		if( is_self )
			continue; //Don't run self

		process_path = path_merge( environment_executable_directory(), exe_paths[iexe] );

		process = process_allocate();

		process_set_executable_path( process, process_path );
		process_set_working_directory( process, environment_executable_directory() );
		process_set_flags( process, PROCESS_ATTACHED | exe_flags[iexe] );

		log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] );

		process_result = process_spawn( process );
		while( process_result == PROCESS_WAIT_INTERRUPTED )
		{
			thread_sleep( 10 );
			process_result = process_wait( process );
		}
		process_deallocate( process );

		string_deallocate( process_path );

		if( process_result != 0 )
		{
			if( process_result >= PROCESS_INVALID_ARGS )
				log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result );
			else
				log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result );
			process_set_exit_code( -1 );
			goto exit;
		}

		log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result );
	}

	log_info( HASH_TEST, "All tests passed" );

exit:

	if( exe_paths )
		string_array_deallocate( exe_paths );
	array_deallocate( exe_flags );

#endif

	thread_terminate( thread );
	thread_destroy( thread );
	while( thread_is_running( thread ) )
		thread_sleep( 10 );
	while( thread_is_thread( thread ) )
		thread_sleep( 10 );

	log_infof( HASH_TEST, "Tests exiting: %d", process_result );

	return process_result;
}
Ejemplo n.º 21
0
int process_wait( process_t* proc )
{
#if FOUNDATION_PLATFORM_POSIX
	int cstatus;
	pid_t err;
#endif	
	
	if( !proc )
		return PROCESS_INVALID_ARGS;

#if FOUNDATION_PLATFORM_WINDOWS

	if( !proc->hp )
		return proc->code;

	while( GetExitCodeProcess( proc->hp, (LPDWORD)&proc->code ) )
	{
		if( ( proc->code != STILL_ACTIVE ) || ( proc->flags & PROCESS_DETACHED ) )
			break;
		thread_sleep( 50 );
		proc->code = -1;
	}

	if( ( proc->code == STILL_ACTIVE ) && ( proc->flags & PROCESS_DETACHED ) )
		return PROCESS_STILL_ACTIVE;

	if( proc->ht )
		CloseHandle( proc->ht );
	if( proc->hp )
		CloseHandle( proc->hp );

	proc->hp = 0;
	proc->ht = 0;

#elif FOUNDATION_PLATFORM_POSIX

	if( !proc->pid )
		return proc->code;

#  if FOUNDATION_PLATFORM_MACOSX
	if( proc->flags & PROCESS_OSX_USE_OPENAPPLICATION )
	{
		if( proc->kq )
		{
			struct kevent event;
			int ret = kevent( proc->kq, 0, 0, &event, 1, 0 );
			if( ret != 1 )
				log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to wait on process, failed to read event from kqueue (%d)", ret );
			
			close( proc->kq );
			proc->kq = 0;
		}
		else
		{
			log_warnf( 0, WARNING_BAD_DATA, "Unable to wait on a process started with PROCESS_OSX_USE_OPENAPPLICATION and no kqueue" );
			return PROCESS_WAIT_FAILED;
		}
		proc->pid = 0;
		proc->code = 0;
		return proc->code;
	}
#  endif
	
	cstatus = 0;
	err = waitpid( proc->pid, &cstatus, ( proc->flags & PROCESS_DETACHED ) ? WNOHANG : 0 );
	if( err > 0 )
	{
		if( WIFEXITED( cstatus ) )
			proc->code = (int)((char)WEXITSTATUS( cstatus ));
		else if( WIFSIGNALED( cstatus ) )
		{
			proc->code = PROCESS_TERMINATED_SIGNAL;
#ifdef WCOREDUMP
			//if( WCOREDUMP( cstatus ) )
			//...
#endif
			//proc->signal = WTERMSIG( cstatus );
		}
		proc->pid = 0;
	}
	else
	{
		int cur_errno = errno;
		if( ( err == 0 ) && ( proc->flags & PROCESS_DETACHED ) )
			return PROCESS_STILL_ACTIVE;
		if( ( err < 0 ) && ( cur_errno == EINTR ) )
			return PROCESS_WAIT_INTERRUPTED;
		log_warnf( 0, WARNING_BAD_DATA, "waitpid(%d) failed: %s (%d) (returned %d)", proc->pid, system_error_message( cur_errno ), cur_errno, err );
		return PROCESS_WAIT_FAILED;
	}
	
#else
#error Not implemented
#endif

	return proc->code;
}
Ejemplo n.º 22
0
int process_spawn( process_t* proc )
{
	static char unescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:/\\";
	int i, num_args;
	int size;
#if FOUNDATION_PLATFORM_WINDOWS
	wchar_t* wcmdline;
	wchar_t* wwd;
	char* cmdline = 0;
#endif

	if( !proc )
		return PROCESS_INVALID_ARGS;
	
	proc->code = PROCESS_INVALID_ARGS;

	if( !string_length( proc->path ) )
		return proc->code;

	//Always escape path on Windows platforms
#if FOUNDATION_PLATFORM_POSIX
	if( string_find_first_not_of( proc->path, unescaped, 0 ) != STRING_NPOS )
#endif
	{
		if( proc->path[0] != '"' )
			proc->path = string_prepend( proc->path, "\"" );
		if( proc->path[ string_length( proc->path ) - 1 ] != '"' )
			proc->path = string_append( proc->path, "\"" );
	}

	size = array_size( proc->args );
	for( i = 0, num_args = 0; i < size; ++i )
	{
		char* arg = proc->args[i];
		
		if( !string_length( arg ) )
			continue;
		
		++num_args;
		
		if( string_find_first_not_of( arg, unescaped, 0 ) != STRING_NPOS )
		{
			if( arg[0] != '"' )
			{
				//Check if we need to escape " characters
				unsigned int pos = string_find( arg, '"', 0 );
				while( pos != STRING_NPOS )
				{
					if( arg[ pos - 1 ] != '\\' )
					{
						char* escarg = string_substr( arg, 0, pos );
						char* left = string_substr( arg, pos, STRING_NPOS );
						escarg = string_append( escarg, "\\" );
						escarg = string_append( escarg, left );
						string_deallocate( left );
						string_deallocate( arg );
						arg = escarg;
					}
					pos = string_find( arg, '"', pos + 2 );
				}
				arg = string_prepend( arg, "\"" );
				arg = string_append( arg, "\"" );

				proc->args[i] = arg;
			}
		}
	}

#if FOUNDATION_PLATFORM_WINDOWS

#  ifndef SEE_MASK_NOASYNC
#    define SEE_MASK_NOASYNC           0x00000100
#  endif

	if( !( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE ) ) //Don't prepend exe path to parameters if using ShellExecute
		cmdline = string_clone( proc->path );
	
	//Build command line string
	for( i = 0; i < size; ++i )
	{
		char* arg = proc->args[i];
		
		if( !string_length( arg ) )
			continue;

		if( cmdline )
			cmdline = string_append( cmdline, " " );
		cmdline = string_append( cmdline, arg );
	}
	
	if( !string_length( proc->wd ) )
		proc->wd = string_clone( environment_current_working_directory() );

	wcmdline = wstring_allocate_from_string( cmdline, 0 );
	wwd = wstring_allocate_from_string( proc->wd, 0 );
	
	if( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE )
	{
		SHELLEXECUTEINFOW sei;
		wchar_t* wverb;
		wchar_t* wpath;

		wverb = ( proc->verb && string_length( proc->verb ) ) ? wstring_allocate_from_string( proc->verb, 0 ) : 0;
		wpath = wstring_allocate_from_string( proc->path, 0 );

		ZeroMemory( &sei, sizeof( sei ) );

		sei.cbSize          = sizeof(SHELLEXECUTEINFOW);
		sei.hwnd            = 0;
		sei.fMask           = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb          = wverb;
		sei.lpFile          = wpath;
		sei.lpParameters    = wcmdline;
		sei.lpDirectory     = wwd;
		sei.nShow           = SW_SHOWNORMAL;

		if( !( proc->flags & PROCESS_CONSOLE ) )
			sei.fMask      |= SEE_MASK_NO_CONSOLE;

		if( proc->flags & PROCESS_STDSTREAMS )
			log_warnf( 0, WARNING_UNSUPPORTED, "Unable to redirect standard in/out through pipes when using ShellExecute for process spawning" );

		log_debugf( 0, "Spawn process (ShellExecute): %s %s", proc->path, cmdline );

		if( !ShellExecuteExW( &sei ) )
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (ShellExecute) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) );
		}
		else
		{
			proc->hp   = sei.hProcess;
			proc->ht   = 0;
			proc->code = 0;
		}

		wstring_deallocate( wverb );
		wstring_deallocate( wpath );
	}
	else
	{
		STARTUPINFOW si;
		PROCESS_INFORMATION pi;
		BOOL inherit_handles = FALSE;

		memset( &si, 0, sizeof( si ) );
		memset( &pi, 0, sizeof( pi ) );
		si.cb = sizeof( si );

		if( proc->flags & PROCESS_STDSTREAMS )
		{
			proc->pipeout = pipe_allocate();
			proc->pipein = pipe_allocate();

			si.dwFlags |= STARTF_USESTDHANDLES;
			si.hStdOutput = pipe_write_handle( proc->pipeout );
			si.hStdError = pipe_write_handle( proc->pipeout );
			si.hStdInput = pipe_read_handle( proc->pipein );

			//Don't inherit wrong ends of pipes
			SetHandleInformation( pipe_read_handle( proc->pipeout ), HANDLE_FLAG_INHERIT, 0 );
			SetHandleInformation( pipe_write_handle( proc->pipein ), HANDLE_FLAG_INHERIT, 0 );

			inherit_handles = TRUE;
		}

		log_debugf( 0, "Spawn process (CreateProcess): %s %s", proc->path, cmdline );

		if( !CreateProcessW( 0/*wpath*/, wcmdline, 0, 0, inherit_handles, ( proc->flags & PROCESS_CONSOLE ) ? CREATE_NEW_CONSOLE : 0, 0, wwd, &si, &pi ) )
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (CreateProcess) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) );

			stream_deallocate( proc->pipeout );
			stream_deallocate( proc->pipein );

			proc->pipeout = 0;
			proc->pipein = 0;
		}
		else
		{
			proc->hp = pi.hProcess;
			proc->ht = pi.hThread;
			proc->code = 0;
		}

		if( proc->pipeout )
			pipe_close_write( proc->pipeout );
		if( proc->pipein )
			pipe_close_read( proc->pipein );
	}

	wstring_deallocate( wcmdline );
	wstring_deallocate( wwd );
	string_deallocate( cmdline );
	
	if( proc->code < 0 )
		return proc->code; //Error

#endif

#if FOUNDATION_PLATFORM_MACOSX
	
	if( proc->flags & PROCESS_OSX_USE_OPENAPPLICATION )
	{
		proc->pid = 0;
		
		LSApplicationParameters params;
		ProcessSerialNumber psn;
		FSRef* fsref = memory_allocate( 0, sizeof( FSRef ), 0, MEMORY_TEMPORARY | MEMORY_ZERO_INITIALIZED );
		
		memset( &params, 0, sizeof( LSApplicationParameters ) );
		memset( &psn, 0, sizeof( ProcessSerialNumber ) );
		
		char* pathstripped = string_strip( string_clone( proc->path ), "\"" );
		
		OSStatus status = 0;
		status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 );
		if( status < 0 )
		{
			pathstripped = string_append( pathstripped, ".app" );
			status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 );
		}
		
		CFStringRef* args = 0;
		for( i = 0, size = array_size( proc->args ); i < size; ++i ) //App gets executable path automatically, don't include
			array_push( args, CFStringCreateWithCString( 0, proc->args[i], kCFStringEncodingUTF8 ) );
		
		CFArrayRef argvref = CFArrayCreate( 0, (const void**)args, (CFIndex)array_size( args ), 0 );
		
		params.flags = kLSLaunchDefaults;
		params.application = fsref;
		params.argv = argvref;

		log_debugf( 0, "Spawn process (LSOpenApplication): %s", pathstripped );
		
		status = LSOpenApplication( &params, &psn );
		if( status != 0 )
		{
			proc->code = status;
			log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process for executable '%s': %s", proc->path, system_error_message( status ) );
		}
		
		CFRelease( argvref );
		for( i = 0, size = array_size( args ); i < size; ++i )
			CFRelease( args[i] );
		
		memory_deallocate( fsref );
		string_deallocate( pathstripped );
		
		if( status == 0 )
		{
			pid_t pid = 0;
			GetProcessPID( &psn, &pid );
			
			proc->pid = pid;

			//Always "detached" with LSOpenApplication, not a child process at all
			//Setup a kqueue to watch when process terminates so we can emulate a wait
			proc->kq = kqueue();
			if( proc->kq < 0 )
			{
				log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create kqueue for process watch: %s (%d)", proc->kq, system_error_message( proc->kq ) );
				proc->kq = 0;
			}
			else
			{
				struct kevent changes;
				EV_SET( &changes, (pid_t)pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, 0 );
				int ret = kevent( proc->kq, &changes, 1, &changes, 1, 0 );
				if( ret != 1 )
				{
					log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to setup kqueue for process watch, failed to add event to kqueue (%d)", ret );
					close( proc->kq );
					proc->kq = 0;
				}
			}
		}
		
		goto exit;
	}
#endif

#if FOUNDATION_PLATFORM_POSIX

	//Insert executable arg at start and null ptr at end
	int argc = array_size( proc->args ) + 1;
	array_grow( proc->args, 2 );
	for( int arg = argc - 1; arg > 0; --arg )
		proc->args[arg] = proc->args[arg-1];
	proc->args[0] = string_clone( proc->path );
	proc->args[argc] = 0;

	if( proc->flags & PROCESS_STDSTREAMS )
	{
		proc->pipeout = pipe_allocate();
		proc->pipein = pipe_allocate();
	}
	
	proc->pid = 0;	
	pid_t pid = fork();

	if( pid == 0 )
	{
		//Child
		if( string_length( proc->wd ) )
		{
			log_debugf( 0, "Spawned child process, setting working directory to %s", proc->wd );
			environment_set_current_working_directory( proc->wd );
		}

		log_debugf( 0, "Child process executing: %s", proc->path );

		if( proc->flags & PROCESS_STDSTREAMS )
		{
			pipe_close_read( proc->pipeout );
			dup2( pipe_write_fd( proc->pipeout ), STDOUT_FILENO );

			pipe_close_write( proc->pipein );
			dup2( pipe_read_fd( proc->pipein ), STDIN_FILENO );
		}

		int code = execv( proc->path, proc->args );
		if( code < 0 ) //Will always be true since this point will never be reached if execve() is successful
			log_warnf( 0, WARNING_BAD_DATA, "Child process failed execve() : %s : %s", proc->path, system_error_message( errno ) );
		
		//Error
		process_exit( -1 );
	}

	if( pid > 0 )
	{		
		log_debugf( 0, "Child process forked, pid %d", pid );

		proc->pid = pid;

		if( proc->pipeout )
			pipe_close_write( proc->pipeout );
		if( proc->pipein )
			pipe_close_read( proc->pipein );
		
		if( proc->flags & PROCESS_DETACHED )
		{
			int cstatus = 0;
			pid_t err = waitpid( pid, &cstatus, WNOHANG );
			if( err == 0 )
			{
				//TODO: Ugly wait to make sure process spawned correctly
				thread_sleep( 500 );
				err = waitpid( pid, &cstatus, WNOHANG );
			}
			if( err > 0 )
			{
				//Process exited, check code
				proc->code = (int)((char)WEXITSTATUS( cstatus ));
				log_debugf( 0, "Child process returned: %d", proc->code );
				return proc->code;
			}
		}
	}
	else
	{
		//Error
		proc->code = errno;
		log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process: %s : %s", proc->path, system_error_message( proc->code ) );

		if( proc->pipeout )
			stream_deallocate( proc->pipeout );
		if( proc->pipein )
			stream_deallocate( proc->pipein );

		proc->pipeout = 0;
		proc->pipein = 0;
		
		return proc->code;
	}	

#endif

#if !FOUNDATION_PLATFORM_WINDOWS && !FOUNDATION_PLATFORM_POSIX
	FOUNDATION_ASSERT_FAIL( "Process spawning not supported on platform" );
#endif
	
#if FOUNDATION_PLATFORM_MACOSX
exit:
#endif

	if( proc->flags & PROCESS_DETACHED )
		return PROCESS_STILL_ACTIVE;

	return process_wait( proc );
}
Ejemplo n.º 23
0
size_t
network_poll(network_poll_t* pollobj, network_poll_event_t* events, size_t capacity,
             unsigned int timeoutms) {
	int avail = 0;
	size_t num_events = 0;

#if FOUNDATION_PLATFORM_WINDOWS
	//TODO: Refactor to keep fd_set across loop and rebuild on change (add/remove)
	int num_fd = 0;
	int ret = 0;
	size_t islot;
	fd_set fdread, fdwrite, fderr;
#endif

	if (!pollobj->num_sockets)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	int ret = poll(pollobj->pollfds, pollobj->num_sockets, timeoutms);

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	int ret = epoll_wait(pollobj->fd_poll, pollobj->events, pollobj->num_sockets + 1, timeoutms);
	int num_polled = ret;

#elif FOUNDATION_PLATFORM_WINDOWS

	FD_ZERO(&fdread);
	FD_ZERO(&fdwrite);
	FD_ZERO(&fderr);

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		socket_base_t* sockbase = _socket_base + pollobj->slots[islot].base;

		FD_SET(fd, &fdread);
		if (sockbase->state == SOCKETSTATE_CONNECTING)
			FD_SET(fd, &fdwrite);
		FD_SET(fd, &fderr);

		if (fd >= num_fd)
			num_fd = fd + 1;
	}

	if (!num_fd) {
		return num_events;
	}
	else {
		struct timeval tv;

		tv.tv_sec  = timeoutms / 1000;
		tv.tv_usec = (timeoutms % 1000) * 1000;

		ret = select(num_fd, &fdread, &fdwrite, &fderr, &tv);
	}

#else
#  error Not implemented
#endif

	if (ret < 0) {
		int err = NETWORK_SOCKET_ERROR;
		string_const_t errmsg = system_error_message(err);
		log_warnf(HASH_NETWORK, WARNING_SUSPICIOUS, STRING_CONST("Error in socket poll: %.*s (%d)"),
		          STRING_FORMAT(errmsg), err);
		if (!avail)
			return num_events;
		ret = avail;
	}
	if (!avail && !ret)
		return num_events;

#if FOUNDATION_PLATFORM_APPLE

	struct pollfd* pfd = pollobj->pollfds;
	network_poll_slot_t* slot = pollobj->slots;
	for (size_t i = 0; i < pollobj->num_sockets; ++i, ++pfd, ++slot) {
		socket_t* sock = slot->sock;
		socket_base_t* sockbase = _socket_base + slot->base;
		int fd = slot->fd;
		if (pfd->revents & POLLIN) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && (pfd->revents & POLLOUT)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			pfd->events = POLLIN | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (pfd->revents & POLLERR) {
			pfd->events = POLLOUT | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (pfd->revents & POLLHUP) {
			pfd->events = POLLOUT | POLLERR | POLLHUP;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	struct epoll_event* event = pollobj->events;
	for (int i = 0; i < num_polled; ++i, ++event) {
		FOUNDATION_ASSERT(pollobj->slots[ event->data.fd ].base >= 0);

		socket_t* sock = pollobj->slots[ event->data.fd ].sock;
		socket_base_t* sockbase = _socket_base + pollobj->slots[ event->data.fd ].base;
		int fd = pollobj->slots[ event->data.fd ].fd;
		if (event->events & EPOLLIN) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && (event->events & EPOLLOUT)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			struct epoll_event mod_event;
			mod_event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
			mod_event.data.fd = event->data.fd;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_MOD, fd, &mod_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (event->events & EPOLLERR) {
			struct epoll_event del_event;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_DEL, fd, &del_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (event->events & EPOLLHUP) {
			struct epoll_event del_event;
			epoll_ctl(pollobj->fd_poll, EPOLL_CTL_DEL, fd, &del_event);
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}

#elif FOUNDATION_PLATFORM_WINDOWS

	for (islot = 0; islot < pollobj->num_sockets; ++islot) {
		int fd = pollobj->slots[islot].fd;
		socket_t* sock = pollobj->slots[islot].sock;
		socket_base_t* sockbase = _socket_base + pollobj->slots[islot].base;

		if (sockbase->fd != fd)
			continue;

		if (FD_ISSET(fd, &fdread)) {
			if (sockbase->state == SOCKETSTATE_LISTENING) {
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTION, sock);
			}
			else { //SOCKETSTATE_CONNECTED
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_DATAIN, sock);
			}
		}
		if ((sockbase->state == SOCKETSTATE_CONNECTING) && FD_ISSET(fd, &fdwrite)) {
			sockbase->state = SOCKETSTATE_CONNECTED;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (FD_ISSET(fd, &fderr)) {
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
	}
#else
#  error Not implemented
#endif

	return num_events;
}
Ejemplo n.º 24
0
bool mutex_wait( mutex_t* mutex, unsigned int timeout )
{
#if FOUNDATION_PLATFORM_WINDOWS
	DWORD ret;
#elif FOUNDATION_PLATFORM_POSIX
	struct timeval now;
	struct timespec then;
#endif	
	FOUNDATION_ASSERT( mutex );
#if FOUNDATION_PLATFORM_WINDOWS

#if !BUILD_DEPLOY
	profile_wait( mutex->name );
#endif

	atomic_incr32( &mutex->waiting );

	ret = WaitForSingleObject( mutex->event, ( timeout == 0 ) ? INFINITE : timeout );

	if( ret == WAIT_OBJECT_0 )
		mutex_lock( mutex );
	
	if( atomic_decr32( &mutex->waiting ) == 0 )
		ResetEvent( mutex->event );

	return ret == WAIT_OBJECT_0;

#elif FOUNDATION_PLATFORM_POSIX
	
	mutex_lock( mutex );
	
	if( mutex->pending )
	{
		mutex->pending = false;
		return true;
	}

	--mutex->lockcount;
	
	bool was_signal = false;
	if( !timeout )
	{
		int ret = pthread_cond_wait( &mutex->cond, &mutex->mutex );
		if( ret == 0 )
		{
			was_signal = true;
		}
		else
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to wait on mutex '%s': %s (%d)", mutex->name, system_error_message( ret ), ret );
		}
	}
	else
	{
		int ret;
		gettimeofday( &now, 0 );
		then.tv_sec  = now.tv_sec + ( timeout / 1000 );
		then.tv_nsec = ( now.tv_usec * 1000 ) + (long)( timeout % 1000 ) * 1000000L;
		while( then.tv_nsec > 999999999 )
		{
			++then.tv_sec;
			then.tv_nsec -= 1000000000L;
		}
		ret = pthread_cond_timedwait( &mutex->cond, &mutex->mutex, &then );
		if( ret == 0 )
		{
			was_signal = true;
		}
		else if( ret != ETIMEDOUT )
		{
			log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to wait (timed) on mutex '%s': %s (%d)", mutex->name, system_error_message( ret ), ret );
		}
	}

	++mutex->lockcount;
	mutex->lockedthread = thread_id();
	
	if( was_signal )
		mutex->pending = false;
	else
		mutex_unlock( mutex );
	
	return was_signal;

#else
#  error mutex_wait not implemented
#endif
}
Ejemplo n.º 25
0
int
main_run(void* main_arg) {
#if !BUILD_MONOLITHIC
	string_const_t pattern;
	string_t* exe_paths = 0;
	size_t iexe, exesize;
	process_t* process = 0;
	string_t process_path = { 0, 0 };
	unsigned int* exe_flags = 0;
#else
	void* test_result;
#endif
#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL
	int remain_counter = 0;
#endif
#if BUILD_DEBUG
	const string_const_t build_name = string_const(STRING_CONST("debug"));
#elif BUILD_RELEASE
	const string_const_t build_name = string_const(STRING_CONST("release"));
#elif BUILD_PROFILE
	const string_const_t build_name = string_const(STRING_CONST("profile"));
#elif BUILD_DEPLOY
	const string_const_t build_name = string_const(STRING_CONST("deploy"));
#endif
#if BUILD_MONOLITHIC
	const string_const_t build_type = string_const(STRING_CONST(" monolithic"));
#else
	const string_const_t build_type = string_empty();
#endif
	char* pathbuf;
	int process_result = 0;
	thread_t event_thread;
	FOUNDATION_UNUSED(main_arg);
	FOUNDATION_UNUSED(build_name);

	log_set_suppress(HASH_TEST, ERRORLEVEL_DEBUG);

	log_infof(HASH_TEST, STRING_CONST("Task library v%s built for %s using %s (%.*s%.*s)"),
	          string_from_version_static(task_module_version()).str, FOUNDATION_PLATFORM_DESCRIPTION,
	          FOUNDATION_COMPILER_DESCRIPTION, STRING_FORMAT(build_name), STRING_FORMAT(build_type));

	thread_initialize(&event_thread, event_loop, 0, STRING_CONST("event_thread"),
	                  THREAD_PRIORITY_NORMAL, 0);
	thread_start(&event_thread);

	pathbuf = memory_allocate(HASH_STRING, BUILD_MAX_PATHLEN, 0, MEMORY_PERSISTENT);

	while (!thread_is_running(&event_thread))
		thread_sleep(10);

#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL
	while (!_test_should_start) {
#if FOUNDATION_PLATFORM_ANDROID
		system_process_events();
#endif
		thread_sleep(100);
	}
#endif

	fs_remove_directory(STRING_ARGS(environment_temporary_directory()));

#if BUILD_MONOLITHIC

	test_run_fn tests[] = {
		test_task_run,
		0
	};

#if FOUNDATION_PLATFORM_ANDROID

	thread_t test_thread;
	thread_initialize(&test_thread, test_runner, tests, STRING_CONST("test_runner"),
	                  THREAD_PRIORITY_NORMAL, 0);
	thread_start(&test_thread);

	log_debug(HASH_TEST, STRING_CONST("Starting test runner thread"));

	while (!thread_is_running(&test_thread)) {
		system_process_events();
		thread_sleep(10);
	}

	while (thread_is_running(&test_thread)) {
		system_process_events();
		thread_sleep(10);
	}

	test_result = thread_join(&test_thread);
	process_result = (int)(intptr_t)test_result;

	thread_finalize(&test_thread);

#else

	test_result = test_runner(tests);
	process_result = (int)(intptr_t)test_result;

#endif

	if (process_result != 0)
		log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"),
		          process_result);

#if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL

	while (!_test_should_terminate && _test_have_focus && (remain_counter < 50)) {
		system_process_events();
		thread_sleep(100);
		++remain_counter;
	}

#endif

	log_debug(HASH_TEST, STRING_CONST("Exiting main loop"));

#else // !BUILD_MONOLITHIC

	//Find all test executables in the current executable directory
#if FOUNDATION_PLATFORM_WINDOWS
	pattern = string_const(STRING_CONST("^test-.*\\.exe$"));
#elif FOUNDATION_PLATFORM_MACOSX
	pattern = string_const(STRING_CONST("^test-.*$"));
#elif FOUNDATION_PLATFORM_POSIX
	pattern = string_const(STRING_CONST("^test-.*$"));
#else
#  error Not implemented
#endif
	exe_paths = fs_matching_files(STRING_ARGS(environment_executable_directory()),
	                              STRING_ARGS(pattern), false);
	array_resize(exe_flags, array_size(exe_paths));
	memset(exe_flags, 0, sizeof(unsigned int) * array_size(exe_flags));
#if FOUNDATION_PLATFORM_MACOSX
	//Also search for test applications
	string_const_t app_pattern = string_const(STRING_CONST("^test-.*\\.app$"));
	regex_t* app_regex = regex_compile(app_pattern.str, app_pattern.length);
	string_t* subdirs = fs_subdirs(STRING_ARGS(environment_executable_directory()));
	for (size_t idir = 0, dirsize = array_size(subdirs); idir < dirsize; ++idir) {
		if (regex_match(app_regex, subdirs[idir].str, subdirs[idir].length, 0, 0)) {
			string_t exe_path = { subdirs[idir].str, subdirs[idir].length - 4 };
			array_push(exe_paths, exe_path);
			array_push(exe_flags, PROCESS_MACOSX_USE_OPENAPPLICATION);
		}
	}
	string_array_deallocate(subdirs);
	regex_deallocate(app_regex);
#endif
	for (iexe = 0, exesize = array_size(exe_paths); iexe < exesize; ++iexe) {
		string_const_t* process_args = 0;
		string_const_t exe_file_name = path_base_file_name(STRING_ARGS(exe_paths[iexe]));
		if (string_equal(STRING_ARGS(exe_file_name), STRING_ARGS(environment_executable_name())))
			continue; //Don't run self

		process_path = path_concat(pathbuf, BUILD_MAX_PATHLEN,
		                           STRING_ARGS(environment_executable_directory()),
		                           STRING_ARGS(exe_paths[iexe]));
		process = process_allocate();

		process_set_executable_path(process, STRING_ARGS(process_path));
		process_set_working_directory(process, STRING_ARGS(environment_executable_directory()));
		process_set_flags(process, PROCESS_ATTACHED | exe_flags[iexe]);

		if (!_test_memory_tracker)
			array_push(process_args, string_const(STRING_CONST("--no-memory-tracker")));
		process_set_arguments(process, process_args, array_size(process_args));

		log_infof(HASH_TEST, STRING_CONST("Running test executable: %.*s"),
		          STRING_FORMAT(exe_paths[iexe]));

		process_result = process_spawn(process);
		while (process_result == PROCESS_WAIT_INTERRUPTED) {
			thread_sleep(10);
			process_result = process_wait(process);
		}
		process_deallocate(process);
		array_deallocate(process_args);

		if (process_result != 0) {
			if (process_result >= PROCESS_INVALID_ARGS)
				log_warnf(HASH_TEST, WARNING_SUSPICIOUS,
				          STRING_CONST("Tests failed, process terminated with error %x"),
				          process_result);
			else
				log_warnf(HASH_TEST, WARNING_SUSPICIOUS, STRING_CONST("Tests failed with exit code %d"),
				          process_result);
			process_set_exit_code(-1);
			goto exit;
		}

		log_infof(HASH_TEST, STRING_CONST("All tests from %.*s passed (%d)"),
		          STRING_FORMAT(exe_paths[iexe]), process_result);
	}

	log_info(HASH_TEST, STRING_CONST("All tests passed"));

exit:

	if (exe_paths)
		string_array_deallocate(exe_paths);
	array_deallocate(exe_flags);

#endif

	_test_should_terminate = true;

	thread_signal(&event_thread);
	thread_finalize(&event_thread);

	memory_deallocate(pathbuf);

	log_infof(HASH_TEST, STRING_CONST("Tests exiting: %s (%d)"),
	          process_result ? "FAILED" : "PASSED", process_result);

	if (process_result)
		memory_set_tracker(memory_tracker_none());

	return process_result;
}
Ejemplo n.º 26
0
static int
render_import_program(stream_t* stream, const uuid_t uuid) {
	char buffer[1024];
	char pathbuf[BUILD_MAX_PATHLEN];
	resource_source_t source;
	resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1};
	uint64_t platform;
	tick_t timestamp;
	int ret = 0;

	resource_source_initialize(&source);
	resource_source_read(&source, uuid);

	platform = resource_platform(platformdecl);
	timestamp = time_system();

	while (!stream_eos(stream)) {
		string_const_t type, ref;
		string_const_t fullpath;
		string_const_t uuidstr;
		uuid_t shaderuuid;
		hash_t typehash;
		string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n');
		string_split(STRING_ARGS(line), STRING_CONST(" \t"),
		             &type, &ref, false);

		type = string_strip(STRING_ARGS(type), STRING_CONST(STRING_WHITESPACE));
		ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE));
		if (!type.length || !ref.length)
			continue;

		typehash = hash(STRING_ARGS(type));
		if ((typehash != HASH_VERTEXSHADER) && (typehash != HASH_PIXELSHADER)) {
			log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Ignore invalid line: %.*s"),
			          STRING_FORMAT(line));
			continue;
		}

		shaderuuid = string_to_uuid(STRING_ARGS(ref));
		if (uuid_is_null(shaderuuid)) {
			if (path_is_absolute(STRING_ARGS(ref))) {
				fullpath = ref;
			}
			else {
				string_t full;
				string_const_t path = stream_path(stream);
				path = path_directory_name(STRING_ARGS(path));
				full = path_concat(pathbuf, sizeof(pathbuf),
				                   STRING_ARGS(path), STRING_ARGS(ref));
				full = path_absolute(STRING_ARGS(full), sizeof(pathbuf));
				fullpath = string_const(STRING_ARGS(full));
			}

			resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath));
			if (uuid_is_null(sig.uuid)) {
				if (!resource_import(STRING_ARGS(fullpath), uuid_null())) {
					log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Unable to import linked shader: %.*s"),
					          STRING_FORMAT(fullpath));
					ret = -1;
					goto finalize;
				}
				sig = resource_import_lookup(STRING_ARGS(fullpath));
				if (uuid_is_null(sig.uuid)) {
					log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS,
					          STRING_CONST("Import linked shader gave no UUID: %.*s"),
					          STRING_FORMAT(fullpath));
					ret = -1;
					goto finalize;
				}
			}
			shaderuuid = sig.uuid;
		}

		if (!uuid_is_null(shaderuuid)) {
			uuidstr = string_from_uuid_static(shaderuuid);
			resource_source_set(&source, timestamp, typehash,
			                    platform, STRING_ARGS(uuidstr));
		}
	}

	resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE,
	                    0, STRING_CONST("program"));

	if (!resource_source_write(&source, uuid, false)) {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported program: %.*s"),
		          STRING_FORMAT(uuidstr));
		ret = -1;
		goto finalize;
	}
	else {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported program: %.*s"),
		          STRING_FORMAT(uuidstr));
	}

finalize:
	resource_source_finalize(&source);

	return ret;
}
Ejemplo n.º 27
0
static int
render_import_shader(stream_t* stream, const uuid_t uuid) {
	char buffer[1024];
	char pathbuf[BUILD_MAX_PATHLEN];
	resource_source_t source;
	resource_platform_t platformdecl = {-1, -1, -1, -1, -1, -1};
	uint64_t platform;
	tick_t timestamp;
	int ret = 0;

	resource_source_initialize(&source);
	resource_source_read(&source, uuid);

	platform = resource_platform(platformdecl);
	timestamp = time_system();

	while (!stream_eos(stream)) {
		uuid_t shaderuuid;
		string_const_t target, ref, fullpath;
		string_t line = stream_read_line_buffer(stream, buffer, sizeof(buffer), '\n');
		string_split(STRING_ARGS(line), STRING_CONST(" \t"),
		             &target, &ref, false);

		ref = string_strip(STRING_ARGS(ref), STRING_CONST(STRING_WHITESPACE));
		shaderuuid = string_to_uuid(STRING_ARGS(ref));
		if (uuid_is_null(shaderuuid)) {
			if (path_is_absolute(STRING_ARGS(ref))) {
				fullpath = ref;
			}
			else {
				string_t full;
				string_const_t path = stream_path(stream);
				path = path_directory_name(STRING_ARGS(path));
				full = path_concat(pathbuf, sizeof(pathbuf),
				                   STRING_ARGS(path), STRING_ARGS(ref));
				full = path_absolute(STRING_ARGS(full), sizeof(pathbuf));
				fullpath = string_const(STRING_ARGS(full));
			}

			resource_signature_t sig = resource_import_lookup(STRING_ARGS(fullpath));
			if (uuid_is_null(sig.uuid)) {
				if (!resource_import(STRING_ARGS(fullpath), uuid_null())) {
					log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS,
					          STRING_CONST("Unable to import linked shader: %.*s"),
					          STRING_FORMAT(fullpath));
					ret = -1;
					goto finalize;
				}
				sig = resource_import_lookup(STRING_ARGS(fullpath));
				if (uuid_is_null(sig.uuid)) {
					log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS,
					          STRING_CONST("Import linked shader gave no UUID: %.*s"),
					          STRING_FORMAT(fullpath));
					ret = -1;
					goto finalize;
				}
			}
			shaderuuid = sig.uuid;
		}

		if (!uuid_is_null(shaderuuid)) {
			resource_platform_t targetplatformdecl =
			    render_import_parse_target(STRING_ARGS(target), platformdecl);
			uint64_t targetplatform = resource_platform(targetplatformdecl);

			if (resource_autoimport_need_update(shaderuuid, targetplatform))
				resource_autoimport(shaderuuid);

			const string_const_t uuidstr = string_from_uuid_static(shaderuuid);
			resource_source_set(&source, timestamp, HASH_SHADER,
			                    targetplatform, STRING_ARGS(uuidstr));
			resource_source_set_dependencies(uuid, targetplatform, &shaderuuid, 1);
		}
	}

	resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE,
	                    0, STRING_CONST("shader"));

	if (!resource_source_write(&source, uuid, false)) {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported shader: %.*s"),
		          STRING_FORMAT(uuidstr));
		ret = -1;
		goto finalize;
	}
	else {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported shader: %.*s"),
		          STRING_FORMAT(uuidstr));
	}

finalize:
	resource_source_finalize(&source);

	return 0;
}
Ejemplo n.º 28
0
int
process_spawn(process_t* proc) {
	static const string_const_t unescaped = { STRING_CONST("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:/\\") };
	size_t i, num_args;
	size_t size;
#if FOUNDATION_PLATFORM_WINDOWS
	wchar_t* wcmdline;
	wchar_t* wwd;
	string_t cmdline;
#endif
#if !FOUNDATION_PLATFORM_POSIX
	size_t capacity;
#endif

	proc->code = PROCESS_INVALID_ARGS;
	if (!proc->path.length)
		return proc->code;

	//Always escape path on Windows platforms
#if FOUNDATION_PLATFORM_POSIX
	if (string_find_first_not_of(STRING_ARGS(proc->path), STRING_ARGS(unescaped), 0) != STRING_NPOS)
#endif
	{
		bool preesc = (proc->path.str[0] != '"');
		bool postesc = (proc->path.str[ proc->path.length - 1 ] != '"');
		if (preesc || postesc) {
			char* buffer = memory_allocate(HASH_STRING, proc->path.length + 4, 0, MEMORY_PERSISTENT);
			string_t pathesc = string_concat_varg(buffer, proc->path.length + 4,
			                                      "\"", (size_t)(preesc ? 1 : 0),
			                                      STRING_ARGS(proc->path),
			                                      "\"", (size_t)(postesc ? 1 : 0),
			                                      nullptr);
			string_deallocate(proc->path.str);
			proc->path = pathesc;
		}
	}

	size = array_size(proc->args);
	for (i = 0, num_args = 0; i < size; ++i) {
		string_t arg = proc->args[i];

		if (!arg.length)
			continue;

		++num_args;

#if !FOUNDATION_PLATFORM_POSIX
		if (string_find_first_not_of(arg.str, arg.length,
		                             unescaped.str, unescaped.length, 0) != STRING_NPOS) {
			if (arg.str[0] != '"') {
				//Check if we need to escape " characters
				string_t escarg;
				size_t pos = string_find(arg.str, arg.length, '"', 0);
				while (pos != STRING_NPOS) {
					if (arg.str[ pos - 1 ] != '\\') {
						string_const_t right = string_substr(STRING_ARGS(arg), 0, pos);
						string_const_t left = string_substr(STRING_ARGS(arg), pos, STRING_NPOS);
						capacity = arg.length + 2;
						escarg = string_allocate(0, capacity);
						escarg = string_concat(escarg.str, capacity, STRING_ARGS(right), STRING_CONST("\\"));
						escarg = string_append(STRING_ARGS(escarg), capacity, STRING_ARGS(left));
						string_deallocate(arg.str);
						arg = escarg;
					}
					pos = string_find(STRING_ARGS(arg), '"', pos + 2);
				}
				escarg = string_allocate_concat_varg(STRING_CONST("\""), STRING_ARGS(arg),
				                                     STRING_CONST("\""), nullptr);
				string_deallocate(arg.str);
				proc->args[i] = escarg;
			}
		}
#endif
	}

#if FOUNDATION_PLATFORM_WINDOWS

#  ifndef SEE_MASK_NOASYNC
#    define SEE_MASK_NOASYNC 0x00000100
#  endif

	capacity = BUILD_MAX_PATHLEN;
	cmdline = string_allocate(0, capacity);

	//Don't prepend exe path to parameters if using ShellExecute
	if (!(proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE))
		cmdline = string_copy(cmdline.str, capacity, STRING_ARGS(proc->path));

	//Build command line string
	for (i = 0; i < size; ++i) {
		string_t arg = proc->args[i];

		if (!arg.length)
			continue;
		if (cmdline.length + arg.length + 2 >= capacity) {
			string_t newline;
			capacity *= 2;
			newline = string_allocate(0, capacity);
			newline = string_copy(newline.str, capacity, STRING_ARGS(cmdline));
		}
		if (cmdline.length)
			cmdline = string_append(STRING_ARGS(cmdline), capacity, STRING_CONST(" "));
		cmdline = string_append(STRING_ARGS(cmdline), capacity, STRING_ARGS(arg));
	}

	if (!proc->wd.length)
		proc->wd = string_clone(STRING_ARGS(environment_current_working_directory()));

	wcmdline = wstring_allocate_from_string(STRING_ARGS(cmdline));
	wwd = wstring_allocate_from_string(STRING_ARGS(proc->wd));

	if (proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE) {
		SHELLEXECUTEINFOW sei;
		wchar_t* wverb;
		wchar_t* wpath;

		wverb = (proc->verb.length ? wstring_allocate_from_string(STRING_ARGS(proc->verb)) : 0);
		wpath = wstring_allocate_from_string(STRING_ARGS(proc->path));

		ZeroMemory(&sei, sizeof(sei));

		sei.cbSize          = sizeof(SHELLEXECUTEINFOW);
		sei.hwnd            = 0;
		sei.fMask           = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
		sei.lpVerb          = wverb;
		sei.lpFile          = wpath;
		sei.lpParameters    = wcmdline;
		sei.lpDirectory     = wwd;
		sei.nShow           = SW_SHOWNORMAL;

		if (!(proc->flags & PROCESS_CONSOLE))
			sei.fMask      |= SEE_MASK_NO_CONSOLE;

		if (proc->flags & PROCESS_STDSTREAMS)
			log_warn(0, WARNING_UNSUPPORTED, STRING_CONST("Unable to redirect standard in/out"
			                                              " through pipes when using ShellExecute for process spawning"));

		log_debugf(0, STRING_CONST("Spawn process (ShellExecute): %.*s %.*s"),
		           STRING_FORMAT(proc->path), STRING_FORMAT(cmdline));

		if (!ShellExecuteExW(&sei)) {
			string_const_t errstr = system_error_message(0);
			log_warnf(0, WARNING_SYSTEM_CALL_FAIL,
			          STRING_CONST("Unable to spawn process (ShellExecute) for executable '%.*s': %s"),
			          STRING_FORMAT(proc->path), STRING_FORMAT(errstr));
		}
		else {
			proc->hp   = sei.hProcess;
			proc->ht   = 0;
			proc->code = 0;
		}

		wstring_deallocate(wverb);
		wstring_deallocate(wpath);
	}
	else {
		STARTUPINFOW si;
		PROCESS_INFORMATION pi;
		BOOL inherit_handles = FALSE;

		memset(&si, 0, sizeof(si));
		memset(&pi, 0, sizeof(pi));
		si.cb = sizeof(si);

		if (proc->flags & PROCESS_STDSTREAMS) {
			proc->pipeout = pipe_allocate();
			proc->pipein = pipe_allocate();

			si.dwFlags |= STARTF_USESTDHANDLES;
			si.hStdOutput = pipe_write_handle(proc->pipeout);
			si.hStdInput = pipe_read_handle(proc->pipein);
			si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

			//Don't inherit wrong ends of pipes
			SetHandleInformation(pipe_read_handle(proc->pipeout), HANDLE_FLAG_INHERIT, 0);
			SetHandleInformation(pipe_write_handle(proc->pipein), HANDLE_FLAG_INHERIT, 0);

			inherit_handles = TRUE;
		}

		log_debugf(0, STRING_CONST("Spawn process (CreateProcess): %.*s %.*s"),
		           STRING_FORMAT(proc->path), STRING_FORMAT(cmdline));

		if (!CreateProcessW(0, wcmdline, 0, 0, inherit_handles,
		                    (proc->flags & PROCESS_CONSOLE) ? CREATE_NEW_CONSOLE : 0, 0, wwd, &si, &pi)) {
			string_const_t errstr = system_error_message(0);
			log_warnf(0, WARNING_SYSTEM_CALL_FAIL,
			          STRING_CONST("Unable to spawn process (CreateProcess) for executable '%.*s': %.*s"),
			          STRING_FORMAT(proc->path), STRING_FORMAT(errstr));

			stream_deallocate(proc->pipeout);
			stream_deallocate(proc->pipein);

			proc->pipeout = 0;
			proc->pipein = 0;
		}
		else {
			proc->hp = pi.hProcess;
			proc->ht = pi.hThread;
			proc->code = 0;
		}

		if (proc->pipeout)
			pipe_close_write(proc->pipeout);
		if (proc->pipein)
			pipe_close_read(proc->pipein);
	}

	wstring_deallocate(wcmdline);
	wstring_deallocate(wwd);
	string_deallocate(cmdline.str);

	if (proc->code < 0)
		return proc->code; //Error

#endif

#if FOUNDATION_PLATFORM_MACOSX

	if (proc->flags & PROCESS_MACOSX_USE_OPENAPPLICATION) {
		proc->pid = 0;

		LSApplicationParameters params;
		ProcessSerialNumber psn;
		FSRef* fsref = memory_allocate(0, sizeof(FSRef), 0, MEMORY_TEMPORARY | MEMORY_ZERO_INITIALIZED);

		memset(&params, 0, sizeof(LSApplicationParameters));
		memset(&psn, 0, sizeof(ProcessSerialNumber));

		string_const_t pathstripped = string_strip(proc->path.str, proc->path.length, STRING_CONST("\""));
		size_t localcap = pathstripped.length + 5;
		string_t localpath = string_allocate(0, localcap - 1);
		localpath = string_copy(localpath.str, localcap,
		                        STRING_ARGS(pathstripped));     //Need it zero terminated

		OSStatus status = 0;
		status = FSPathMakeRef((uint8_t*)localpath.str, fsref, 0);
		if (status < 0) {
			localpath = string_append(localpath.str, localpath.length, localcap, STRING_CONST(".app"));
			status = FSPathMakeRef((uint8_t*)localpath.str, fsref, 0);
		}

		CFStringRef* args = 0;
		for (i = 0, size = array_size(proc->args); i < size;
		        ++i)    //App gets executable path automatically, don't include
			array_push(args, CFStringCreateWithCString(0, proc->args[i].str, kCFStringEncodingUTF8));

		CFArrayRef argvref = CFArrayCreate(0, (const void**)args, (CFIndex)array_size(args), 0);

		params.flags = kLSLaunchDefaults;
		params.application = fsref;
		params.argv = argvref;

		log_debugf(0, STRING_CONST("Spawn process (LSOpenApplication): %.*s"), STRING_FORMAT(localpath));

		status = LSOpenApplication(&params, &psn);
		if (status != 0) {
			int err = status;
			string_const_t errmsg = system_error_message(err);
			proc->code = status;
			log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
			           STRING_CONST("Unable to spawn process for executable '%.*s': %.*s (%d)"),
			           STRING_FORMAT(localpath), STRING_FORMAT(errmsg), err);
		}

		CFRelease(argvref);
		for (i = 0, size = array_size(args); i < size; ++i)
			CFRelease(args[i]);
		array_deallocate(args);

		memory_deallocate(fsref);
		string_deallocate(localpath.str);

		if (status == 0) {
			pid_t pid = 0;
			GetProcessPID(&psn, &pid);

			proc->pid = pid;

			//Always "detached" with LSOpenApplication, not a child process at all
			//Setup a kqueue to watch when process terminates so we can emulate a wait
			proc->kq = kqueue();
			if (proc->kq < 0) {
				string_const_t errmsg = system_error_message(proc->kq);
				log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
				           STRING_CONST("Unable to create kqueue for process watch: %.*s (%d)"),
				           STRING_FORMAT(errmsg), proc->kq);
				proc->kq = 0;
			}
			else {
				struct kevent changes;
				EV_SET(&changes, (pid_t)pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, 0);
				int ret = kevent(proc->kq, &changes, 1, &changes, 1, 0);
				if (ret != 1) {
					int err = errno;
					string_const_t errmsg = system_error_message(err);
					log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
					           STRING_CONST("Unable to setup kqueue for process watch, failed to add event to kqueue: %.*s (%d)"),
					           STRING_FORMAT(errmsg), err);
					close(proc->kq);
					proc->kq = 0;
				}
			}
		}

		goto exit;
	}
#endif

#if FOUNDATION_PLATFORM_POSIX

	//Insert executable arg at start and null ptr at end
	size_t arg;
	size_t argc = array_size(proc->args) + 1;
	array_grow(proc->args, 2);
	for (arg = argc - 1; arg > 0; --arg)
		proc->args[arg] = proc->args[arg - 1];
	proc->args[0] = string_clone(STRING_ARGS(proc->path));
	proc->args[argc] = (string_t) { 0, 0 };

	char** argv = memory_allocate(0, sizeof(char*) * (argc + 1), 0, MEMORY_PERSISTENT);
	for (arg = 0; arg < argc; ++arg)
		argv[arg] = proc->args[arg].str;
	argv[argc] = 0;

	if (proc->flags & PROCESS_STDSTREAMS) {
		proc->pipeout = pipe_allocate();
		proc->pipein = pipe_allocate();
	}

	proc->pid = 0;
	pid_t pid = fork();

	if (pid == 0) {
		//Child
		if (proc->wd.length) {
			log_debugf(0, STRING_CONST("Spawned child process, setting working directory to %.*s"),
			           STRING_FORMAT(proc->wd));
			environment_set_current_working_directory(STRING_ARGS(proc->wd));
		}

		log_debugf(0, STRING_CONST("Child process executing: %.*s"), STRING_FORMAT(proc->path));

		if (proc->flags & PROCESS_STDSTREAMS) {
			pipe_close_read(proc->pipeout);
			dup2(pipe_write_handle(proc->pipeout), STDOUT_FILENO);

			pipe_close_write(proc->pipein);
			dup2(pipe_read_handle(proc->pipein), STDIN_FILENO);
		}

		int code = execv(proc->path.str, (char* const*)argv);

		//Error
		int err = errno;
		string_const_t errmsg = system_error_message(err);
		log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
		           STRING_CONST("Child process failed execve() '%.*s': %.*s (%d) (%d)"),
			       STRING_FORMAT(proc->path), STRING_FORMAT(errmsg), err, code);
		process_exit(PROCESS_EXIT_FAILURE);
		FOUNDATION_UNUSED(code);
	}

	memory_deallocate(argv);

	if (pid > 0) {
		log_debugf(0, STRING_CONST("Child process forked, pid %d"), pid);

		proc->pid = pid;

		if (proc->pipeout)
			pipe_close_write(proc->pipeout);
		if (proc->pipein)
			pipe_close_read(proc->pipein);

		/*if (proc->flags & PROCESS_DETACHED) {
			int cstatus = 0;
			pid_t err = waitpid(pid, &cstatus, WNOHANG);
			if (err == 0) {
				//TODO: Ugly wait to make sure process spawned correctly
				thread_sleep(500);
				err = waitpid(pid, &cstatus, WNOHANG);
			}
			if (err > 0) {
				//Process exited, check code
				proc->pid = 0;
				proc->code = (int)((char)WEXITSTATUS(cstatus));
				log_debugf(0, STRING_CONST("Child process returned: %d"), proc->code);
				return proc->code;
			}
		}*/
	}
	else {
		//Error
		string_const_t errmsg;
		errmsg = system_error_message(proc->code);
		log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to spawn process '%.*s': %.*s (%d)"),
		           STRING_FORMAT(proc->path), STRING_FORMAT(errmsg), proc->code);

		if (proc->pipeout)
			stream_deallocate(proc->pipeout);
		if (proc->pipein)
			stream_deallocate(proc->pipein);

		proc->pipeout = 0;
		proc->pipein = 0;
		proc->code = PROCESS_INVALID_ARGS;

		return proc->code;
	}

#endif

#if !FOUNDATION_PLATFORM_WINDOWS && !FOUNDATION_PLATFORM_POSIX
	FOUNDATION_ASSERT_FAIL("Process spawning not supported on platform");
#endif

#if FOUNDATION_PLATFORM_MACOSX
exit:
#endif

	if (proc->flags & PROCESS_DETACHED)
		return PROCESS_STILL_ACTIVE;

	return process_wait(proc);
}
Ejemplo n.º 29
0
static int
render_import_glsl_shader(stream_t* stream, const uuid_t uuid, const char* type,
                          size_t type_length) {
	resource_source_t source;
	void* blob = 0;
	size_t size;
	size_t read;
	size_t begin;
	size_t next;
	hash_t checksum;
	tick_t timestamp;
	uint64_t platform;
	size_t maxtokens;
	size_t parameter;
	string_const_t* token = 0;
	string_const_t valstr;
	char buffer[128];
	int ret = 0;
	resource_platform_t platformdecl = { -1, -1, RENDERAPIGROUP_OPENGL, -1, -1, -1};

	resource_source_initialize(&source);
	resource_source_read(&source, uuid);

	read = 0;
	size = stream_size(stream);
	blob = memory_allocate(HASH_RESOURCE, size, 0, MEMORY_PERSISTENT);

	size = stream_read(stream, blob, size);

	platform = resource_platform(platformdecl);
	timestamp = time_system();
	checksum = hash(blob, size);
	if (resource_source_write_blob(uuid, timestamp, HASH_SOURCE,
	                               platform, checksum, blob, size)) {
		resource_source_set_blob(&source, timestamp, HASH_SOURCE,
		                         platform, checksum, size);
	}
	else {
		ret = -1;
		goto finalize;
	}

	//Parse source and set parameters
	maxtokens = 256;
	token = memory_allocate(HASH_RESOURCE, sizeof(string_const_t) * maxtokens, 0, MEMORY_PERSISTENT);
	begin = 0;
	parameter = 0;
	do {
		string_const_t tokens[64], line;
		size_t itok, ntokens;

		next = string_find_first_of(blob, size, STRING_CONST("\n\r"), begin);
		line = string_substr(blob, size, begin, next - begin);
		ntokens = string_explode(STRING_ARGS(line), STRING_CONST(GLSL_TOKEN_DELIM),
		                        tokens, maxtokens, false);

		for (itok = 0; itok < ntokens; ++itok) {
			if ((string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("attribute")) ||
			        string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("uniform"))) &&
			        (itok + 2 < ntokens)) {
				char typebuf[16], dimbuf[16];
				string_const_t typestr = tokens[itok + 1];
				string_const_t namestr = tokens[itok + 2];
				string_const_t dimstr;

				int parameter_type = glsl_type_to_parameter_type(typestr);
				if (parameter_type < 0)
					continue;

				int parameter_dim = glsl_dim_from_token(typestr);
				if (parameter_dim == 1)
					parameter_dim = glsl_dim_from_token(namestr);

				namestr = glsl_name_from_token(namestr);
				typestr = string_to_const(string_from_uint(typebuf, sizeof(typebuf), (unsigned int)parameter_type, false, 0, 0));
				dimstr = string_to_const(string_from_uint(dimbuf, sizeof(dimbuf), (unsigned int)parameter_dim, false, 0, 0));

				log_debugf(HASH_RESOURCE, STRING_CONST("parameter: %.*s type %.*s dim %.*s"),
				           STRING_FORMAT(namestr), STRING_FORMAT(typestr), STRING_FORMAT(dimstr));

				string_t param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_type_%" PRIsize),
				                               parameter);
				resource_source_set(&source, timestamp, hash(STRING_ARGS(param)),
				                    platform, STRING_ARGS(typestr));

				param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_name_%" PRIsize),
				                      parameter);
				resource_source_set(&source, timestamp, hash(STRING_ARGS(param)),
				                    platform, STRING_ARGS(namestr));

				param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_dim_%" PRIsize),
				                      parameter);
				resource_source_set(&source, timestamp, hash(STRING_ARGS(param)),
				                    platform, STRING_ARGS(dimstr));
				++parameter;
			}
		}

		begin = string_find_first_not_of(blob, size, STRING_CONST(STRING_WHITESPACE), next);
	}
	while (next != STRING_NPOS);

	valstr = string_from_uint_static(parameter, false, 0, 0);
	resource_source_set(&source, timestamp, HASH_PARAMETER_COUNT,
	                    platform, STRING_ARGS(valstr));

	resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE,
	                    0, type, type_length);

	if (!resource_source_write(&source, uuid, false)) {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported GLSL shader: %.*s"),
		          STRING_FORMAT(uuidstr));
		ret = -1;
		goto finalize;
	}
	else {
		string_const_t uuidstr = string_from_uuid_static(uuid);
		log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported GLSL shader: %.*s"),
		          STRING_FORMAT(uuidstr));
	}

finalize:
	memory_deallocate(blob);
	memory_deallocate(token);
	resource_source_finalize(&source);

	return ret;
}
Ejemplo n.º 30
0
int
process_wait(process_t* proc) {
#if FOUNDATION_PLATFORM_POSIX
	int cstatus;
	pid_t ret;
#endif

#if FOUNDATION_PLATFORM_WINDOWS

	if (!proc->hp)
		return proc->code;

	while (GetExitCodeProcess(proc->hp, (LPDWORD)&proc->code)) {
		if ((proc->code != (int)STILL_ACTIVE) || (proc->flags & PROCESS_DETACHED))
			break;
		thread_sleep(50);
		proc->code = -1;
	}

	if ((proc->code == (int)STILL_ACTIVE) && (proc->flags & PROCESS_DETACHED))
		return PROCESS_STILL_ACTIVE;

	if (proc->ht)
		CloseHandle(proc->ht);
	if (proc->hp)
		CloseHandle(proc->hp);

	proc->hp = 0;
	proc->ht = 0;

#elif FOUNDATION_PLATFORM_POSIX

	if (!proc->pid)
		return proc->code;

#  if FOUNDATION_PLATFORM_MACOSX
	if (proc->flags & PROCESS_MACOSX_USE_OPENAPPLICATION) {
		if (proc->kq) {
			struct kevent event;
			ret = kevent(proc->kq, 0, 0, &event, 1, 0);
			if (ret != 1) {
				int err = errno;
				string_const_t errmsg = system_error_message(err);
				log_warnf(0, WARNING_SYSTEM_CALL_FAIL,
				          STRING_CONST("Unable to wait on process, failed to read event from kqueue: %.*s (%d)"),
				          STRING_FORMAT(errmsg), err);
			}

			close(proc->kq);
			proc->kq = 0;
		}
		else {
			log_warn(0, WARNING_INVALID_VALUE,
			         STRING_CONST("Unable to wait on a process started with PROCESS_MACOSX_USE_OPENAPPLICATION and no kqueue"));
			return PROCESS_WAIT_FAILED;
		}
		proc->pid = 0;
		proc->code = 0;
		return proc->code;
	}
#  endif

	cstatus = 0;
	ret = waitpid(proc->pid, &cstatus, (proc->flags & PROCESS_DETACHED) ? WNOHANG : 0);
	if (ret > 0) {
		if (WIFEXITED(cstatus))
			proc->code = (int)((char)WEXITSTATUS(cstatus));
		else if (WIFSIGNALED(cstatus)) {
			proc->code = PROCESS_TERMINATED_SIGNAL;
#ifdef WCOREDUMP
			//if( WCOREDUMP( cstatus ) )
			//...
#endif
			//proc->signal = WTERMSIG( cstatus );
		}
		else {
			proc->code = PROCESS_WAIT_FAILED;
		}
		proc->pid = 0;
	}
	else {
		int err = errno;
		if ((ret == 0) && (proc->flags & PROCESS_DETACHED))
			return PROCESS_STILL_ACTIVE;
		if ((ret < 0) && (err == EINTR))
			return PROCESS_WAIT_INTERRUPTED;
		string_const_t errmsg = system_error_message(err);
		log_warnf(0, WARNING_INVALID_VALUE, STRING_CONST("waitpid(%d) failed: %.*s (%d) (returned %d)"),
		          proc->pid, STRING_FORMAT(errmsg), err, ret);
		return PROCESS_WAIT_FAILED;
	}

#elif FOUNDATION_PLATFORM_PNACL
	//Not supported
#else
#error Not implemented
#endif

	return proc->code;
}