Example #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;
}
Example #2
0
void
mutex_signal(mutex_t* mutex) {
#if !BUILD_DEPLOY
	profile_signal(mutex->name.str, mutex->name.length);
#endif

#if FOUNDATION_PLATFORM_WINDOWS

	SetEvent(mutex->event);

#elif FOUNDATION_PLATFORM_POSIX || FOUNDATION_PLATFORM_PNACL

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

	int ret = pthread_cond_broadcast(&mutex->cond);
	if (ret != 0) {
		string_const_t errmsg = system_error_message(ret);
		log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to signal mutex '%.*s': %.*s (%d)"),
		           STRING_FORMAT(mutex->name), STRING_FORMAT(errmsg), ret);
	}

	mutex_unlock(mutex);

#else
#  error mutex_signal not implemented
#endif
}
const char* environment_current_working_directory( void )
{
	if( _environment_current_working_dir[0] )
		return _environment_current_working_dir;
#if FOUNDATION_PLATFORM_WINDOWS
	{
		char* path;
		wchar_t* wd = memory_allocate_zero( sizeof( wchar_t ) * FOUNDATION_MAX_PATHLEN, 0, MEMORY_TEMPORARY );
		GetCurrentDirectoryW( FOUNDATION_MAX_PATHLEN-1, wd );
		path = path_clean( string_allocate_from_wstring( wd, 0 ), true );
		string_copy( _environment_current_working_dir, path, FOUNDATION_MAX_PATHLEN );
		string_copy( _environment_current_working_dir, path, FOUNDATION_MAX_PATHLEN );
		string_deallocate( path );
		memory_deallocate( wd );
	}
#elif FOUNDATION_PLATFORM_POSIX
	char* path = memory_allocate_zero( FOUNDATION_MAX_PATHLEN, 0, MEMORY_TEMPORARY );
	if( !getcwd( path, FOUNDATION_MAX_PATHLEN ) )
	{
		log_errorf( ERROR_SYSTEM_CALL_FAIL, "Unable to get cwd: %s", system_error_message( 0 ) );
		return "";
	}
	path = path_clean( path, true );
	string_copy( _environment_current_working_dir, path, FOUNDATION_MAX_PATHLEN );
	memory_deallocate( path );
#else
#  error Not implemented
#endif
	return _environment_current_working_dir;
}
Example #4
0
static void* _memory_reallocate_malloc( void* p, uint64_t size, unsigned int align )
{
	align = _memory_get_align( align );
#if FOUNDATION_PLATFORM_WINDOWS
	return _aligned_realloc( p, (size_t)size, align );
#else
	if( align )
	{
		//No realloc aligned available
		void* memory = aligned_alloc( align, (size_t)size );
		if( !memory )
		{
			log_panicf( ERROR_OUT_OF_MEMORY, "Unable to reallocate memory: %s", system_error_message( 0 ) );
			return 0;
		}
		if( p )
		{
			size_t prev_size = malloc_usable_size( p );
			memcpy( memory, p, ( size < prev_size ) ? size : prev_size );
		}
		return memory;
	}
	return realloc( p, (size_t)size );
#endif
}
Example #5
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;
}
Example #6
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;
}
Example #7
0
/*
 * Wrapper around openvpn_execve
 */
