Revision 7492483826c746b4038a42eb9f05e2e4bc2f43bf authored by Jeff Bezanson on 28 March 2017, 18:03:56 UTC, committed by Jeff Bezanson on 28 March 2017, 18:03:56 UTC
1 parent 4809620
runtime_ccall.cpp
// This file is a part of Julia. License is MIT: http://julialang.org/license
#include "llvm-version.h"
#include <map>
#include <string>
#include <cstdio>
#include <llvm/Support/Host.h>
#include "fix_llvm_assert.h"
#include "julia.h"
#include "julia_internal.h"
using namespace llvm;
// --- library symbol lookup ---
// map from "libX" to full soname "libX.so.ver"
#if defined(__linux__) || defined(__FreeBSD__)
static uv_rwlock_t soname_lock;
static std::map<std::string, std::string> sonameMap;
static bool got_sonames = false;
extern "C" void jl_init_runtime_ccall(void)
{
uv_rwlock_init(&soname_lock);
}
// This reloads the sonames, necessary after system upgrade.
// Keep this DLLEXPORTed, this is used by `BinDeps.jl` to make sure
// newly installed libraries can be found.
extern "C" JL_DLLEXPORT void jl_read_sonames(void)
{
char *line=NULL;
size_t sz=0;
#if defined(__linux__)
FILE *ldc = popen("/sbin/ldconfig -p", "r");
#else
FILE *ldc = popen("/sbin/ldconfig -r", "r");
#endif
if (ldc == NULL) return; // ignore errors in running ldconfig (other than whatever might have been printed to stderr)
// This loop is not allowed to call julia GC while holding the lock
uv_rwlock_wrlock(&soname_lock);
sonameMap.clear();
while (!feof(ldc)) {
ssize_t n = getline(&line, &sz, ldc);
if (n == -1)
break;
if (n > 2 && isspace((unsigned char)line[0])) {
#ifdef __linux__
int i = 0;
while (isspace((unsigned char)line[++i])) ;
char *name = &line[i];
char *dot = strstr(name, ".so");
i = 0;
#else
char *name = strstr(line, ":-l");
if (name == NULL) continue;
strncpy(name, "lib", 3);
char *dot = strchr(name, '.');
#endif
if (NULL == dot)
continue;
#ifdef __linux__
// Detect if this entry is for the current architecture
while (!isspace((unsigned char)dot[++i])) ;
while (isspace((unsigned char)dot[++i])) ;
int j = i;
while (!isspace((unsigned char)dot[++j])) ;
char *arch = strstr(dot+i,"x86-64");
if (arch != NULL && arch < dot + j) {
#ifdef _P32
continue;
#endif
}
else {
#ifdef _P64
continue;
#endif
}
#endif // __linux__
char *abslibpath = strrchr(line, ' ');
if (dot != NULL && abslibpath != NULL) {
std::string pfx(name, dot - name);
// Do not include ' ' in front and '\n' at the end
std::string soname(abslibpath+1, line+n-(abslibpath+1)-1);
sonameMap[pfx] = soname;
}
}
}
free(line);
pclose(ldc);
uv_rwlock_wrunlock(&soname_lock);
}
// This API is not thread safe. The return value can be free'd if
// `jl_read_sonames()` is called on another thread.
extern "C" JL_DLLEXPORT const char *jl_lookup_soname(const char *pfx, size_t n)
{
if (!got_sonames) {
jl_read_sonames();
got_sonames = true;
}
const char *res = nullptr;
uv_rwlock_rdlock(&soname_lock);
auto search = sonameMap.find(std::string(pfx, n));
if (search != sonameMap.end())
res = search->second.c_str();
uv_rwlock_rdunlock(&soname_lock);
return res;
}
extern "C" void *jl_dlopen_soname(const char *pfx, size_t n, unsigned flags)
{
if (!got_sonames) {
jl_read_sonames();
got_sonames = true;
}
void *res = nullptr;
uv_rwlock_rdlock(&soname_lock);
auto search = sonameMap.find(std::string(pfx, n));
if (search != sonameMap.end())
res = jl_dlopen(search->second.c_str(), flags);
uv_rwlock_rdunlock(&soname_lock);
return res;
}
#else
extern "C" void jl_init_runtime_ccall(void)
{
}
#endif
// map from user-specified lib names to handles
static std::map<std::string, void*> libMap;
static jl_mutex_t libmap_lock;
extern "C"
void *jl_get_library(const char *f_lib)
{
void *hnd;
#ifdef _OS_WINDOWS_
if ((intptr_t)f_lib == 1)
return jl_exe_handle;
if ((intptr_t)f_lib == 2)
return jl_dl_handle;
#endif
if (f_lib == NULL)
return jl_RTLD_DEFAULT_handle;
JL_LOCK_NOGC(&libmap_lock);
// This is the only operation we do on the map, which doesn't invalidate
// any references or iterators.
void **map_slot = &libMap[f_lib];
JL_UNLOCK_NOGC(&libmap_lock);
hnd = jl_atomic_load_acquire(map_slot);
if (hnd != NULL)
return hnd;
// We might run this concurrently on two threads but it doesn't matter.
hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT);
if (hnd != NULL)
jl_atomic_store_release(map_slot, hnd);
return hnd;
}
extern "C" JL_DLLEXPORT
void *jl_load_and_lookup(const char *f_lib, const char *f_name, void **hnd)
{
void *handle = jl_atomic_load_acquire(hnd);
if (!handle)
jl_atomic_store_release(hnd, (handle = jl_get_library(f_lib)));
return jl_dlsym(handle, f_name);
}
// miscellany
extern "C" JL_DLLEXPORT
jl_value_t *jl_get_cpu_name(void)
{
#if JL_LLVM_VERSION >= 30500
StringRef HostCPUName = llvm::sys::getHostCPUName();
#else
const std::string& HostCPUName = llvm::sys::getHostCPUName();
#endif
return jl_pchar_to_string(HostCPUName.data(), HostCPUName.size());
}
extern "C" JL_DLLEXPORT
jl_value_t *jl_get_JIT(void)
{
#if defined(USE_ORCJIT)
const std::string& HostJITName = "ORCJIT";
#elif defined(USE_MCJIT)
const std::string& HostJITName = "MCJIT";
#else
const std::string& HostJITName = "Unknown";
#endif
return jl_pchar_to_string(HostJITName.data(), HostJITName.size());
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...