Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ julia-base: julia-deps $(build_sysconfdir)/julia/startup.jl $(build_man1dir)/jul
julia-libccalltest: julia-deps
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src libccalltest

julia-libccalllazyfoo: julia-deps
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src libccalllazyfoo

julia-libccalllazybar: julia-deps julia-libccalllazyfoo
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src libccalllazybar

julia-libllvmcalltest: julia-deps
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src libllvmcalltest

Expand All @@ -102,7 +108,8 @@ julia-sysimg-bc : julia-stdlib julia-base julia-cli-$(JULIA_BUILD_MODE) julia-sr
julia-sysimg-release julia-sysimg-debug : julia-sysimg-% : julia-sysimg-ji julia-src-%
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT) -f sysimage.mk sysimg-$*

julia-debug julia-release : julia-% : julia-sysimg-% julia-src-% julia-symlink julia-libccalltest julia-libllvmcalltest julia-base-cache
julia-debug julia-release : julia-% : julia-sysimg-% julia-src-% julia-symlink julia-libccalltest \
julia-libccalllazyfoo julia-libccalllazybar julia-libllvmcalltest julia-base-cache

stdlibs-cache-release stdlibs-cache-debug : stdlibs-cache-% : julia-%
@$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT) -f pkgimage.mk all-$*
Expand Down Expand Up @@ -189,7 +196,7 @@ JL_TARGETS := julia-debug
endif

