diff --git a/src/crystal/system/thread_local.cr b/src/crystal/system/thread_local.cr new file mode 100644 index 000000000000..5b7242df12ca --- /dev/null +++ b/src/crystal/system/thread_local.cr @@ -0,0 +1,28 @@ +class Thread + struct Local(T) + # def initialize + # {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + # end + + # def initialize(&destructor : Proc(T, Nil)) + # {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + # end + + def get(& : -> T) : T + get? || set(yield) + end + + # def get? : T? + # def set(value : T) : T + end +end + +{% if flag?(:wasi) %} + require "./wasi/thread_local" +{% elsif flag?(:unix) %} + require "./unix/thread_local" +{% elsif flag?(:win32) %} + require "./win32/thread_local" +{% else %} + {% raise "Thread not supported" %} +{% end %} diff --git a/src/crystal/system/unix/thread_local.cr b/src/crystal/system/unix/thread_local.cr new file mode 100644 index 000000000000..f6bedd279fd1 --- /dev/null +++ b/src/crystal/system/unix/thread_local.cr @@ -0,0 +1,30 @@ +require "c/pthread" + +class Thread + struct Local(T) + @key : LibC::PthreadKeyT + + def initialize + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + err = LibC.pthread_key_create(out @key, nil) + raise RuntimeError.from_os_error("pthread_key_create", Errno.new(err)) unless err == 0 + end + + def initialize(&destructor : Proc(T, Nil)) + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + err = LibC.pthread_key_create(out @key, destructor.unsafe_as(Proc(Void*, Nil))) + raise RuntimeError.from_os_error("pthread_key_create", Errno.new(err)) unless err == 0 + end + + def get? : T? + pointer = LibC.pthread_getspecific(@key) + pointer.as(T) if pointer + end + + def set(value : T) : T + err = LibC.pthread_setspecific(@key, value.as(Void*)) + raise RuntimeError.from_os_error("pthread_setspecific", Errno.new(err)) unless err == 0 + value + end + end +end diff --git a/src/crystal/system/wasi/thread_local.cr b/src/crystal/system/wasi/thread_local.cr new file mode 100644 index 000000000000..f1e742780370 --- /dev/null +++ b/src/crystal/system/wasi/thread_local.cr @@ -0,0 +1,21 @@ +class Thread + struct Local(T) + @value : T? + + def initialize + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + end + + def initialize(&destructor : T ->) + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + end + + def get? : T? + @value + end + + def set(value : T) : T + @value = value + end + end +end diff --git a/src/crystal/system/win32/thread_local.cr b/src/crystal/system/win32/thread_local.cr new file mode 100644 index 000000000000..ce53d84a2a29 --- /dev/null +++ b/src/crystal/system/win32/thread_local.cr @@ -0,0 +1,30 @@ +require "c/fibersapi" + +class Thread + struct Local(T) + @key : LibC::DWORD + + def initialize + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + @key = LibC.FlsAlloc + raise RuntimeError.from_winerror("FlsAlloc: out of indexes") if @key == LibC::FLS_OUT_OF_INDEXES + end + + def initialize(&destructor : Proc(T, Nil)) + {% raise "T must be a Reference or Pointer" unless T < Reference || T < Pointer %} + @key = LibC.FlsAlloc(destructor.unsafe_as(LibC::FLS_CALLBACK_FUNCTION)) + raise RuntimeError.from_winerror("FlsAlloc: out of indexes") if @key == LibC::FLS_OUT_OF_INDEXES + end + + def get? : T? + pointer = LibC.FlsGetValue(@key) + pointer.as(T) if pointer + end + + def set(value : T) : T + ret = LibC.FlsSetValue(@key, value.as(Void*)) + raise RuntimeError.from_winerror("FlsSetValue") if ret == 0 + value + end + end +end diff --git a/src/lib_c/aarch64-android/c/pthread.cr b/src/lib_c/aarch64-android/c/pthread.cr index fbab59bd07d7..bd4390df5035 100644 --- a/src/lib_c/aarch64-android/c/pthread.cr +++ b/src/lib_c/aarch64-android/c/pthread.cr @@ -26,6 +26,7 @@ lib LibC fun pthread_getspecific(__key : PthreadKeyT) : Void* fun pthread_join(__pthread : PthreadT, __return_value_ptr : Void**) : Int fun pthread_key_create(__key_ptr : PthreadKeyT*, __key_destructor : Void* ->) : Int + fun pthread_key_delete(__key_ptr : PthreadKeyT) : Int fun pthread_mutexattr_destroy(__attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(__attr : PthreadMutexattrT*) : Int diff --git a/src/lib_c/aarch64-darwin/c/pthread.cr b/src/lib_c/aarch64-darwin/c/pthread.cr index d146e227197f..43d240435702 100644 --- a/src/lib_c/aarch64-darwin/c/pthread.cr +++ b/src/lib_c/aarch64-darwin/c/pthread.cr @@ -13,9 +13,13 @@ lib LibC fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_get_stackaddr_np(x0 : PthreadT) : Void* fun pthread_get_stacksize_np(x0 : PthreadT) : SizeT fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -26,4 +30,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/aarch64-darwin/c/sys/types.cr b/src/lib_c/aarch64-darwin/c/sys/types.cr index 836ac0c1c43d..a0dbc91bdfaa 100644 --- a/src/lib_c/aarch64-darwin/c/sys/types.cr +++ b/src/lib_c/aarch64-darwin/c/sys/types.cr @@ -40,6 +40,7 @@ lib LibC end type PthreadT = Void* + alias PthreadKeyT = UInt alias SSizeT = Long alias SusecondsT = Int alias TimeT = Long diff --git a/src/lib_c/aarch64-linux-gnu/c/pthread.cr b/src/lib_c/aarch64-linux-gnu/c/pthread.cr index 5d9f7b94e225..e3fe03d237b5 100644 --- a/src/lib_c/aarch64-linux-gnu/c/pthread.cr +++ b/src/lib_c/aarch64-linux-gnu/c/pthread.cr @@ -25,8 +25,12 @@ lib LibC fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int fun pthread_detach(th : PthreadT) : Int fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_equal(thread1 : PthreadT, thread2 : PthreadT) : Int fun pthread_join(th : PthreadT, thread_return : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(attr : PthreadMutexattrT*, type : Int) : Int @@ -37,4 +41,5 @@ lib LibC fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/aarch64-linux-gnu/c/sys/types.cr b/src/lib_c/aarch64-linux-gnu/c/sys/types.cr index bef2498d1494..49aeefee2e39 100644 --- a/src/lib_c/aarch64-linux-gnu/c/sys/types.cr +++ b/src/lib_c/aarch64-linux-gnu/c/sys/types.cr @@ -41,6 +41,7 @@ lib LibC end alias PthreadT = ULong + alias PthreadKeyT = UInt alias SSizeT = Long alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/aarch64-linux-musl/c/pthread.cr b/src/lib_c/aarch64-linux-musl/c/pthread.cr index 6ee1a20d90a6..6704cd4c9802 100644 --- a/src/lib_c/aarch64-linux-musl/c/pthread.cr +++ b/src/lib_c/aarch64-linux-musl/c/pthread.cr @@ -17,7 +17,11 @@ lib LibC fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -28,4 +32,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/aarch64-linux-musl/c/sys/types.cr b/src/lib_c/aarch64-linux-musl/c/sys/types.cr index f828ffacffd0..0959f27fc863 100644 --- a/src/lib_c/aarch64-linux-musl/c/sys/types.cr +++ b/src/lib_c/aarch64-linux-musl/c/sys/types.cr @@ -54,6 +54,7 @@ lib LibC end type PthreadT = Void* + alias PthreadKeyT = UInt alias SSizeT = Long alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr index 5d9f7b94e225..e3fe03d237b5 100644 --- a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr +++ b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr @@ -25,8 +25,12 @@ lib LibC fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int fun pthread_detach(th : PthreadT) : Int fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_equal(thread1 : PthreadT, thread2 : PthreadT) : Int fun pthread_join(th : PthreadT, thread_return : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(attr : PthreadMutexattrT*, type : Int) : Int @@ -37,4 +41,5 @@ lib LibC fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/arm-linux-gnueabihf/c/sys/types.cr b/src/lib_c/arm-linux-gnueabihf/c/sys/types.cr index 7a1618b91cf2..a4728582034f 100644 --- a/src/lib_c/arm-linux-gnueabihf/c/sys/types.cr +++ b/src/lib_c/arm-linux-gnueabihf/c/sys/types.cr @@ -54,6 +54,7 @@ lib LibC end alias PthreadT = ULong + alias PthreadKeyT = UInt alias SSizeT = Int alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/i386-linux-gnu/c/pthread.cr b/src/lib_c/i386-linux-gnu/c/pthread.cr index 33274a6cf51d..a621e19acc72 100644 --- a/src/lib_c/i386-linux-gnu/c/pthread.cr +++ b/src/lib_c/i386-linux-gnu/c/pthread.cr @@ -25,7 +25,11 @@ lib LibC fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int fun pthread_detach(th : PthreadT) : Int fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(th : PthreadT, thread_return : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(attr : PthreadMutexattrT*, type : Int) : Int @@ -36,4 +40,5 @@ lib LibC fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/i386-linux-gnu/c/sys/types.cr b/src/lib_c/i386-linux-gnu/c/sys/types.cr index a1d00215d55d..c38fcb92f102 100644 --- a/src/lib_c/i386-linux-gnu/c/sys/types.cr +++ b/src/lib_c/i386-linux-gnu/c/sys/types.cr @@ -41,6 +41,7 @@ lib LibC end alias PthreadT = ULong + alias PthreadKeyT = UInt alias SSizeT = Int alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/i386-linux-musl/c/pthread.cr b/src/lib_c/i386-linux-musl/c/pthread.cr index 6ee1a20d90a6..6704cd4c9802 100644 --- a/src/lib_c/i386-linux-musl/c/pthread.cr +++ b/src/lib_c/i386-linux-musl/c/pthread.cr @@ -17,7 +17,11 @@ lib LibC fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -28,4 +32,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/i386-linux-musl/c/sys/types.cr b/src/lib_c/i386-linux-musl/c/sys/types.cr index e8a6362b52fe..7e4448048fe3 100644 --- a/src/lib_c/i386-linux-musl/c/sys/types.cr +++ b/src/lib_c/i386-linux-musl/c/sys/types.cr @@ -54,6 +54,7 @@ lib LibC end type PthreadT = Void* + alias PthreadKeyT = UInt alias SSizeT = Int alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/x86_64-darwin/c/pthread.cr b/src/lib_c/x86_64-darwin/c/pthread.cr index d146e227197f..07d973e2ec28 100644 --- a/src/lib_c/x86_64-darwin/c/pthread.cr +++ b/src/lib_c/x86_64-darwin/c/pthread.cr @@ -15,7 +15,11 @@ lib LibC fun pthread_detach(x0 : PthreadT) : Int fun pthread_get_stackaddr_np(x0 : PthreadT) : Void* fun pthread_get_stacksize_np(x0 : PthreadT) : SizeT + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -26,4 +30,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-darwin/c/sys/types.cr b/src/lib_c/x86_64-darwin/c/sys/types.cr index 836ac0c1c43d..a0dbc91bdfaa 100644 --- a/src/lib_c/x86_64-darwin/c/sys/types.cr +++ b/src/lib_c/x86_64-darwin/c/sys/types.cr @@ -40,6 +40,7 @@ lib LibC end type PthreadT = Void* + alias PthreadKeyT = UInt alias SSizeT = Long alias SusecondsT = Int alias TimeT = Long diff --git a/src/lib_c/x86_64-dragonfly/c/pthread.cr b/src/lib_c/x86_64-dragonfly/c/pthread.cr index 90bf0c6285a0..17e2d7f94e7c 100644 --- a/src/lib_c/x86_64-dragonfly/c/pthread.cr +++ b/src/lib_c/x86_64-dragonfly/c/pthread.cr @@ -19,7 +19,11 @@ lib LibC fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -30,4 +34,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-dragonfly/c/sys/types.cr b/src/lib_c/x86_64-dragonfly/c/sys/types.cr index effbe1227c7f..d5c47dd4eae5 100644 --- a/src/lib_c/x86_64-dragonfly/c/sys/types.cr +++ b/src/lib_c/x86_64-dragonfly/c/sys/types.cr @@ -17,6 +17,7 @@ lib LibC type PthreadAttrT = Void* type PthreadCondT = Void* type PthreadCondattrT = Void* + alias PthreadKeyT = Int type PthreadMutexT = Void* type PthreadMutexattrT = Void* type PthreadT = Void* diff --git a/src/lib_c/x86_64-freebsd/c/pthread.cr b/src/lib_c/x86_64-freebsd/c/pthread.cr index 9cc78c2f2850..f1885a2a1400 100644 --- a/src/lib_c/x86_64-freebsd/c/pthread.cr +++ b/src/lib_c/x86_64-freebsd/c/pthread.cr @@ -19,7 +19,11 @@ lib LibC fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -30,4 +34,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_set_name_np(PthreadT, Char*) + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-freebsd/c/sys/types.cr b/src/lib_c/x86_64-freebsd/c/sys/types.cr index 7e0ffad4cd28..77de36fbe71b 100644 --- a/src/lib_c/x86_64-freebsd/c/sys/types.cr +++ b/src/lib_c/x86_64-freebsd/c/sys/types.cr @@ -17,6 +17,7 @@ lib LibC type PthreadAttrT = Void* type PthreadCondT = Void* type PthreadCondattrT = Void* + alias PthreadKeyT = Int type PthreadMutexT = Void* type PthreadMutexattrT = Void* type PthreadT = Void* diff --git a/src/lib_c/x86_64-linux-gnu/c/pthread.cr b/src/lib_c/x86_64-linux-gnu/c/pthread.cr index 33274a6cf51d..a621e19acc72 100644 --- a/src/lib_c/x86_64-linux-gnu/c/pthread.cr +++ b/src/lib_c/x86_64-linux-gnu/c/pthread.cr @@ -25,7 +25,11 @@ lib LibC fun pthread_create(newthread : PthreadT*, attr : PthreadAttrT*, start_routine : Void* -> Void*, arg : Void*) : Int fun pthread_detach(th : PthreadT) : Int fun pthread_getattr_np(thread : PthreadT, attr : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(th : PthreadT, thread_return : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(attr : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(attr : PthreadMutexattrT*, type : Int) : Int @@ -36,4 +40,5 @@ lib LibC fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-linux-gnu/c/sys/types.cr b/src/lib_c/x86_64-linux-gnu/c/sys/types.cr index 0fa18856ed06..08faf707a99a 100644 --- a/src/lib_c/x86_64-linux-gnu/c/sys/types.cr +++ b/src/lib_c/x86_64-linux-gnu/c/sys/types.cr @@ -40,6 +40,7 @@ lib LibC __align : Int end + alias PthreadKeyT = UInt alias PthreadT = ULong alias SSizeT = Long alias SusecondsT = Long diff --git a/src/lib_c/x86_64-linux-musl/c/pthread.cr b/src/lib_c/x86_64-linux-musl/c/pthread.cr index 6ee1a20d90a6..6704cd4c9802 100644 --- a/src/lib_c/x86_64-linux-musl/c/pthread.cr +++ b/src/lib_c/x86_64-linux-musl/c/pthread.cr @@ -17,7 +17,11 @@ lib LibC fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int fun pthread_getattr_np(x0 : PthreadT, x1 : PthreadAttrT*) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -28,4 +32,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-linux-musl/c/sys/types.cr b/src/lib_c/x86_64-linux-musl/c/sys/types.cr index 7b05d631a549..60697e828056 100644 --- a/src/lib_c/x86_64-linux-musl/c/sys/types.cr +++ b/src/lib_c/x86_64-linux-musl/c/sys/types.cr @@ -54,6 +54,7 @@ lib LibC end type PthreadT = Void* + alias PthreadKeyT = UInt alias SSizeT = Long alias SusecondsT = Long alias TimeT = Long diff --git a/src/lib_c/x86_64-netbsd/c/pthread.cr b/src/lib_c/x86_64-netbsd/c/pthread.cr index e0f477018777..7f5479bcfbeb 100644 --- a/src/lib_c/x86_64-netbsd/c/pthread.cr +++ b/src/lib_c/x86_64-netbsd/c/pthread.cr @@ -25,6 +25,7 @@ lib LibC fun pthread_join(x0 : PthreadT, x1 : Void**) : Int alias PthreadKeyDestructor = (Void*) -> fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_main_np : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int diff --git a/src/lib_c/x86_64-openbsd/c/pthread.cr b/src/lib_c/x86_64-openbsd/c/pthread.cr index 15773336f239..b1d4ed2eeed6 100644 --- a/src/lib_c/x86_64-openbsd/c/pthread.cr +++ b/src/lib_c/x86_64-openbsd/c/pthread.cr @@ -20,6 +20,7 @@ lib LibC fun pthread_join(x0 : PthreadT, x1 : Void**) : Int alias PthreadKeyDestructor = (Void*) -> fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_main_np : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int diff --git a/src/lib_c/x86_64-solaris/c/pthread.cr b/src/lib_c/x86_64-solaris/c/pthread.cr index 538d68263739..cbad672ceea0 100644 --- a/src/lib_c/x86_64-solaris/c/pthread.cr +++ b/src/lib_c/x86_64-solaris/c/pthread.cr @@ -19,7 +19,11 @@ lib LibC fun pthread_cond_wait(x0 : PthreadCondT*, x1 : PthreadMutexT*) : Int fun pthread_create(x0 : PthreadT*, x1 : PthreadAttrT*, x2 : Void* -> Void*, x3 : Void*) : Int fun pthread_detach(x0 : PthreadT) : Int + fun pthread_getspecific(PthreadKeyT) : Void* fun pthread_join(x0 : PthreadT, x1 : Void**) : Int + alias PthreadKeyDestructor = (Void*) -> + fun pthread_key_create(PthreadKeyT*, PthreadKeyDestructor) : Int + fun pthread_key_delete(PthreadKeyT) : Int fun pthread_mutexattr_destroy(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_init(x0 : PthreadMutexattrT*) : Int fun pthread_mutexattr_settype(x0 : PthreadMutexattrT*, x1 : Int) : Int @@ -30,4 +34,5 @@ lib LibC fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT fun pthread_setname_np(PthreadT, Char*) : Int + fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-solaris/c/sys/types.cr b/src/lib_c/x86_64-solaris/c/sys/types.cr index b8457bffe861..1054d0204c44 100644 --- a/src/lib_c/x86_64-solaris/c/sys/types.cr +++ b/src/lib_c/x86_64-solaris/c/sys/types.cr @@ -45,6 +45,7 @@ lib LibC end alias PthreadT = UInt + alias PthreadKeyT = Int alias SSizeT = Long alias SusecondsT = Long diff --git a/src/lib_c/x86_64-windows-msvc/c/fibersapi.cr b/src/lib_c/x86_64-windows-msvc/c/fibersapi.cr new file mode 100644 index 000000000000..5b2dfc05a1f9 --- /dev/null +++ b/src/lib_c/x86_64-windows-msvc/c/fibersapi.cr @@ -0,0 +1,10 @@ +lib LibC + FLS_OUT_OF_INDEXES = 0xFFFFFFFF_u32 + + alias FLS_CALLBACK_FUNCTION = Proc(Void*, Nil) + + fun FlsAlloc(FLS_CALLBACK_FUNCTION) : DWORD + fun FlsFree(DWORD) : BOOL + fun FlsGetValue(DWORD) : Void* + fun FlsSetValue(DWORD, Void*) : BOOL +end diff --git a/src/regex/lib_pcre2.cr b/src/regex/lib_pcre2.cr index 6f45a4465219..f6234e30b3c1 100644 --- a/src/regex/lib_pcre2.cr +++ b/src/regex/lib_pcre2.cr @@ -264,10 +264,12 @@ lib LibPCRE2 fun jit_stack_create = pcre2_jit_stack_create_8(startsize : LibC::SizeT, maxsize : LibC::SizeT, gcontext : GeneralContext*) : JITStack* fun jit_stack_assign = pcre2_jit_stack_assign_8(mcontext : MatchContext*, callable_function : Void* -> JITStack*, callable_data : Void*) : Void + fun jit_stack_free = pcre2_jit_stack_free_8(jit_stack : JITStack*) : Void fun pattern_info = pcre2_pattern_info_8(code : Code*, what : UInt32, where : Void*) : Int fun match = pcre2_match_8(code : Code*, subject : UInt8*, length : LibC::SizeT, startoffset : LibC::SizeT, options : UInt32, match_data : MatchData*, mcontext : MatchContext*) : Int + fun match_data_create = pcre2_match_data_create_8(ovecsize : UInt32, gcontext : GeneralContext*) : MatchData* fun match_data_create_from_pattern = pcre2_match_data_create_from_pattern_8(code : Code*, gcontext : GeneralContext*) : MatchData* fun match_data_free = pcre2_match_data_free_8(match_data : MatchData*) : Void diff --git a/src/regex/pcre2.cr b/src/regex/pcre2.cr index b56a4ea68839..ae0b1d823a55 100644 --- a/src/regex/pcre2.cr +++ b/src/regex/pcre2.cr @@ -1,5 +1,5 @@ require "./lib_pcre2" -require "crystal/thread_local_value" +require "crystal/system/thread_local" # :nodoc: module Regex::PCRE2 @@ -207,12 +207,14 @@ module Regex::PCRE2 private def match_impl(str, byte_index, options) match_data = match_data(str, byte_index, options) || return - ovector_count = LibPCRE2.get_ovector_count(match_data) + # we reuse the same matchdata allocation, so we must "reimplement" the + # behavior of pcre2_match_data_create_from_pattern (get_ovector_count always + # returns 65535, aka the maximum): + ovector_count = capture_count_impl &+ 1 ovector = Slice.new(LibPCRE2.get_ovector_pointer(match_data), ovector_count &* 2) # We need to dup the ovector because `match_data` is re-used for subsequent - # matches (see `@match_data`). - # Dup brings the ovector data into the realm of the GC. + # matches. Dup brings the ovector data into the realm of the GC. ovector = ovector.dup ::Regex::MatchData.new(self, @re, str, byte_index, ovector.to_unsafe, ovector_count.to_i32 &- 1) @@ -228,43 +230,50 @@ module Regex::PCRE2 class_getter match_context : LibPCRE2::MatchContext* do match_context = LibPCRE2.match_context_create(nil) - LibPCRE2.jit_stack_assign(match_context, ->(_data) { Regex::PCRE2.jit_stack }, nil) + LibPCRE2.jit_stack_assign(match_context, ->(_data) { + jit_stack + }, nil) match_context end - # Returns a JIT stack that's shared in the current thread. + # JIT stack is unique per thread. # - # Only a single `match` function can run per thread at any given time, so there - # can't be any concurrent access to the JIT stack. - @@jit_stack = Crystal::ThreadLocalValue(LibPCRE2::JITStack*).new + # Only a single `match` function can run per thread at any given time, so + # there can't be any concurrent access to the JIT stack. + @@jit_stack = Thread::Local(LibPCRE2::JITStack*).new do |jit_stack| + LibPCRE2.jit_stack_free(jit_stack) + end - def self.jit_stack + protected def self.jit_stack @@jit_stack.get do LibPCRE2.jit_stack_create(32_768, 1_048_576, nil) || raise "Error allocating JIT stack" end end - # Match data is shared per instance and thread. + # Match data is unique per thread. # - # Match data contains a buffer for backtracking when matching in interpreted mode (non-JIT). - # This buffer is heap-allocated and should be re-used for subsequent matches. - @match_data = Crystal::ThreadLocalValue(LibPCRE2::MatchData*).new + # Match data contains a buffer for backtracking when matching in interpreted + # mode (non-JIT). This buffer is heap-allocated and should be re-used for + # subsequent matches. + @@match_data = Thread::Local(LibPCRE2::MatchData*).new do |match_data| + LibPCRE2.match_data_free(match_data) + end - private def match_data - @match_data.get do - LibPCRE2.match_data_create_from_pattern(@re, nil) + protected def self.match_data : LibPCRE2::MatchData* + @@match_data.get do + # the ovector size is clamped to 65535 pairs; we declare the maximum + # because we allocate the match data buffer once for the thread and need + # to adapt to any regular expression + LibPCRE2.match_data_create(65_535, nil) end end def finalize - @match_data.consume_each do |match_data| - LibPCRE2.match_data_free(match_data) - end LibPCRE2.code_free @re end private def match_data(str, byte_index, options) - match_data = self.match_data + match_data = Regex::PCRE2.match_data match_count = LibPCRE2.match(@re, str, str.bytesize, byte_index, pcre2_match_options(options), match_data, PCRE2.match_context) if match_count < 0