bool
openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
{
  struct gc_arena gc = gc_new ();
  const int stat = openvpn_execve (a, es, flags);
  int ret = false;

  if (platform_system_ok (stat))
    ret = true;
  else
    {
      if (error_message)
	msg (((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s",
	     error_message,
	     system_error_message (stat, &gc));
    }
  gc_free (&gc);
  return ret;
}
Example #8
0
static void* _memory_allocate_malloc( uint16_t context, uint64_t size, unsigned int align, memory_hint_t hint )
{
	align = _memory_get_align( align );
#if FOUNDATION_PLATFORM_WINDOWS
	return _aligned_malloc( (size_t)size, align );
#elif FOUNDATION_PLATFORM_POSIX && !FOUNDATION_PLATFORM_ANDROID
	void* memory = 0;
	if( !align )
		return malloc( (size_t)size );
	/*int result = posix_memalign( &memory, align, (size_t)size );	
	if( result || !memory )
		log_panicf( ERROR_OUT_OF_MEMORY, "Unable to allocate memory: %s", system_error_message( 0 ) );
	return ( result == 0 ) ? memory : 0;*/
	memory = aligned_alloc( align, (size_t)size );
	if( !memory )
		log_panicf( ERROR_OUT_OF_MEMORY, "Unable to allocate memory: %s", system_error_message( 0 ) );
	return memory;
#else
	void* memory = malloc( size + align );
	memory = _memory_align_pointer( memory, align );
	return memory;
#endif
}
Example #9
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;
}
Example #10
0
bool
mutex_try_wait(mutex_t* mutex, unsigned int milliseconds) {
#if FOUNDATION_PLATFORM_WINDOWS
	DWORD ret;
#elif FOUNDATION_PLATFORM_POSIX || FOUNDATION_PLATFORM_PNACL
	struct timeval now;
	struct timespec then;
#endif
#if FOUNDATION_PLATFORM_WINDOWS

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

	atomic_incr32(&mutex->waiting);

	ret = WaitForSingleObject(mutex->event, milliseconds);

	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 || FOUNDATION_PLATFORM_PNACL

	mutex_lock(mutex);

	if (mutex->pending) {
		mutex->pending = false;
		return true;
	}
	if (!milliseconds) {
		mutex_unlock(mutex);
		return false;
	}

	--mutex->lockcount;

	bool was_signal = false;
	if (milliseconds == 0xFFFFFFFF) {
		int ret = pthread_cond_wait(&mutex->cond, &mutex->mutex);
		if (ret == 0) {
			was_signal = true;
		}
		else {
			string_const_t errmsg = system_error_message(ret);
			log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to wait on mutex '%.*s': %.*s (%d)"),
			           STRING_FORMAT(mutex->name), STRING_FORMAT(errmsg), ret);
		}
	}
	else {
		int ret;
		gettimeofday(&now, 0);
		then.tv_sec  = now.tv_sec + (time_t)(milliseconds / 1000);
		then.tv_nsec = (now.tv_usec * 1000) + (long)(milliseconds % 1000) * 1000000L;
		while (then.tv_nsec >= 1000000000L) {
			++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) {
			string_const_t errmsg = system_error_message(ret);
			log_errorf(0, ERROR_SYSTEM_CALL_FAIL,
			           STRING_CONST("Unable to wait (timed) on mutex '%.*s': %.*s (%d)"),
			           STRING_FORMAT(mutex->name), STRING_FORMAT(errmsg), 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
}
Example #11
0
static void*
_memory_reallocate_malloc(void* p, size_t size, unsigned  int align, size_t oldsize) {
#if ( FOUNDATION_SIZE_POINTER == 4 ) && FOUNDATION_PLATFORM_WINDOWS
	FOUNDATION_UNUSED(oldsize);
	align = _memory_get_align(align);
#  if BUILD_ENABLE_MEMORY_GUARD
	if (p) {
		p = _memory_guard_verify(p);
		p = _aligned_realloc(p, (size_t)size + FOUNDATION_MAX_ALIGN * 3, align);
	}
	else {
		p = _aligned_malloc((size_t)size + FOUNDATION_MAX_ALIGN * 3, align);
	}
	if (p)
		p = _memory_guard_initialize(p, (size_t)size);
	return p;
#  else
	return _aligned_realloc(p, (size_t)size, align);
#  endif
#else
	void* memory;
	void* raw_p;

	align = _memory_get_align(align);

	memory = p;
#  if BUILD_ENABLE_MEMORY_GUARD
	if (memory)
		memory = _memory_guard_verify(memory);
#  endif
	raw_p = memory ? *((void**)memory - 1) : nullptr;
	memory = nullptr;

#if FOUNDATION_PLATFORM_WINDOWS
	if (raw_p && !((uintptr_t)raw_p & 1)) {
		size_t padding = (align > FOUNDATION_SIZE_POINTER ? align : FOUNDATION_SIZE_POINTER);
#  if BUILD_ENABLE_MEMORY_GUARD
		size_t extra_padding = FOUNDATION_MAX_ALIGN * 3;
#  else
		size_t extra_padding = 0;
#  endif
		void* raw_memory = _aligned_realloc(raw_p, size + padding + extra_padding, align ? align : 8);
		if (raw_memory) {
			memory = pointer_offset(raw_memory, padding);
			*((void**)memory - 1) = raw_memory;
#  if BUILD_ENABLE_MEMORY_GUARD
			memory = _memory_guard_initialize(memory, size);
#  endif
		}
	}
	else {
#  if FOUNDATION_SIZE_POINTER == 4
		memory = _memory_allocate_malloc_raw(size, align, 0U);
#  else
		memory = _memory_allocate_malloc_raw(size, align,
		                                     (raw_p && ((uintptr_t)raw_p < 0xFFFFFFFFULL)) ?
		                                       MEMORY_32BIT_ADDRESS : 0U);
#  endif
		if (p && memory && oldsize)
			memcpy(memory, p, (size < oldsize) ? size : oldsize);
		_memory_deallocate_malloc(p);
	}

#else //!FOUNDATION_PLATFORM_WINDOWS

//If we're on ARM the realloc can return a 16-bit aligned address, causing raw pointer store to SIGILL
//Realigning does not work since the realloc memory copy preserve cannot be done properly. Revert to normal alloc-and-copy
//Same with alignment, since we cannot guarantee that the returned memory block offset from start of actual memory block
//is the same in the reallocated block as the original block, we need to alloc-and-copy to get alignment
//Memory guard introduces implicit alignments as well so alloc-and-copy for that
#if !FOUNDATION_ARCH_ARM && !FOUNDATION_ARCH_ARM_64 && !BUILD_ENABLE_MEMORY_GUARD
	if (!align && raw_p && !((uintptr_t)raw_p & 1)) {
		void* raw_memory = realloc(raw_p, (size_t)size + FOUNDATION_SIZE_POINTER);
		if (raw_memory) {
			*(void**)raw_memory = raw_memory;
			memory = pointer_offset(raw_memory, FOUNDATION_SIZE_POINTER);
		}
	}
	else
#endif
	{
#  if FOUNDATION_SIZE_POINTER == 4
#    if !BUILD_ENABLE_LOG
		FOUNDATION_UNUSED(raw_p);
#    endif
		memory = _memory_allocate_malloc_raw(size, align, 0U);
#  else
		memory = _memory_allocate_malloc_raw(size, align,
		                                     (raw_p && ((uintptr_t)raw_p < 0xFFFFFFFFULL)) ?
		                                       MEMORY_32BIT_ADDRESS : 0U);
#  endif
		if (p && memory && oldsize)
			memcpy(memory, p, (size < oldsize) ? (size_t)size : (size_t)oldsize);
		_memory_deallocate_malloc(p);
	}

#endif

	if (!memory) {
		string_const_t errmsg = system_error_message(0);
		log_panicf(HASH_MEMORY, ERROR_OUT_OF_MEMORY,
		           STRING_CONST("Unable to reallocate memory (%" PRIsize " -> %" PRIsize " @ 0x%" PRIfixPTR ", raw 0x%" PRIfixPTR "): %.*s"),
		           oldsize, size, (uintptr_t)p, (uintptr_t)raw_p, STRING_FORMAT(errmsg));
	}

	return memory;
#endif
}
Example #12
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 );
}
Example #13
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);
}
Example #14
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
}
Example #15
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
}
Example #16
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, (nfds_t)pollobj->num_sockets, (int)timeoutms);

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	int ret = epoll_wait(pollobj->fd_poll, pollobj->events,
	                     (int)pollobj->num_sockets + 1, (int)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;
		if (fd != NETWORK_SOCKET_INVALID) {
			socket_t* sock = pollobj->slots[islot].sock;

			FD_SET(fd, &fdread);
			if (sock->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,
		             (timeoutms != NETWORK_TIMEOUT_INFINITE) ? &tv : nullptr);
	}

#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 islot = 0; islot < pollobj->num_sockets; ++islot, ++pfd, ++slot) {
		socket_t* sock = slot->sock;
		bool update_slot = false;
		bool had_error = false;
		if (pfd->revents & POLLERR) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (pfd->revents & POLLHUP) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (!had_error && (pfd->revents & POLLIN)) {
			if (sock->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 (!had_error && (sock->state == SOCKETSTATE_CONNECTING) && (pfd->revents & POLLOUT)) {
			int serr = 0;
			socklen_t slen = sizeof(int);
			getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&serr, &slen);
			if (!serr) {
				sock->state = SOCKETSTATE_CONNECTED;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
			}
			else {
				had_error = true;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
				socket_close(sock);
			}
			update_slot = true;
		}
		if (update_slot)
			network_poll_update_slot(pollobj, islot, sock);
	}

#elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_ANDROID

	struct epoll_event* event = pollobj->events;
	for (int i = 0; i < num_polled; ++i, ++event) {
		socket_t* sock = pollobj->slots[ event->data.fd ].sock;
		bool update_slot = false;
		bool had_error = false;
		if (event->events & EPOLLERR) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
			socket_close(sock);
		}
		if (event->events & EPOLLHUP) {
			update_slot = true;
			had_error = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (!had_error && (event->events & EPOLLIN)) {
			if (sock->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 (!had_error && (sock->state == SOCKETSTATE_CONNECTING) && (event->events & EPOLLOUT)) {
			int serr = 0;
			socklen_t slen = sizeof(int);
			getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&serr, &slen);
			if (!serr) {
				sock->state = SOCKETSTATE_CONNECTED;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
			}
			else {
				had_error = true;
				network_poll_push_event(events, capacity, num_events, NETWORKEVENT_ERROR, sock);
				socket_close(sock);
			}
			update_slot = true;
		}
		if (update_slot)
			network_poll_update_slot(pollobj, (size_t)event->data.fd, 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;
		bool update_slot = false;

		if (FD_ISSET(fd, &fdread)) {
			if (sock->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 ((sock->state == SOCKETSTATE_CONNECTING) && FD_ISSET(fd, &fdwrite)) {
			update_slot = true;
			sock->state = SOCKETSTATE_CONNECTED;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_CONNECTED, sock);
		}
		if (FD_ISSET(fd, &fderr)) {
			update_slot = true;
			network_poll_push_event(events, capacity, num_events, NETWORKEVENT_HANGUP, sock);
			socket_close(sock);
		}
		if (update_slot)
			network_poll_update_slot(pollobj, islot, sock);
	}
#else
#  error Not implemented
#endif

	return num_events;
}
Example #17
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;
}
Example #18
0
static void*
_memory_allocate_malloc_raw(size_t size, unsigned int align, unsigned int hint) {
	FOUNDATION_UNUSED(hint);

	//If we align manually, we must be able to retrieve the original pointer for passing to free()
	//Thus all allocations need to go through that path

#if FOUNDATION_PLATFORM_WINDOWS

#  if FOUNDATION_SIZE_POINTER == 4
#    if BUILD_ENABLE_MEMORY_GUARD
	char* memory = _aligned_malloc((size_t)size + FOUNDATION_MAX_ALIGN * 3, align);
	if (memory)
		memory = _memory_guard_initialize(memory, (size_t)size);
	return memory;
#    else
	return _aligned_malloc((size_t)size, align);
#    endif
#  else
	unsigned int padding, extra_padding = 0;
	size_t allocate_size;
	char* raw_memory;
	void* memory;
	long vmres;

	if (!(hint & MEMORY_32BIT_ADDRESS)) {
		padding = (align > FOUNDATION_SIZE_POINTER ? align : FOUNDATION_SIZE_POINTER);
#if BUILD_ENABLE_MEMORY_GUARD
		extra_padding = FOUNDATION_MAX_ALIGN * 3;
#endif
		raw_memory = _aligned_malloc((size_t)size + padding + extra_padding, align);
		if (raw_memory) {
			memory = raw_memory +
			         padding; //Will be aligned since padding is multiple of alignment (minimum align/pad is pointer size)
			*((void**)memory - 1) = raw_memory;
			FOUNDATION_ASSERT(!((uintptr_t)raw_memory & 1));
			FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#if BUILD_ENABLE_MEMORY_GUARD
			memory = _memory_guard_initialize(memory, size);
			FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#endif
			return memory;
		}
		log_errorf(HASH_MEMORY, ERROR_OUT_OF_MEMORY, STRING_CONST("Unable to allocate %" PRIsize " bytes of memory"), size);
		return 0;
	}

#    if BUILD_ENABLE_MEMORY_GUARD
	extra_padding = FOUNDATION_MAX_ALIGN * 3;
#    endif

	allocate_size = size + FOUNDATION_SIZE_POINTER + extra_padding + align;
	raw_memory = 0;

	vmres = NtAllocateVirtualMemory(INVALID_HANDLE_VALUE, &raw_memory, 1, &allocate_size,
	                                MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	if (vmres != 0) {
		log_errorf(HASH_MEMORY, ERROR_OUT_OF_MEMORY,
		           STRING_CONST("Unable to allocate %" PRIsize " bytes of memory in low 32bit address space"), size);
		return 0;
	}

	memory = _memory_align_pointer(raw_memory + FOUNDATION_SIZE_POINTER, align);
	*((void**)memory - 1) = (void*)((uintptr_t)raw_memory | 1);
#    if BUILD_ENABLE_MEMORY_GUARD
	memory = _memory_guard_initialize(memory, size);
#    endif
	FOUNDATION_ASSERT(!((uintptr_t)raw_memory & 1));
	FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
	return memory;
#  endif

#else

#  if FOUNDATION_SIZE_POINTER > 4
	if (!(hint & MEMORY_32BIT_ADDRESS))
#  endif
	{
#if BUILD_ENABLE_MEMORY_GUARD
		size_t extra_padding = FOUNDATION_MAX_ALIGN * 3;
#else
		size_t extra_padding = 0;
#endif
		size_t allocate_size = size + align + FOUNDATION_SIZE_POINTER + extra_padding;
		char* raw_memory = malloc(allocate_size);
		if (raw_memory) {
			void* memory = _memory_align_pointer(raw_memory + FOUNDATION_SIZE_POINTER, align);
			*((void**)memory - 1) = raw_memory;
			FOUNDATION_ASSERT(!((uintptr_t)raw_memory & 1));
			FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#if BUILD_ENABLE_MEMORY_GUARD
			memory = _memory_guard_initialize(memory, size);
			FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#endif
			return memory;
		}
		log_errorf(HASH_MEMORY, ERROR_OUT_OF_MEMORY,
		           STRING_CONST("Unable to allocate %" PRIsize " bytes of memory (%" PRIsize " requested)"), size,
		           allocate_size);
		return 0;
	}

#  if FOUNDATION_SIZE_POINTER > 4

	size_t allocate_size;
	char* raw_memory;
	void* memory;

#    if BUILD_ENABLE_MEMORY_GUARD
	unsigned int extra_padding = FOUNDATION_MAX_ALIGN * 3;
#else
	unsigned int extra_padding = 0;
#    endif

	allocate_size = size + align + FOUNDATION_SIZE_POINTER * 2 + extra_padding;

#ifndef MAP_UNINITIALIZED
#define MAP_UNINITIALIZED 0
#endif

#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

#    ifndef MAP_32BIT
	//On MacOSX app needs to be linked with -pagezero_size 10000 -image_base 100000000 to
	// 1) Free up low 4Gb address range by reducing page zero size
	// 2) Move executable base address above 4Gb to free up more memory address space
#define MMAP_REGION_START ((uintptr_t)0x10000)
#define MMAP_REGION_END   ((uintptr_t)0x80000000)
	static atomicptr_t baseaddr = { (void*)MMAP_REGION_START };
	bool retried = false;
	do {
		raw_memory = mmap(atomic_loadptr(&baseaddr), allocate_size, PROT_READ | PROT_WRITE,
		                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0);
		if (((uintptr_t)raw_memory >= MMAP_REGION_START) &&
		    (uintptr_t)(raw_memory + allocate_size) < MMAP_REGION_END) {
			atomic_storeptr(&baseaddr, pointer_offset(raw_memory, allocate_size));
			break;
		}
		if (raw_memory && (raw_memory != MAP_FAILED)) {
			if (munmap(raw_memory, allocate_size) < 0)
				log_warn(HASH_MEMORY, WARNING_SYSTEM_CALL_FAIL,
				         STRING_CONST("Failed to munmap pages outside 32-bit range"));
		}
		raw_memory = 0;
		if (retried)
			break;
		retried = true;
		atomic_storeptr(&baseaddr, (void*)MMAP_REGION_START);
	}
	while (true);
#    else
	raw_memory = mmap(0, allocate_size, PROT_READ | PROT_WRITE,
	                  MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0);
	if (raw_memory == MAP_FAILED) {
		raw_memory = mmap(0, allocate_size, PROT_READ | PROT_WRITE,
	                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0);
		if (raw_memory == MAP_FAILED)
			raw_memory = 0;
		if ((uintptr_t)raw_memory > 0xFFFFFFFFULL) {
			if (munmap(raw_memory, allocate_size) < 0)
				log_warn(HASH_MEMORY, WARNING_SYSTEM_CALL_FAIL,
				         STRING_CONST("Failed to munmap pages outside 32-bit range"));
			raw_memory = 0;
		}
	}
#    endif
	if (!raw_memory) {
		string_const_t errmsg = system_error_message(0);
		log_errorf(HASH_MEMORY, ERROR_OUT_OF_MEMORY,
		           STRING_CONST("Unable to allocate %" PRIsize " bytes of memory in low 32bit address space: %.*s"),
		           size, STRING_FORMAT(errmsg));
		return 0;
	}

	memory = _memory_align_pointer(raw_memory + FOUNDATION_SIZE_POINTER * 2, align);
	*((uintptr_t*)memory - 1) = ((uintptr_t)raw_memory | 1);
	*((uintptr_t*)memory - 2) = (uintptr_t)allocate_size;
	FOUNDATION_ASSERT(!((uintptr_t)raw_memory & 1));
	FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#    if BUILD_ENABLE_MEMORY_GUARD
	memory = _memory_guard_initialize(memory, size);
	FOUNDATION_ASSERT(!((uintptr_t)memory & 1));
#    endif

	return memory;

#  endif

#endif
}
Example #19
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;
}
Example #20
0
object_t library_load( const char* name )
{
	library_t* library;
	hash_t namehash;
	unsigned int i, size;
	uint64_t id;
#if FOUNDATION_PLATFORM_WINDOWS
	char* dllname;
	HANDLE dll;
#endif

	//Locate already loaded library
	library = 0;
	namehash = string_hash( name );
	for( i = 0, size = objectmap_size( _library_map ); i < size; ++i )
	{
		library = objectmap_raw_lookup( _library_map, i );
		if( library && ( library->namehash == namehash ) )
		{
			FOUNDATION_ASSERT( string_equal( library->name, name ) );
			atomic_incr32( &library->ref );
			return library->id;
		}
	}
	
	error_context_push( "loading library", name );

	//Try loading library
#if FOUNDATION_PLATFORM_WINDOWS

	dllname = string_format( "%s.dll", name );
	dll = LoadLibraryA( dllname );
	if( !dll )
	{
#if FOUNDATION_PLATFORM_ARCH_X86
		string_deallocate( dllname );
		dllname = string_format( "%s32.dll", name );
		dll = LoadLibraryA( dllname );
#elif FOUNDATION_PLATFORM_ARCH_X86_64
		string_deallocate( dllname );
		dllname = string_format( "%s64.dll", name );
		dll = LoadLibraryA( dllname );
#endif
	}
	string_deallocate( dllname );
	if( !dll )
	{
		log_warnf( 0, WARNING_SUSPICIOUS, "Unable to load DLL '%s': %s", name, system_error_message( 0 ) );
		error_context_pop();
		return 0;
	}

#elif FOUNDATION_PLATFORM_POSIX

#  if FOUNDATION_PLATFORM_APPLE
	char* libname = string_format( "lib%s.dylib", name );
#  else
	char* libname = string_format( "lib%s.so", name );
#  endif
	void* lib = dlopen( libname, RTLD_LAZY );
	string_deallocate( libname );
#if FOUNDATION_PLATFORM_ANDROID
	if( !lib )
	{
		libname = string_format( "%s/lib%s.so", environment_executable_directory(), name );
		lib = dlopen( libname, RTLD_LAZY );
		string_deallocate( libname );
	}
#endif
	if( !lib )
	{
		log_warnf( 0, WARNING_SUSPICIOUS, "Unable to load dynamic library '%s': %s", name, dlerror() );
		error_context_pop();
		return 0;
	}

#else
	
	log_errorf( 0, ERROR_NOT_IMPLEMENTED, "Dynamic library loading not implemented for this platform: %s", name );
	error_context_pop();
	return 0;

#endif

	id = objectmap_reserve( _library_map );
	if( !id )
	{
#if FOUNDATION_PLATFORM_WINDOWS
		FreeLibrary( dll );
#elif FOUNDATION_PLATFORM_POSIX
		dlclose( lib );
#endif
		log_errorf( 0, ERROR_OUT_OF_MEMORY, "Unable to allocate new library '%s', map full", name );	
		error_context_pop();
		return 0;
	}
	library = memory_allocate_zero( sizeof( library_t ), 0, MEMORY_PERSISTENT );
	library->ref = 1;
	library->id = id;
	library->namehash = string_hash( name );
	string_copy( library->name, name, 32 );
#if FOUNDATION_PLATFORM_WINDOWS
	library->dll = dll;
#elif FOUNDATION_PLATFORM_POSIX
	library->lib = lib;
#endif
	objectmap_set( _library_map, id, library );

	error_context_pop();
	
	return library->id;
}