# private libraries, that are installed in $(prefix)/lib/julia
JL_PRIVATE_LIBS-0 := libccalltest libllvmcalltest
JL_PRIVATE_LIBS-0 := libccalltest libccalllazyfoo libccalllazybar libllvmcalltest
ifeq ($(JULIA_BUILD_MODE),release)
JL_PRIVATE_LIBS-0 += libjulia-internal libjulia-codegen
else ifeq ($(JULIA_BUILD_MODE),debug)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Language changes
Compiler/Runtime improvements
-----------------------------
* Updated GC heuristics to count allocated pages instead of individual objects ([#50144]).
* A new `LazyLibrary` type is exported from `Libdl` for use in building chained lazy library
loads, primarily to be used within JLLs ([#50074]).

Command-line option changes
---------------------------
Expand Down
14 changes: 9 additions & 5 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,12 @@ include("missing.jl")
# version
include("version.jl")

# Concurrency (part 1)
include("linked_list.jl")
include("condition.jl")
include("threads.jl")
include("lock.jl")

# system & environment
include("sysinfo.jl")
include("libc.jl")
Expand All @@ -328,11 +334,9 @@ const liblapack_name = libblas_name
include("logging.jl")
using .CoreLogging

# Concurrency
include("linked_list.jl")
include("condition.jl")
include("threads.jl")
include("lock.jl")
# Concurrency (part 2)
# Note that `atomics.jl` here should be deprecated
Core.eval(Threads, :(include("atomics.jl")))
include("channels.jl")
include("partr.jl")
include("task.jl")
Expand Down
148 changes: 141 additions & 7 deletions base/libdl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Base.DL_LOAD_PATH

export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL,
RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e,
dlpath, find_library, dlext, dllist
dlpath, find_library, dlext, dllist, LazyLibrary, LazyLibraryPath, BundledLazyLibraryPath

"""
DL_LOAD_PATH
Expand Down Expand Up @@ -45,6 +45,9 @@ applicable.
"""
(RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL, RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW)

# The default flags for `dlopen()`
const default_rtld_flags = RTLD_LAZY | RTLD_DEEPBIND

"""
dlsym(handle, sym; throw_error::Bool = true)

Expand Down Expand Up @@ -72,8 +75,8 @@ end
Look up a symbol from a shared library handle, silently return `C_NULL` on lookup failure.
This method is now deprecated in favor of `dlsym(handle, sym; throw_error=false)`.
"""
function dlsym_e(hnd::Ptr, s::Union{Symbol,AbstractString})
return something(dlsym(hnd, s; throw_error=false), C_NULL)
function dlsym_e(args...)
return something(dlsym(args...; throw_error=false), C_NULL)
end

"""
Expand Down Expand Up @@ -110,10 +113,10 @@ If the library cannot be found, this method throws an error, unless the keyword
"""
function dlopen end

dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; kwargs...) =
dlopen(s::Symbol, flags::Integer = default_rtld_flags; kwargs...) =
dlopen(string(s), flags; kwargs...)

function dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; throw_error::Bool = true)
function dlopen(s::AbstractString, flags::Integer = default_rtld_flags; throw_error::Bool = true)
ret = ccall(:jl_load_dynamic_library, Ptr{Cvoid}, (Cstring,UInt32,Cint), s, flags, Cint(throw_error))
if ret == C_NULL
return nothing
Expand All @@ -138,10 +141,10 @@ vendor = dlopen("libblas") do lib
end
```
"""
function dlopen(f::Function, args...; kwargs...)
function dlopen(f::Function, name, args...; kwargs...)
hdl = nothing
try
hdl = dlopen(args...; kwargs...)
hdl = dlopen(name, args...; kwargs...)
f(hdl)
finally
dlclose(hdl)
Expand Down Expand Up @@ -314,4 +317,135 @@ function dllist()
return dynamic_libraries
end


"""
LazyLibraryPath

Helper type for lazily constructed library paths for use with `LazyLibrary`.
Arguments are passed to `joinpath()`. Arguments must be able to have
`string()` called on them.

```
libfoo = LazyLibrary(LazyLibraryPath(prefix, "lib/libfoo.so.1.2.3"))
```
"""
struct LazyLibraryPath
pieces::Vector
LazyLibraryPath(pieces::Vector) = new(pieces)
end
LazyLibraryPath(args...) = LazyLibraryPath(collect(args))
Base.string(llp::LazyLibraryPath) = joinpath(string.(llp.pieces)...)
Base.cconvert(::Type{Cstring}, llp::LazyLibraryPath) = Base.cconvert(Cstring, string(llp))
# Define `print` so that we can wrap this in a `LazyString`
Base.print(io::IO, llp::LazyLibraryPath) = print(io, string(llp))

# Helper to get `Sys.BINDIR` at runtime
struct SysBindirGetter; end
Base.string(::SysBindirGetter) = dirname(Sys.BINDIR)

"""
BundledLazyLibraryPath

Helper type for lazily constructed library paths that are stored within the
bundled Julia distribution, primarily for use by Base modules.

```
libfoo = LazyLibrary(BundledLazyLibraryPath("lib/libfoo.so.1.2.3"))
```
"""
BundledLazyLibraryPath(subpath) = LazyLibraryPath(SysBindirGetter(), subpath)


"""
LazyLibrary(name, flags = <default dlopen flags>,
dependencies = LazyLibrary[], on_load_callback = nothing)

Represents a lazily-loaded library that opens itself and its dependencies on first usage
in a `dlopen()`, `dlsym()`, or `ccall()` usage. While this structure contains the
ability to run arbitrary code on first load via `on_load_callback`, we caution that this
should be used sparingly, as it is not expected that `ccall()` should result in large
amounts of Julia code being run. You may call `ccall()` from within the
`on_load_callback` but only for the current library and its dependencies, and user should
not call `wait()` on any tasks within the on load callback.
"""
mutable struct LazyLibrary
# Name and flags to open with
const path
const flags::UInt32

# Dependencies that must be loaded before we can load
dependencies::Vector{LazyLibrary}

# Function that get called once upon initial load
on_load_callback
const lock::Base.ReentrantLock

# Pointer that we eventually fill out upon first `dlopen()`
@atomic handle::Ptr{Cvoid}
function LazyLibrary(path; flags = default_rtld_flags, dependencies = LazyLibrary[],
on_load_callback = nothing)
return new(
path,
UInt32(flags),
collect(dependencies),
on_load_callback,
Base.ReentrantLock(),
C_NULL,
)
end
end

# We support adding dependencies only because of very special situations
# such as LBT needing to have OpenBLAS_jll added as a dependency dynamically.
function add_dependency!(ll::LazyLibrary, dep::LazyLibrary)
@lock ll.lock begin
push!(ll.dependencies, dep)
end
end

# Register `jl_libdl_dlopen_func` so that `ccall()` lowering knows
# how to call `dlopen()`, during bootstrap.
# See `post_image_load_hooks` for non-bootstrapping.
Base.unsafe_store!(cglobal(:jl_libdl_dlopen_func, Any), dlopen)

function dlopen(ll::LazyLibrary, flags::Integer = ll.flags; kwargs...)
handle = @atomic :acquire ll.handle
if handle == C_NULL
@lock ll.lock begin
# Check to see if another thread has already run this
if ll.handle == C_NULL
# Ensure that all dependencies are loaded
for dep in ll.dependencies
dlopen(dep; kwargs...)
end

# Load our library
handle = dlopen(string(ll.path), flags; kwargs...)
@atomic :release ll.handle = handle

# Only the thread that loaded the library calls the `on_load_callback()`.
if ll.on_load_callback !== nothing
ll.on_load_callback()
end
end
end
else
# Invoke our on load callback, if it exists
if ll.on_load_callback !== nothing
# This empty lock protects against the case where we have updated
# `ll.handle` in the branch above, but not exited the lock. We want
# a second thread that comes in at just the wrong time to have to wait
# for that lock to be released (and thus for the on_load_callback to
# have finished), hence the empty lock here. But we want the
# on_load_callback thread to bypass this, which will be happen thanks
# to the fact that we're using a reentrant lock here.
@lock ll.lock begin end
end
end

return handle
end
dlopen(x::Any) = throw(TypeError(:dlopen, "", Union{Symbol,String,LazyLibrary}, x))
dlsym(ll::LazyLibrary, args...; kwargs...) = dlsym(dlopen(ll), args...; kwargs...)
dlpath(ll::LazyLibrary) = dlpath(dlopen(ll))
end # module Libdl
1 change: 0 additions & 1 deletion base/threads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ module Threads
global Condition # we'll define this later, make sure we don't import Base.Condition

include("threadingconstructs.jl")
include("atomics.jl")
include("locks-mt.jl")

end
2 changes: 2 additions & 0 deletions doc/src/devdocs/locks.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ may result in pernicious and hard-to-find deadlocks. BE VERY CAREFUL!
>
> > this may continue to be held after releasing the iolock, or acquired without it,
> > but be very careful to never attempt to acquire the iolock while holding it
>
> * Libdl.LazyLibrary lock


The following is the root lock, meaning no other lock shall be held when trying to acquire it:
Expand Down
8 changes: 8 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ $(build_includedir)/julia/uv/*.h: $(LIBUV_INC)/uv/*.h | $(build_includedir)/juli
$(INSTALL_F) $^ $(build_includedir)/julia/uv

libccalltest: $(build_shlibdir)/libccalltest.$(SHLIB_EXT)
libccalllazyfoo: $(build_shlibdir)/libccalllazyfoo.$(SHLIB_EXT)
libccalllazybar: $(build_shlibdir)/libccalllazybar.$(SHLIB_EXT)
libllvmcalltest: $(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT)

ifeq ($(OS), Linux)
Expand All @@ -276,6 +278,12 @@ endif
mv [email protected] $@
$(INSTALL_NAME_CMD)libccalltest.$(SHLIB_EXT) $@

$(build_shlibdir)/libccalllazyfoo.$(SHLIB_EXT): $(SRCDIR)/ccalllazyfoo.c
@$(call PRINT_CC, $(CC) $(JCFLAGS) $(JL_CFLAGS) $(JCPPFLAGS) $(FLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(call SONAME_FLAGS,ccalllazyfoo.$(SHLIB_EXT)))

$(build_shlibdir)/libccalllazybar.$(SHLIB_EXT): $(SRCDIR)/ccalllazybar.c $(build_shlibdir)/libccalllazyfoo.$(SHLIB_EXT)
@$(call PRINT_CC, $(CC) $(JCFLAGS) $(JL_CFLAGS) $(JCPPFLAGS) $(FLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(call SONAME_FLAGS,ccalllazybar.$(SHLIB_EXT)) -lccalllazyfoo)

$(build_shlibdir)/libllvmcalltest.$(SHLIB_EXT): $(SRCDIR)/llvmcalltest.cpp $(LLVM_CONFIG_ABSOLUTE)
@$(call PRINT_CC, $(CXX) $(LLVM_CXXFLAGS) $(FLAGS) $(CPPFLAGS) $(CXXFLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS) $(COMMON_LIBPATHS) $(NO_WHOLE_ARCHIVE) $(CG_LLVMLINK)) -lpthread

Expand Down
5 changes: 3 additions & 2 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,9 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
f_lib = jl_symbol_name((jl_sym_t*)t1);
else if (jl_is_string(t1))
f_lib = jl_string_data(t1);
else
f_name = NULL;
else {
out.lib_expr = t1;
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/ccalllazybar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include "ccalltest_common.h"

// We expect this to come from `libccalllazyfoo`
extern int foo(int);

DLLEXPORT int bar(int a) {
return foo(a + 1);
}
7 changes: 7 additions & 0 deletions src/ccalllazyfoo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include "ccalltest_common.h"

DLLEXPORT int foo(int a) {
return a*2;
}
33 changes: 1 addition & 32 deletions src/ccalltest.c
Original file line number Diff line number Diff line change
@@ -1,41 +1,10 @@
// This file is a part of Julia. License is MIT: https://julialang.org/license

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <stdint.h>
#include <inttypes.h>

#include "../src/support/platform.h"
#include "../src/support/dtypes.h"

// Borrow definition from `support/dtypes.h`
#ifdef _OS_WINDOWS_
# define DLLEXPORT __declspec(dllexport)
#else
# if defined(_OS_LINUX_) && !defined(_COMPILER_CLANG_)
// Clang and ld disagree about the proper relocation for STV_PROTECTED, causing
// linker errors.
# define DLLEXPORT __attribute__ ((visibility("protected")))
# else
# define DLLEXPORT __attribute__ ((visibility("default")))
# endif
#endif


#ifdef _P64
#define jint int64_t
#define PRIjint PRId64
#else
#define jint int32_t
#define PRIjint PRId32
#endif
#include "ccalltest_common.h"

int verbose = 1;

int c_int = 0;


//////////////////////////////////
// Test for proper argument register truncation

Expand Down
Loading