static void* objectmap_thread(void* arg) { objectmap_t* map; object_base_t* objects; int obj; int loop; object_base_t* lookup; map = arg; objects = memory_allocate(0, sizeof(object_base_t) * 512, 16, MEMORY_PERSISTENT | MEMORY_ZERO_INITIALIZED); thread_sleep(10); for (loop = 0; loop < 32; ++loop) { thread_yield(); for (obj = 0; obj < 512; ++obj) { atomic_store32(&objects[obj].ref, 1); objects[obj].id = objectmap_reserve(map); EXPECT_NE_MSGFORMAT(objects[obj].id, 0, "Unable to reserve slot for object num %d", obj); EXPECT_EQ_MSGFORMAT(objectmap_lookup(map, objects[obj].id), 0, "Object %d (%" PRIx64 ") already stored in map in loop %d", obj, objects[obj].id, loop); EXPECT_TRUE(objectmap_set(map, objects[obj].id, objects + obj)); lookup = objectmap_lookup(map, objects[obj].id); EXPECT_NE_MSGFORMAT(lookup, 0, "Object num %d (%" PRIx64 ") not set in map, got null on lookup in loop %d", obj, objects[obj].id, loop); EXPECT_EQ_MSGFORMAT(lookup, objects + obj, "Object %d (%" PRIx64 ") 0x%" PRIfixPTR " was not set at reserved slot in map, got object 0x%" PRIfixPTR " in loop %d", obj, objects[obj].id, (uintptr_t)(objects + obj), (uintptr_t)lookup, loop); } thread_yield(); for (obj = 0; obj < 512; ++obj) { void* raw = map->map[ objects[obj].id & map->mask_index ]; lookup = objectmap_lookup(map, objects[obj].id); EXPECT_NE_MSGFORMAT(lookup, 0, "Object 0x%" PRIfixPTR " num %d (%" PRIx64 ") not set in map, got null on lookup in loop %d (raw 0x%" PRIfixPTR ")", (uintptr_t)(objects + obj), obj, objects[obj].id, loop, (uintptr_t)raw); EXPECT_EQ_MSGFORMAT(lookup, objects + obj, "Object %d (%" PRIx64 ") 0x%" PRIfixPTR " was not set at reserved slot in map, got object 0x%" PRIfixPTR " in loop %d", obj, objects[obj].id, (uintptr_t)(objects + obj), (uintptr_t)lookup, loop); EXPECT_TRUE(objectmap_free(map, objects[obj].id)); lookup = objectmap_lookup(map, objects[obj].id); EXPECT_EQ_MSGFORMAT(lookup, 0, "Object %d (%" PRIx64 ") 0x%" PRIfixPTR " still set in map, got non-null (0x%" PRIfixPTR ") on lookup in loop %d", obj, objects[obj].id, (uintptr_t)(objects + obj), (uintptr_t)lookup, loop); } } memory_deallocate(objects); return 0; }
object_t render_vertexbuffer_create(render_backend_t* backend, render_usage_t usage, size_t vertices, const render_vertex_decl_t* decl, const void* data) { object_t id = objectmap_reserve(_render_map_buffer); if (!id) { log_error(HASH_RENDER, ERROR_OUT_OF_MEMORY, STRING_CONST("Unable to allocate vertex buffer, out of slots in object map")); return 0; } memory_context_push(HASH_RENDER); render_vertexbuffer_t* buffer = memory_allocate(HASH_RENDER, sizeof(render_vertexbuffer_t), 0, MEMORY_PERSISTENT | MEMORY_ZERO_INITIALIZED); buffer->id = id; buffer->backend = backend; buffer->usage = usage; buffer->buffertype = RENDERBUFFER_VERTEX; buffer->policy = RENDERBUFFER_UPLOAD_ONDISPATCH; buffer->size = decl->size; memcpy(&buffer->decl, decl, sizeof(render_vertex_decl_t)); atomic_store32(&buffer->ref, 1); objectmap_set(_render_map_buffer, id, buffer); if (vertices) { buffer->allocated = vertices; buffer->used = vertices; buffer->store = backend->vtable.allocate_buffer(backend, (render_buffer_t*)buffer); if (data) { memcpy(buffer->store, data, vertices * buffer->size); buffer->flags |= RENDERBUFFER_DIRTY; } } memory_context_pop(); return id; }
DECLARE_TEST(objectmap, store) { objectmap_t* map; object_base_t first; object_base_t second; object_base_t third; map = objectmap_allocate(129); memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(first)); memset(&third, 0, sizeof(first)); atomic_store32(&first.ref, 1); atomic_store32(&second.ref, 1); atomic_store32(&third.ref, 1); first.id = 1; second.id = 2; third.id = 3; EXPECT_EQ(objectmap_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, 1), 0); first.id = objectmap_reserve(map); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); second.id = objectmap_reserve(map); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); objectmap_set(map, first.id, &first); EXPECT_EQ(objectmap_lookup(map, first.id), &first); EXPECT_EQ(objectmap_raw_lookup(map, 0), &first); EXPECT_EQ(objectmap_lookup(map, second.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); objectmap_set(map, second.id, &second); EXPECT_EQ(objectmap_lookup(map, first.id), &first); EXPECT_EQ(objectmap_raw_lookup(map, 0), &first); EXPECT_EQ(objectmap_lookup(map, second.id), &second); EXPECT_EQ(objectmap_raw_lookup(map, 1), &second); objectmap_free(map, first.id); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), &second); EXPECT_EQ(objectmap_raw_lookup(map, 1), &second); objectmap_free(map, first.id); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), &second); EXPECT_EQ(objectmap_raw_lookup(map, 1), &second); objectmap_free(map, second.id); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); objectmap_deallocate(map); //Size should be clamped to three map = objectmap_allocate(1); EXPECT_EQ(objectmap_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, 1), 0); first.id = objectmap_reserve(map); EXPECT_TYPENE(first.id, 0, object_t, PRIx64); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); second.id = objectmap_reserve(map); EXPECT_TYPENE(second.id, 0, object_t, PRIx64); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); third.id = objectmap_reserve(map); EXPECT_TYPENE(third.id, 0, object_t, PRIx64); EXPECT_EQ(objectmap_lookup(map, first.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup(map, second.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); EXPECT_EQ(objectmap_lookup(map, third.id), 0); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); objectmap_set(map, first.id, &first); objectmap_set(map, second.id, &second); objectmap_set(map, third.id, &third); log_enable_stdout(false); EXPECT_TYPEEQ(objectmap_reserve(map), 0, object_t, PRIx64); EXPECT_TYPEEQ(objectmap_reserve(map), 0, object_t, PRIx64); log_enable_stdout(true); objectmap_free(map, first.id); objectmap_free(map, second.id); //Leak one object //objectmap_free(map, third.id); EXPECT_EQ(objectmap_lookup_ref(map, first.id), nullptr); EXPECT_EQ(objectmap_raw_lookup(map, 0), 0); EXPECT_EQ(objectmap_lookup_ref(map, second.id), nullptr); EXPECT_EQ(objectmap_raw_lookup(map, 1), 0); EXPECT_NE(objectmap_lookup_ref(map, third.id), nullptr); EXPECT_NE(objectmap_raw_lookup(map, 2), 0); log_enable_stdout(false); objectmap_deallocate(map); log_enable_stdout(true); return 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; }