@@ -196,7 +196,7 @@ version (Windows)
196
196
import core.sys.windows.winnt /+ : CONTEXT, CONTEXT_CONTROL, CONTEXT_INTEGER+/ ;
197
197
198
198
extern (Windows ) alias btex_fptr = uint function (void * );
199
- extern (C ) uintptr_t _beginthreadex(void * , uint , btex_fptr, void * , uint , uint * ) nothrow ;
199
+ extern (C ) uintptr_t _beginthreadex(void * , uint , btex_fptr, void * , uint , uint * ) nothrow @nogc ;
200
200
201
201
//
202
202
// Entry point for Windows threads
@@ -2020,7 +2020,9 @@ extern (C) void thread_init() @nogc
2020
2020
// exist to be scanned at this point, it is sufficient for these
2021
2021
// functions to detect the condition and return immediately.
2022
2022
2023
+ initLowlevelThreads();
2023
2024
Thread .initLocks();
2025
+
2024
2026
// The Android VM runtime intercepts SIGUSR1 and apparently doesn't allow
2025
2027
// its signal handler to run, so swap the two signals on Android, since
2026
2028
// thread_resumeHandler does nothing.
@@ -2116,6 +2118,7 @@ extern (C) void thread_term() @nogc
2116
2118
Thread .pAboutToStart = null ;
2117
2119
}
2118
2120
Thread .termLocks();
2121
+ termLowlevelThreads();
2119
2122
}
2120
2123
2121
2124
3070
3073
* Throws:
3071
3074
* ThreadError.
3072
3075
*/
3073
- private void onThreadError (string msg) nothrow
3076
+ private void onThreadError (string msg) nothrow @nogc
3074
3077
{
3075
3078
__gshared ThreadError error = new ThreadError (null );
3076
3079
error.msg = msg;
@@ -5628,3 +5631,187 @@ version (Windows)
5628
5631
else
5629
5632
version (Posix )
5630
5633
alias ThreadID = pthread_t ;
5634
+
5635
+ // /////////////////////////////////////////////////////////////////////////////
5636
+ // lowlovel threading support
5637
+ private
5638
+ {
5639
+ __gshared size_t ll_nThreads;
5640
+ __gshared ThreadID* ll_pThreads;
5641
+
5642
+ __gshared align (Mutex .alignof) void [__traits(classInstanceSize, Mutex )] ll_lock;
5643
+
5644
+ @property Mutex lowlevelLock() nothrow @nogc
5645
+ {
5646
+ return cast (Mutex )ll_lock.ptr;
5647
+ }
5648
+
5649
+ void initLowlevelThreads () @nogc
5650
+ {
5651
+ ll_lock[] = typeid (Mutex ).initializer[];
5652
+ lowlevelLock.__ctor();
5653
+ }
5654
+
5655
+ void termLowlevelThreads () @nogc
5656
+ {
5657
+ lowlevelLock.__dtor();
5658
+ }
5659
+
5660
+ void ll_removeThread (ThreadID tid) nothrow @nogc
5661
+ {
5662
+ lowlevelLock.lock_nothrow();
5663
+ scope (exit) lowlevelLock.unlock_nothrow();
5664
+
5665
+ foreach (i; 0 .. ll_nThreads)
5666
+ {
5667
+ if (tid is ll_pThreads[i])
5668
+ {
5669
+ import core.stdc.string : memmove;
5670
+ memmove(ll_pThreads + i, ll_pThreads + i + 1 , ThreadID.sizeof * (ll_nThreads - i - 1 ));
5671
+ -- ll_nThreads;
5672
+ // no need to minimize, next add will do
5673
+ break ;
5674
+ }
5675
+ }
5676
+ }
5677
+ }
5678
+
5679
+ /**
5680
+ * Create a thread not under control of the runtime, i.e. TLS module constructors are
5681
+ * not run and the GC does not suspend it during a collection
5682
+ *
5683
+ * Params:
5684
+ * dg = delegate to execute in the created thread
5685
+ * stacksize = size of the stack of the created thread. The default of 0 will select the
5686
+ * platform-specific default size
5687
+ *
5688
+ * Returns: the platform specific thread ID of the new thread. If an error occurs, a preallocated
5689
+ * ThreadError is thrown.
5690
+ */
5691
+ ThreadID createLowLevelThread (void delegate () nothrow dg, uint stacksize = 0 ) nothrow @nogc
5692
+ {
5693
+ void delegate () nothrow * context = cast (void delegate () nothrow * )malloc(dg.sizeof);
5694
+ * context = dg;
5695
+
5696
+ ThreadID tid;
5697
+ version (Windows )
5698
+ {
5699
+ static extern (Windows) uint thread_lowlevelEntry(void * ctx) nothrow
5700
+ {
5701
+ auto dg = * cast (void delegate () nothrow * )ctx;
5702
+ free(ctx);
5703
+
5704
+ dg();
5705
+ ll_removeThread(GetCurrentThreadId());
5706
+ return 0 ;
5707
+ }
5708
+
5709
+ // see Thread.start() for why thread is created in suspended state
5710
+ HANDLE hThread = cast (HANDLE ) _beginthreadex(null , stacksize, &thread_lowlevelEntry,
5711
+ context, CREATE_SUSPENDED , &tid);
5712
+ if (! hThread)
5713
+ onThreadError(" Error creating thread" );
5714
+ }
5715
+
5716
+ lowlevelLock.lock_nothrow();
5717
+ scope (exit) lowlevelLock.unlock_nothrow();
5718
+
5719
+ ll_nThreads++ ;
5720
+ ll_pThreads = cast (ThreadID* )realloc(ll_pThreads, Thread .sizeof * ll_nThreads);
5721
+
5722
+ version (Windows )
5723
+ {
5724
+ ll_pThreads[ll_nThreads - 1 ] = tid;
5725
+ if (ResumeThread(hThread) == - 1 )
5726
+ onThreadError(" Error resuming thread" );
5727
+ CloseHandle(hThread);
5728
+ }
5729
+ else version (Posix )
5730
+ {
5731
+ static extern (C) void * thread_lowlevelEntry(void * ctx) nothrow
5732
+ {
5733
+ auto dg = * cast (void delegate () nothrow * )ctx;
5734
+ free(ctx);
5735
+
5736
+ dg();
5737
+ ll_removeThread(pthread_self());
5738
+ return null ;
5739
+ }
5740
+
5741
+ pthread_attr_t attr;
5742
+
5743
+ if (pthread_attr_init(&attr))
5744
+ onThreadError(" Error initializing thread attributes" );
5745
+ if (stacksize && pthread_attr_setstacksize(&attr, stacksize))
5746
+ onThreadError(" Error initializing thread stack size" );
5747
+ if (pthread_create(&tid, &attr, &thread_lowlevelEntry, context) != 0 )
5748
+ onThreadError(" Error creating thread" );
5749
+
5750
+ ll_pThreads[ll_nThreads - 1 ] = tid;
5751
+ }
5752
+ return tid;
5753
+ }
5754
+
5755
+ /**
5756
+ * Wait for a thread created with `createLowLevelThread` to terminate
5757
+ *
5758
+ * Params:
5759
+ * tid = the thread ID returned by `createLowLevelThread`
5760
+ */
5761
+ void joinLowLevelThread (ThreadID tid) nothrow @nogc
5762
+ {
5763
+ version (Windows )
5764
+ {
5765
+ HANDLE handle = OpenThreadHandle(tid);
5766
+ if (! handle)
5767
+ return ;
5768
+ WaitForSingleObject(handle, INFINITE );
5769
+ CloseHandle(handle);
5770
+ }
5771
+ else version (Posix )
5772
+ {
5773
+ if (pthread_join(tid, null ) != 0 )
5774
+ onThreadError(" Unable to join thread" );
5775
+ }
5776
+ }
5777
+
5778
+ /**
5779
+ * Check whether a thread was created by `createLowLevelThread`
5780
+ *
5781
+ * Params:
5782
+ * tid = the platform specific thread ID
5783
+ *
5784
+ * Returns: `true` if the thread was created by `createLowLevelThread` and is still running
5785
+ */
5786
+ bool findLowLevelThread (ThreadID tid) nothrow @nogc
5787
+ {
5788
+ lowlevelLock.lock_nothrow();
5789
+ scope (exit) lowlevelLock.unlock_nothrow();
5790
+
5791
+ foreach (i; 0 .. ll_nThreads)
5792
+ if (tid is ll_pThreads[i])
5793
+ return true ;
5794
+ return false ;
5795
+ }
5796
+
5797
+ nothrow @nogc unittest
5798
+ {
5799
+ struct TaskWithContect
5800
+ {
5801
+ shared int n = 0 ;
5802
+ void run () nothrow
5803
+ {
5804
+ n.atomicOp! " +=" (1 );
5805
+ }
5806
+ }
5807
+ TaskWithContect task;
5808
+
5809
+ ThreadID[8 ] tids;
5810
+ for (int i = 0 ; i < tids.length; i++ )
5811
+ tids[i] = createLowLevelThread(&task.run);
5812
+
5813
+ for (int i = 0 ; i < tids.length; i++ )
5814
+ joinLowLevelThread(tids[i]);
5815
+
5816
+ assert (task.n == tids.length);
5817
+ }
0 commit comments