Ejemplo n.º 1
0
DECLARE_TEST(atomic, cas) {
	size_t num_threads = math_clamp(system_hardware_threads() * 4, 4, 32);
	size_t ithread;
	thread_t threads[32];
	cas_value_t cas_values[32];

	for (ithread = 0; ithread < num_threads; ++ithread) {
		cas_values[ithread].val_32 = (int32_t)ithread;
		cas_values[ithread].val_64 = (int64_t)ithread;
		cas_values[ithread].val_ptr = (void*)(uintptr_t)ithread;
		thread_initialize(&threads[ithread], cas_thread, &cas_values[ithread],
		                  STRING_CONST("cas"), THREAD_PRIORITY_NORMAL, 0);
	}
	for (ithread = 0; ithread < num_threads; ++ithread)
		thread_start(&threads[ithread]);

	test_wait_for_threads_startup(threads, num_threads);
	test_wait_for_threads_finish(threads, num_threads);

	for (ithread = 0; ithread < num_threads; ++ithread)
		thread_finalize(&threads[ithread]);

	EXPECT_EQ(atomic_load32(&val_32), 0);
	EXPECT_EQ(atomic_load64(&val_64), 0);
	EXPECT_EQ(atomic_loadptr(&val_ptr), 0);

	return 0;
}
Ejemplo n.º 2
0
object_t objectmap_reserve( objectmap_t* map )
{
	uint64_t idx, next, id;

	FOUNDATION_ASSERT( map ); /*lint -esym(613,pool) */
	
	//Reserve spot in array
	//TODO: Look into double-ended implementation with allocation from tail and free push to head
	do
	{
		idx = atomic_load64( &map->free );
		if( idx >= map->size )
		{
			log_error( 0, ERROR_OUT_OF_MEMORY, "Pool full, unable to reserve id" );
			return 0;
		}
		next = ((uintptr_t)map->map[idx]) >> 1;
	} while( !atomic_cas64( &map->free, next, idx ) );
	
	//Sanity check that slot isn't taken
	FOUNDATION_ASSERT_MSG( (intptr_t)(map->map[idx]) & 1, "Map failed sanity check, slot taken after reserve" );
	map->map[idx] = 0;
	
	//Allocate ID
	id = 0;
	do
	{
		id = atomic_incr64( &map->id ) & map->id_max; //Wrap-around handled by masking
	} while( !id );

	//Make sure id stays within correct bits (if fails, check objectmap allocation and the mask setup there)
	FOUNDATION_ASSERT( ( ( id << map->size_bits ) & map->mask_id ) == ( id << map->size_bits ) );
	
	return ( id << map->size_bits ) | idx; /*lint +esym(613,pool) */
}
Ejemplo n.º 3
0
void
lua_release_execution_right(lua_t* env) {
	FOUNDATION_ASSERT(atomic_load64(&env->executing_thread) == thread_id());
	FOUNDATION_ASSERT(env->executing_count > 0);
	if (!--env->executing_count) {
		atomic_store64(&env->executing_thread, 0);
		semaphore_post(&env->execution_right);
	}
}
Ejemplo n.º 4
0
void objectmap_free( objectmap_t* map, object_t id )
{
	uint64_t idx, last;

	FOUNDATION_ASSERT( map ); /*lint -esym(613,pool) */
	
	idx = (intptr_t)( id & map->mask_index );
	if( (uintptr_t)map->map[idx] & 1 )
		return; //Already free

	do
	{
		last = atomic_load64( &map->free );
		map->map[idx] = (void*)((uintptr_t)(last<<1)|1);
	} while( !atomic_cas64( &map->free, idx, last ) ); /*lint +esym(613,pool) */
}
Ejemplo n.º 5
0
bool
lua_acquire_execution_right(lua_t* env, bool force) {
	uint64_t self = thread_id();
	if (atomic_load64(&env->executing_thread) == self) {
		++env->executing_count;
		return true;
	}
	if (force) {
		semaphore_wait(&env->execution_right);
		atomic_store64(&env->executing_thread, self);
		FOUNDATION_ASSERT(env->executing_count == 0);
		++env->executing_count;
		return true;
	}
	if (semaphore_try_wait(&env->execution_right, 0)) {
		atomic_store64(&env->executing_thread, self);
		FOUNDATION_ASSERT(env->executing_count == 0);
		++env->executing_count;
		return true;
	}
	return false;
}
Ejemplo n.º 6
0
DECLARE_TEST(atomic, add) {
	size_t num_threads = math_clamp(system_hardware_threads() * 4, 4, 32);
	size_t ithread;
	thread_t threads[32];

	for (ithread = 0; ithread < num_threads; ++ithread)
		thread_initialize(&threads[ithread], add_thread, 0,
		                  STRING_CONST("add"), THREAD_PRIORITY_NORMAL, 0);
	for (ithread = 0; ithread < num_threads; ++ithread)
		thread_start(&threads[ithread]);

	test_wait_for_threads_startup(threads, num_threads);
	test_wait_for_threads_finish(threads, num_threads);

	for (ithread = 0; ithread < num_threads; ++ithread)
		thread_finalize(&threads[ithread]);

	EXPECT_EQ(atomic_load32(&val_32), 0);
	EXPECT_EQ(atomic_load64(&val_64), 0);

	return 0;
}
Ejemplo n.º 7
0
bool
lua_has_execution_right(lua_t* env) {
	return (atomic_load64(&env->executing_thread) == thread_id());
}
Ejemplo n.º 8
0
DECLARE_TEST( profile, stream )
{
	object_t thread[32];
	int ith;
	int frame;
	char* filename;

	error();

	filename = path_merge( environment_temporary_directory(), "test.profile" );
	log_infof( HASH_TEST, "Output to profile file: %s", filename );
	fs_make_directory( environment_temporary_directory() );
	_profile_stream = fs_open_file( filename, STREAM_OUT | STREAM_BINARY );
	string_deallocate( filename );

	profile_initialize( "test_profile", _test_profile_buffer, _test_profile_buffer_size );
	profile_set_output( _profile_file_writer );
	profile_set_output_wait( 10 );
	profile_enable( true );

	for( ith = 0; ith < 32; ++ith )
	{
		thread[ith] = thread_create( _profile_stream_thread, "profile_thread", THREAD_PRIORITY_NORMAL, 0 );
		thread_start( thread[ith], 0 );
	}

	test_wait_for_threads_startup( thread, 32 );

	for( frame = 0; frame < 1000; ++frame )
	{
		thread_sleep( 16 );
		profile_log( "This is a really long profile log line that should break into multiple profile blocks automatically without causing any issues whatsoever if everything works as expected which it should or the code needs to be fixed" );
		profile_end_frame( frame++ );
		if( ( frame % 30 ) == 0 )
		{
			profile_enable( false );
			thread_sleep( 10 );
			profile_enable( true );
		}
	}

	for( ith = 0; ith < 32; ++ith )
	{
		thread_terminate( thread[ith] );
		thread_destroy( thread[ith] );
		thread_yield();
	}

	test_wait_for_threads_exit( thread, 32 );

	profile_end_frame( frame++ );
	profile_set_output_wait( 100 );

	thread_sleep( 1000 );

	profile_enable( false );
	profile_shutdown();

	error();

	stream_deallocate( _profile_stream );

	//TODO: Validate that output is sane
	log_debugf( HASH_TEST, "Generated %lld blocks", atomic_load64( &_profile_generated_blocks ) );

	return 0;
}
Ejemplo n.º 9
0
DECLARE_TEST(profile, stream) {
	thread_t thread[32];
	int ith;
	uint64_t frame;
	string_t filename;

	error(); //Clear error

	filename = path_allocate_concat(STRING_ARGS(environment_temporary_directory()),
	                                STRING_CONST("test.profile"));
	//log_infof(HASH_TEST, STRING_CONST("Output to profile file: %.*s"), STRING_FORMAT(filename));
	fs_make_directory(STRING_ARGS(environment_temporary_directory()));
	_profile_stream = fs_open_file(STRING_ARGS(filename), STREAM_OUT | STREAM_BINARY);
	string_deallocate(filename.str);

	profile_initialize(STRING_CONST("test_profile"), _test_profile_buffer, TEST_PROFILE_BUFFER_SIZE);
	profile_set_output(_profile_file_writer);
	profile_set_output_wait(10);
	profile_enable(true);

	for (ith = 0; ith < 32; ++ith)
		thread_initialize(&thread[ith], _profile_stream_thread, 0, STRING_CONST("profile_thread"),
		                  THREAD_PRIORITY_NORMAL, 0);
	for (ith = 0; ith < 32; ++ith)
		thread_start(&thread[ith]);

	test_wait_for_threads_startup(thread, 32);

	for (frame = 0; frame < 1000; ++frame) {
		thread_sleep(16);
		profile_log(
		    STRING_CONST("This is a really long profile log line that should break into multiple profile blocks automatically without causing any issues whatsoever if everything works as expected which it should or the code needs to be fixed"));
		profile_end_frame(frame++);
		if ((frame % 30) == 0) {
			profile_enable(false);
			thread_sleep(10);
			profile_enable(true);
		}
	}

	for (ith = 0; ith < 32; ++ith)
		thread_signal(&thread[ith]);

	test_wait_for_threads_finish(thread, 32);

	for (ith = 0; ith < 32; ++ith)
		thread_finalize(&thread[ith]);

	profile_end_frame(frame++);
	profile_set_output_wait(10000);

	thread_sleep(1000);

	profile_begin_block(STRING_CONST("Should be cleaned up"));
	profile_end_block();

	profile_enable(false);
	profile_finalize();

	error();

	stream_deallocate(_profile_stream);

//TODO: Validate that output is sane
	log_debugf(HASH_TEST, STRING_CONST("Generated %" PRId64 " blocks"),
	           atomic_load64(&_profile_generated_blocks));

	return 0;
}