#include "moar.h" int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) { char *cpath; DLLib *lib; if (!MVM_str_hash_key_is_valid(tc, name)) { MVM_str_hash_key_throw_invalid(tc, name); } uv_mutex_lock(&tc->instance->mutex_dll_registry); MVMDLLRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->dll_registry, name); /* already loaded */ if (entry && entry->lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 0; } MVMROOT2(tc, name, path, { path = MVM_file_in_libpath(tc, path); }); cpath = MVM_string_utf8_c8_encode_C_string(tc, path); lib = MVM_nativecall_load_lib(cpath); if (!lib) { char *waste[] = { cpath, NULL }; uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc_free(tc, waste, "failed to load library '%s'", cpath); } MVM_free(cpath); if (!entry) { entry = MVM_fixkey_hash_insert_nocheck(tc, &tc->instance->dll_registry, name); entry->refcount = 0; MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_key, "DLL name hash key"); } entry->lib = lib; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 1; } int MVM_dll_free(MVMThreadContext *tc, MVMString *name) { if (!MVM_str_hash_key_is_valid(tc, name)) { MVM_str_hash_key_throw_invalid(tc, name); } uv_mutex_lock(&tc->instance->mutex_dll_registry); MVMDLLRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->dll_registry, name); if (!entry) { char *c_name = MVM_string_utf8_encode_C_string(tc, name); char *waste[] = { c_name, NULL }; uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc_free(tc, waste, "cannot free non-existent library '%s'", c_name); } /* already freed */ if (!entry->lib) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 0; } if (entry->refcount > 0) { char *c_name = MVM_string_utf8_encode_C_string(tc, name); char *waste[] = { c_name, NULL }; uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc_free(tc, waste, "cannot free in-use library '%s'", c_name); } MVM_nativecall_free_lib(entry->lib); entry->lib = NULL; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return 1; } MVMObject * MVM_dll_find_symbol(MVMThreadContext *tc, MVMString *lib, MVMString *sym) { MVMDLLSym *obj; char *csym; void *address; if (!MVM_str_hash_key_is_valid(tc, lib)) { MVM_str_hash_key_throw_invalid(tc, lib); } uv_mutex_lock(&tc->instance->mutex_dll_registry); MVMDLLRegistry *entry = MVM_fixkey_hash_fetch_nocheck(tc, &tc->instance->dll_registry, lib); if (!entry) { char *c_lib = MVM_string_utf8_encode_C_string(tc, lib); char *waste[] = { c_lib, NULL }; uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc_free(tc, waste, "cannot find symbol '%s' in non-existent library", c_lib); } if (!entry->lib) { char *c_lib = MVM_string_utf8_encode_C_string(tc, lib); char *waste[] = { c_lib, NULL }; uv_mutex_unlock(&tc->instance->mutex_dll_registry); MVM_exception_throw_adhoc_free(tc, waste, "cannot find symbol '%s' in unloaded library", c_lib); } csym = MVM_string_utf8_c8_encode_C_string(tc, sym); address = MVM_nativecall_find_sym(entry->lib, csym); MVM_free(csym); if (!address) { uv_mutex_unlock(&tc->instance->mutex_dll_registry); return NULL; } obj = (MVMDLLSym *)MVM_repr_alloc_init(tc, tc->instance->raw_types.RawDLLSym); obj->body.address = address; obj->body.dll = entry; entry->refcount++; uv_mutex_unlock(&tc->instance->mutex_dll_registry); return (MVMObject *)obj; } void MVM_dll_drop_symbol(MVMThreadContext *tc, MVMObject *obj) { MVMDLLSym *sym; MVMDLLRegistry *dll; if (REPR(obj)->ID != MVM_REPR_ID_MVMDLLSym) MVM_exception_throw_adhoc(tc, "unexpected object with REPR other than MVMDLLSym"); sym = (MVMDLLSym *)obj; dll = sym->body.dll; if (!dll) return; MVM_decr(&dll->refcount); sym->body.address = NULL; sym->body.dll = NULL; }