Skip to content

Commit

Permalink
dlopen revision
Browse files Browse the repository at this point in the history
  • Loading branch information
impact-maker committed Apr 15, 2024
1 parent 2d2f41f commit de9e66b
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 80 deletions.
88 changes: 46 additions & 42 deletions src/library_dylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -1097,42 +1097,36 @@ var LibraryDylink = {
},

// void* dlopen(const char* filename, int flags);
$dlopenInternal__deps: ['$ENV', '$dlSetError', '$PATH'],
$dlopenInternal: (handle, jsflags) => {
// void *dlopen(const char *file, int mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}});
var flags = {{{ makeGetValue('handle', C_STRUCTS.dso.flags, 'i32') }}};
#if DYLINK_DEBUG
dbg(`dlopenInternal: ${filename}`);
#endif
filename = PATH.normalize(filename);
var searchpaths = [];

var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}});
var localScope = global ? null : {};

// We don't care about RTLD_NOW and RTLD_LAZY.
var combinedFlags = {
global,
nodelete: Boolean(flags & {{{ cDefs.RTLD_NODELETE }}}),
loadAsync: jsflags.loadAsync,
}

if (jsflags.loadAsync) {
return loadDynamicLibrary(filename, combinedFlags, localScope, handle);
}

try {
return loadDynamicLibrary(filename, combinedFlags, localScope, handle)
} catch (e) {
#if ASSERTIONS
err(`Error in loading dynamic library ${filename}: ${e}`);
#endif
dlSetError(`Could not load dynamic lib: ${filename}\n${e}`);
return 0;
}
},
$dlopenInternal__deps: ['$loadDynamicLibrary', '$dlSetError', '$PATH'],
$dlopenInternal: function(filename, flags) {

filename = UTF8ToString(filename);
filename = PATH.normalize(filename);

var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}});
var nodelete = Boolean(flags & {{{ cDefs.RTLD_NODELETE }}});

var loadAsync = !!(flags & {{{ cDefs.RTLD_NOW }}});

var promise = loadDynamicLibrary(filename, {
global: global,
nodelete: nodelete,
loadAsync: loadAsync
});

if (loadAsync) {
return promise.then(module => {
var handle = _malloc(4);
{{{ makeSetValue('handle', 0, 'module', 'i32') }}};
return handle;
}).catch(err => {
$dlSetError('Dlopen failed: ' + err.message);
return 0;
});
} else {
return Asyncify.handleSync(promise);
}
},

_dlopen_js__deps: ['$dlopenInternal'],
#if ASYNCIFY
Expand Down Expand Up @@ -1172,13 +1166,23 @@ var LibraryDylink = {
promise.then(successCallback).catch(errorCallback);
},

_emscripten_dlopen_js__deps: ['$dlopenInternal', '$runtimeKeepalivePush', '$runtimeKeepalivePop', '$dlSetError', '$dynCall', '$promiseToCallback'],
_emscripten_dlopen_js: function(handle, onsuccess, onerror, user_data) {
runtimeKeepalivePush();
var promise = dlopenInternal(handle, { loadAsync: true });
_emscripten_dlopen_js__deps: ['$dlopenInternal', '$runtimeKeepalivePush', '$runtimeKeepalivePop', '$dlSetError', '$dynCall'],
_emscripten_dlopen_js: function(handle, promise, onsuccess, onerror,) {

{{{ runtimeKeepalivePush() }}}

var filename = UTF8ToString(handle);
var flags = {{{ makeGetValue('promise', 4, 'i32') }}};

dlopenInternal(filename, flags)
.then(module => {
{{{ makeDynCall('vpp', 'onsuccess') }}}(module, handle);
{{{ runtimeKeepalivePop() }}};
}).catch(err => {
{{{ makeDynCall('vpp', 'onerror') }}}(0, user_data);
{{{ runtimeKeepalivePop() }}};
});

// Utilize the $promiseToCallback utility function
promiseToCallback(promise, onsuccess, onerror, user_data);
},


Expand Down
64 changes: 26 additions & 38 deletions system/lib/libc/dynlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,35 +586,11 @@ void* dlopen(const char* file, int flags) {

void emscripten_dlopen(const char* filename, int flags, void* user_data,
em_dlopen_callback onsuccess, em_arg_callback_func onerror) {
dbg("emscripten_dlopen: %s", filename);
if (!filename) {
onsuccess(user_data, head->dso);
return;
}
do_write_lock();
char buf[2*NAME_MAX+2];
filename = resolve_path(buf, filename, sizeof buf);
struct dso* p = find_existing(filename);
if (p) {
onsuccess(user_data, p);
return;
}
p = load_library_start(filename, flags);
if (!p) {
do_write_unlock();
onerror(user_data);
return;
}

// For async mode
struct async_data* d = malloc(sizeof(struct async_data));
d->user_data = user_data;
d->onsuccess = onsuccess;
d->onerror = onerror;

em_promise_t promise = emscripten_dlopen_promise(filename,flags);
emscripten_promise_then(promise, onsuccess, user_data);
emscripten_promise_catch(promise, onerror, user_data);

dbg("calling emscripten_dlopen_js %p", p);
// Unlock happens in dlopen_onsuccess/dlopen_onerror
_emscripten_dlopen_js(p, dlopen_onsuccess, dlopen_onerror, d);
}

static void promise_onsuccess(void* user_data, void* handle) {
Expand All @@ -636,16 +612,28 @@ static void promise_onerror(void* user_data) {
// TODO(sbc): Consider inverting this and perhaps deprecating/removing
// the old API.
em_promise_t emscripten_dlopen_promise(const char* filename, int flags) {
// Create a promise that is resolved (and destroyed) once the operation
// succeeds.
em_promise_t p = emscripten_promise_create();
emscripten_dlopen(filename, flags, p, promise_onsuccess, promise_onerror);

// Create a second promise bound the first one to return the caller. It's
// then up to the caller to destroy this promise.
em_promise_t ret = emscripten_promise_create();
emscripten_promise_resolve(ret, EM_PROMISE_MATCH, p);
return ret;

if (!filename) {
return emscripten_promise_resolve(EM_PROMISE_FULFILL, RTLD_DEFAULT);
}

struct dso* p = find_existing(filename);

if (p) {
return emscripten_promise_resolve(EM_PROMISE_FULFILL, p);
}

em_promise_t promise = emscripten_promise_create();

p = load_library_start(filename, flags);

if (!p) {
emscripten_promise_reject(promise, NULL);
} else {
_emscripten_dlopen_js(p, promise, dlopen_onsuccess, dlopen_onerror);
}

return promise;
}

void* __dlsym(void* restrict p, const char* restrict s, void* restrict ra) {
Expand Down

0 comments on commit de9e66b

Please sign in to comment.