Browse code

Add winthreads, adopt to changed location of iostream.cpp

Steffen Neumann authored on 18/01/2022 11:27:30
Showing5 changed files

... ...
@@ -102,7 +102,7 @@ ARCH_OBJS=./boost/libs/filesystem/src/path_traits.o \
102 102
 ./boost/libs/thread/src/win32/tss_pe.o \
103 103
 ./boost/libs/thread/src/win32/tss_dll.o \
104 104
 ./boost/libs/thread/src/win32/thread.o \
105
-./boost_aux/boost/nowide/iostream.o
105
+./boost_aux/libs/nowide/src/iostream.o
106 106
 ARCH_CPPFLAGS=-fpermissive -DWINDOWS_NATIVE -DWIN32 -DBOOST_HAS_WINTHREADS -DBOOST_THREAD_BUILD_LIB
107 107
 ARCH_LIBS=-lws2_32 -lz
108 108
 RHDF5_LIBS=$(shell echo 'Rhdf5lib::pkgconfig("PKG_CXX_LIBS")'| "${R_HOME}/bin/R" --vanilla --slave)  
109 109
new file mode 100755
... ...
@@ -0,0 +1,980 @@
1
+// Distributed under the Boost Software License, Version 1.0. (See
2
+// accompanying file LICENSE_1_0.txt or copy at
3
+// http://www.boost.org/LICENSE_1_0.txt)
4
+// (C) Copyright 2007 Anthony Williams
5
+// (C) Copyright 2007 David Deakins
6
+// (C) Copyright 2011-2018 Vicente J. Botet Escriba
7
+
8
+//#define BOOST_THREAD_VERSION 3
9
+
10
+#include <boost/winapi/config.hpp>
11
+#include <boost/thread/thread_only.hpp>
12
+#include <boost/thread/once.hpp>
13
+#include <boost/thread/tss.hpp>
14
+#include <boost/thread/condition_variable.hpp>
15
+#include <boost/thread/detail/tss_hooks.hpp>
16
+#include <boost/thread/future.hpp>
17
+#include <boost/assert.hpp>
18
+#include <boost/cstdint.hpp>
19
+#if defined BOOST_THREAD_USES_DATETIME
20
+#include <boost/date_time/posix_time/conversion.hpp>
21
+#include <boost/thread/thread_time.hpp>
22
+#endif
23
+#include <boost/thread/csbl/memory/unique_ptr.hpp>
24
+#include <memory>
25
+#include <algorithm>
26
+#ifndef UNDER_CE
27
+#include <process.h>
28
+#endif
29
+#include <stdio.h>
30
+#include <windows.h>
31
+#include <boost/predef/platform.h>
32
+
33
+#if BOOST_PLAT_WINDOWS_RUNTIME
34
+#include <mutex>
35
+#include <atomic>
36
+#include <Activation.h>
37
+#include <wrl\client.h>
38
+#include <wrl\event.h>
39
+#include <wrl\wrappers\corewrappers.h>
40
+#include <wrl\ftm.h>
41
+#include <windows.system.threading.h>
42
+#pragma comment(lib, "runtimeobject.lib")
43
+#endif
44
+
45
+namespace boost
46
+{
47
+  namespace detail
48
+  {
49
+    thread_data_base::~thread_data_base()
50
+    {
51
+        for (notify_list_t::iterator i = notify.begin(), e = notify.end();
52
+                i != e; ++i)
53
+        {
54
+            i->second->unlock();
55
+            i->first->notify_all();
56
+        }
57
+//#ifndef BOOST_NO_EXCEPTIONS
58
+        for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
59
+                i != e; ++i)
60
+        {
61
+            (*i)->notify_deferred();
62
+        }
63
+//#endif
64
+    }
65
+  }
66
+
67
+    namespace
68
+    {
69
+#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
70
+        boost::once_flag current_thread_tls_init_flag;
71
+#else
72
+        boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
73
+#endif
74
+#if defined(UNDER_CE)
75
+        // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
76
+#define TLS_OUT_OF_INDEXES 0xFFFFFFFF
77
+#endif
78
+#if !BOOST_PLAT_WINDOWS_RUNTIME
79
+        DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
80
+#else
81
+        __declspec(thread) boost::detail::thread_data_base* current_thread_data_base;
82
+#endif
83
+
84
+        void create_current_thread_tls_key()
85
+        {
86
+            tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
87
+#if !BOOST_PLAT_WINDOWS_RUNTIME
88
+            current_thread_tls_key=TlsAlloc();
89
+            BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
90
+#endif
91
+        }
92
+
93
+        void cleanup_tls_key()
94
+        {
95
+#if !BOOST_PLAT_WINDOWS_RUNTIME
96
+            if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
97
+            {
98
+                TlsFree(current_thread_tls_key);
99
+                current_thread_tls_key=TLS_OUT_OF_INDEXES;
100
+            }
101
+#endif
102
+        }
103
+
104
+        void set_current_thread_data(detail::thread_data_base* new_data)
105
+        {
106
+            boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
107
+#if BOOST_PLAT_WINDOWS_RUNTIME
108
+            current_thread_data_base = new_data;
109
+#else
110
+            if (current_thread_tls_key != TLS_OUT_OF_INDEXES)
111
+            {
112
+                BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data));
113
+            }
114
+            else
115
+            {
116
+                BOOST_VERIFY(false);
117
+                //boost::throw_exception(thread_resource_error());
118
+            }
119
+#endif
120
+        }
121
+    }
122
+
123
+    namespace detail
124
+    {
125
+      thread_data_base* get_current_thread_data()
126
+      {
127
+#if BOOST_PLAT_WINDOWS_RUNTIME
128
+          return current_thread_data_base;
129
+#else
130
+          if (current_thread_tls_key == TLS_OUT_OF_INDEXES)
131
+          {
132
+              return 0;
133
+          }
134
+          return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
135
+#endif
136
+      }
137
+    }
138
+
139
+    namespace
140
+    {
141
+#ifndef BOOST_HAS_THREADEX
142
+// Windows CE doesn't define _beginthreadex
143
+
144
+        struct ThreadProxyData
145
+        {
146
+            typedef unsigned (__stdcall* func)(void*);
147
+            func start_address_;
148
+            void* arglist_;
149
+            ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
150
+        };
151
+
152
+        DWORD WINAPI ThreadProxy(LPVOID args)
153
+        {
154
+            boost::csbl::unique_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
155
+            DWORD ret=data->start_address_(data->arglist_);
156
+            return ret;
157
+        }
158
+
159
+        inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
160
+                                              void* arglist, unsigned initflag, unsigned* thrdaddr)
161
+        {
162
+            DWORD threadID;
163
+            ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
164
+            HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
165
+                                        data,initflag,&threadID);
166
+            if (hthread==0) {
167
+              delete data;
168
+              return 0;
169
+            }
170
+            *thrdaddr=threadID;
171
+            return reinterpret_cast<uintptr_t const>(hthread);
172
+        }
173
+
174
+#endif
175
+
176
+    }
177
+
178
+    namespace detail
179
+    {
180
+        struct thread_exit_callback_node
181
+        {
182
+            boost::detail::thread_exit_function_base* func;
183
+            thread_exit_callback_node* next;
184
+
185
+            thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
186
+                                      thread_exit_callback_node* next_):
187
+                func(func_),next(next_)
188
+            {}
189
+        };
190
+
191
+    }
192
+
193
+#if BOOST_PLAT_WINDOWS_RUNTIME
194
+    namespace detail
195
+    {
196
+        std::atomic_uint threadCount;
197
+
198
+        bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId)
199
+        {
200
+            Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> threadPoolFactory;
201
+            HRESULT hr = ::Windows::Foundation::GetActivationFactory(
202
+                Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(),
203
+                &threadPoolFactory);
204
+            if (hr != S_OK)
205
+            {
206
+                return false;
207
+            }
208
+
209
+            // Create event for tracking work item completion.
210
+            *thrdId = ++threadCount;
211
+            handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
212
+            if (!completionHandle)
213
+            {
214
+                return false;
215
+            }
216
+            m_completionHandle = completionHandle;
217
+
218
+            // Create new work item.
219
+            Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IWorkItemHandler> workItem =
220
+                Microsoft::WRL::Callback<Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase>>
221
+                ([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *)
222
+            {
223
+                // Add a reference since we need to access the completionHandle after the thread_start_function.
224
+                // This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
225
+                // up closing the handle.
226
+                ::boost::detail::thread_data_base* const thread_info(reinterpret_cast<::boost::detail::thread_data_base*>(parameter));
227
+                intrusive_ptr_add_ref(thread_info);
228
+
229
+                __try
230
+                {
231
+                    address(parameter);
232
+                }
233
+                __finally
234
+                {
235
+                    SetEvent(completionHandle);
236
+                    intrusive_ptr_release(thread_info);
237
+                }
238
+                return S_OK;
239
+            });
240
+
241
+            // Schedule work item on the threadpool.
242
+            Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncAction;
243
+            hr = threadPoolFactory->RunWithPriorityAndOptionsAsync(
244
+                workItem.Get(),
245
+                ABI::Windows::System::Threading::WorkItemPriority_Normal,
246
+                ABI::Windows::System::Threading::WorkItemOptions_TimeSliced,
247
+                &asyncAction);
248
+            return hr == S_OK;
249
+        }
250
+    }
251
+#endif
252
+
253
+    namespace
254
+    {
255
+        void run_thread_exit_callbacks()
256
+        {
257
+            detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false);
258
+            if(current_thread_data)
259
+            {
260
+                while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks)
261
+                {
262
+                    while(current_thread_data->thread_exit_callbacks)
263
+                    {
264
+                        detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
265
+                        current_thread_data->thread_exit_callbacks=current_node->next;
266
+                        if(current_node->func)
267
+                        {
268
+                            (*current_node->func)();
269
+                            boost::detail::heap_delete(current_node->func);
270
+                        }
271
+                        boost::detail::heap_delete(current_node);
272
+                    }
273
+                    while (!current_thread_data->tss_data.empty())
274
+                    {
275
+                        std::map<void const*,detail::tss_data_node>::iterator current
276
+                            = current_thread_data->tss_data.begin();
277
+                        if(current->second.func && (current->second.value!=0))
278
+                        {
279
+                            (*current->second.caller)(current->second.func,current->second.value);
280
+                        }
281
+                        current_thread_data->tss_data.erase(current);
282
+                    }
283
+                }
284
+                set_current_thread_data(0);
285
+            }
286
+        }
287
+
288
+        unsigned __stdcall thread_start_function(void* param)
289
+        {
290
+            detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
291
+            set_current_thread_data(thread_info);
292
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
293
+            BOOST_TRY
294
+            {
295
+#endif
296
+                thread_info->run();
297
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
298
+            }
299
+            BOOST_CATCH(thread_interrupted const&)
300
+            {
301
+            }
302
+            // Unhandled exceptions still cause the application to terminate
303
+            BOOST_CATCH_END
304
+#endif
305
+            run_thread_exit_callbacks();
306
+            return 0;
307
+        }
308
+    }
309
+
310
+    thread::thread() BOOST_NOEXCEPT
311
+    {}
312
+
313
+    bool thread::start_thread_noexcept()
314
+    {
315
+#if BOOST_PLAT_WINDOWS_RUNTIME
316
+         intrusive_ptr_add_ref(thread_info.get());
317
+         if (!thread_info->thread_handle.start(&thread_start_function, thread_info.get(), &thread_info->id))
318
+         {
319
+             intrusive_ptr_release(thread_info.get());
320
+             return false;
321
+         }
322
+         return true;
323
+#else
324
+        uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
325
+        if(!new_thread)
326
+        {
327
+            return false;
328
+        }
329
+        intrusive_ptr_add_ref(thread_info.get());
330
+        thread_info->thread_handle=(detail::win32::handle)(new_thread);
331
+        ResumeThread(thread_info->thread_handle);
332
+        return true;
333
+#endif
334
+    }
335
+
336
+    bool thread::start_thread_noexcept(const attributes& attr)
337
+    {
338
+#if BOOST_PLAT_WINDOWS_RUNTIME
339
+        // Stack size isn't supported with Windows Runtime.
340
+        attr;
341
+        return start_thread_noexcept();
342
+#else
343
+      uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),
344
+                                                CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_info->id);
345
+      if(!new_thread)
346
+      {
347
+        return false;
348
+      }
349
+      intrusive_ptr_add_ref(thread_info.get());
350
+      thread_info->thread_handle=(detail::win32::handle)(new_thread);
351
+      ResumeThread(thread_info->thread_handle);
352
+      return true;
353
+#endif
354
+    }
355
+
356
+    thread::thread(detail::thread_data_ptr data):
357
+        thread_info(data)
358
+    {}
359
+
360
+    namespace
361
+    {
362
+        struct externally_launched_thread:
363
+            detail::thread_data_base
364
+        {
365
+            externally_launched_thread()
366
+            {
367
+                ++count;
368
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
369
+                interruption_enabled=false;
370
+#endif
371
+            }
372
+            ~externally_launched_thread() {
373
+              BOOST_ASSERT(notify.empty());
374
+              notify.clear();
375
+//#ifndef BOOST_NO_EXCEPTIONS
376
+              BOOST_ASSERT(async_states_.empty());
377
+              async_states_.clear();
378
+//#endif
379
+            }
380
+
381
+            void run()
382
+            {}
383
+            void notify_all_at_thread_exit(condition_variable*, mutex*)
384
+            {}
385
+
386
+        private:
387
+            externally_launched_thread(externally_launched_thread&);
388
+            void operator=(externally_launched_thread&);
389
+        };
390
+
391
+        void make_external_thread_data()
392
+        {
393
+            externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
394
+            BOOST_TRY
395
+            {
396
+                set_current_thread_data(me);
397
+            }
398
+            BOOST_CATCH(...)
399
+            {
400
+                detail::heap_delete(me);
401
+                BOOST_RETHROW
402
+            }
403
+            BOOST_CATCH_END
404
+        }
405
+
406
+        detail::thread_data_base* get_or_make_current_thread_data()
407
+        {
408
+            detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
409
+            if(!current_thread_data)
410
+            {
411
+                make_external_thread_data();
412
+                current_thread_data=detail::get_current_thread_data();
413
+            }
414
+            return current_thread_data;
415
+        }
416
+    }
417
+
418
+    thread::id thread::get_id() const BOOST_NOEXCEPT
419
+    {
420
+#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
421
+        detail::thread_data_ptr local_thread_info=(get_thread_info)();
422
+        if(!local_thread_info)
423
+        {
424
+            return 0;
425
+        }
426
+        return local_thread_info->id;
427
+#else
428
+        return thread::id((get_thread_info)());
429
+#endif
430
+    }
431
+
432
+    bool thread::joinable() const BOOST_NOEXCEPT
433
+    {
434
+        detail::thread_data_ptr local_thread_info = (get_thread_info)();
435
+        if(!local_thread_info)
436
+        {
437
+            return false;
438
+        }
439
+        return true;
440
+    }
441
+    bool thread::join_noexcept()
442
+    {
443
+        detail::thread_data_ptr local_thread_info=(get_thread_info)();
444
+        if(local_thread_info)
445
+        {
446
+            this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax());
447
+            release_handle();
448
+            return true;
449
+        }
450
+        else
451
+        {
452
+          return false;
453
+        }
454
+    }
455
+
456
+    bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
457
+    {
458
+      detail::thread_data_ptr local_thread_info=(get_thread_info)();
459
+      if(local_thread_info)
460
+      {
461
+          if(!this_thread::interruptible_wait(this->native_handle(), timeout))
462
+          {
463
+            res=false;
464
+            return true;
465
+          }
466
+          release_handle();
467
+          res=true;
468
+          return true;
469
+      }
470
+      else
471
+      {
472
+        return false;
473
+      }
474
+    }
475
+
476
+    void thread::detach()
477
+    {
478
+        release_handle();
479
+    }
480
+
481
+    void thread::release_handle()
482
+    {
483
+        thread_info=0;
484
+    }
485
+
486
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
487
+    void thread::interrupt()
488
+    {
489
+        detail::thread_data_ptr local_thread_info=(get_thread_info)();
490
+        if(local_thread_info)
491
+        {
492
+            local_thread_info->interrupt();
493
+        }
494
+    }
495
+
496
+    bool thread::interruption_requested() const BOOST_NOEXCEPT
497
+    {
498
+        detail::thread_data_ptr local_thread_info=(get_thread_info)();
499
+        return local_thread_info.get() && (winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
500
+    }
501
+
502
+#endif
503
+
504
+    unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
505
+    {
506
+        detail::win32::system_info info;
507
+        detail::win32::get_system_info(&info);
508
+        return info.dwNumberOfProcessors;
509
+    }
510
+
511
+    unsigned thread::physical_concurrency() BOOST_NOEXCEPT
512
+    {
513
+      // a bit too strict: Windows XP with SP3 would be sufficient
514
+#if BOOST_PLAT_WINDOWS_RUNTIME                                    \
515
+    || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
516
+    || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
517
+        return 0;
518
+#else
519
+        unsigned cores = 0;
520
+        DWORD size = 0;
521
+
522
+        GetLogicalProcessorInformation(NULL, &size);
523
+        if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
524
+            return 0;
525
+        const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
526
+
527
+        std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(Elements);
528
+        if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
529
+            return 0;
530
+
531
+
532
+        for (size_t i = 0; i < Elements; ++i) {
533
+            if (buffer[i].Relationship == RelationProcessorCore)
534
+                ++cores;
535
+        }
536
+        return cores;
537
+#endif
538
+    }
539
+
540
+    thread::native_handle_type thread::native_handle()
541
+    {
542
+        detail::thread_data_ptr local_thread_info=(get_thread_info)();
543
+        if(!local_thread_info)
544
+        {
545
+            return detail::win32::invalid_handle_value;
546
+        }
547
+#if BOOST_PLAT_WINDOWS_RUNTIME
548
+        // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
549
+        return local_thread_info->thread_handle.waitable_handle();
550
+#else
551
+        return (detail::win32::handle)local_thread_info->thread_handle;
552
+#endif
553
+    }
554
+
555
+    detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
556
+    {
557
+        return thread_info;
558
+    }
559
+
560
+    namespace this_thread
561
+    {
562
+#ifndef UNDER_CE
563
+#if !BOOST_PLAT_WINDOWS_RUNTIME
564
+        namespace detail_
565
+        {
566
+            typedef struct _REASON_CONTEXT {
567
+                ULONG Version;
568
+                DWORD Flags;
569
+                union {
570
+                    LPWSTR SimpleReasonString;
571
+                    struct {
572
+                        HMODULE LocalizedReasonModule;
573
+                        ULONG   LocalizedReasonId;
574
+                        ULONG   ReasonStringCount;
575
+                        LPWSTR  *ReasonStrings;
576
+                    } Detailed;
577
+                } Reason;
578
+            } REASON_CONTEXT, *PREASON_CONTEXT;
579
+            typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG);
580
+            static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
581
+            {
582
+                return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE);
583
+            }
584
+#ifdef _MSC_VER
585
+#pragma warning(push)
586
+#pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
587
+#endif
588
+            static inline setwaitabletimerex_t SetWaitableTimerEx()
589
+            {
590
+                static setwaitabletimerex_t setwaitabletimerex_impl;
591
+                if(setwaitabletimerex_impl)
592
+                    return setwaitabletimerex_impl;
593
+                void (*addr)()=(void (*)()) GetProcAddress(
594
+#if !defined(BOOST_NO_ANSI_APIS)
595
+                    GetModuleHandleA("KERNEL32.DLL"),
596
+#else
597
+                    GetModuleHandleW(L"KERNEL32.DLL"),
598
+#endif
599
+                    "SetWaitableTimerEx");
600
+                if(addr)
601
+                    setwaitabletimerex_impl=(setwaitabletimerex_t) addr;
602
+                else
603
+                    setwaitabletimerex_impl=&SetWaitableTimerEx_emulation;
604
+                return setwaitabletimerex_impl;
605
+            }
606
+#ifdef _MSC_VER
607
+#pragma warning(pop)
608
+#endif
609
+        }
610
+#endif
611
+#endif
612
+        bool interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
613
+        {
614
+            detail::win32::handle handles[4]={0};
615
+            unsigned handle_count=0;
616
+            unsigned wait_handle_index=~0U;
617
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
618
+            unsigned interruption_index=~0U;
619
+#endif
620
+            unsigned timeout_index=~0U;
621
+            if(handle_to_wait_for!=detail::win32::invalid_handle_value)
622
+            {
623
+                wait_handle_index=handle_count;
624
+                handles[handle_count++]=handle_to_wait_for;
625
+            }
626
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
627
+            if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled)
628
+            {
629
+                interruption_index=handle_count;
630
+                handles[handle_count++]=detail::get_current_thread_data()->interruption_handle;
631
+            }
632
+#endif
633
+            detail::win32::handle_manager timer_handle;
634
+
635
+#ifndef UNDER_CE
636
+#if !BOOST_PLAT_WINDOWS_RUNTIME
637
+            // Preferentially use coalescing timers for better power consumption and timer accuracy
638
+            if(timeout != detail::internal_platform_timepoint::getMax())
639
+            {
640
+                boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
641
+                timer_handle=CreateWaitableTimer(NULL,false,NULL);
642
+                if(timer_handle!=0)
643
+                {
644
+                    ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
645
+                    if(time_left_msec/20>tolerable)  // 5%
646
+                        tolerable=static_cast<ULONG>(time_left_msec/20);
647
+                    LARGE_INTEGER due_time={{0,0}};
648
+                    if(time_left_msec>0)
649
+                    {
650
+                        due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
651
+                    }
652
+                    bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
653
+                    if(set_time_succeeded)
654
+                    {
655
+                        timeout_index=handle_count;
656
+                        handles[handle_count++]=timer_handle;
657
+                    }
658
+                }
659
+            }
660
+#endif
661
+#endif
662
+
663
+            bool const using_timer=timeout_index!=~0u;
664
+            boost::intmax_t time_left_msec(INFINITE);
665
+            if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
666
+            {
667
+                time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
668
+                if(time_left_msec < 0)
669
+                {
670
+                    time_left_msec = 0;
671
+                }
672
+            }
673
+
674
+            do
675
+            {
676
+                if(handle_count)
677
+                {
678
+                    unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
679
+                    if(notified_index<handle_count)
680
+                    {
681
+                        if(notified_index==wait_handle_index)
682
+                        {
683
+                            return true;
684
+                        }
685
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
686
+                        else if(notified_index==interruption_index)
687
+                        {
688
+                            winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
689
+                            throw thread_interrupted();
690
+                        }
691
+#endif
692
+                        else if(notified_index==timeout_index)
693
+                        {
694
+                            return false;
695
+                        }
696
+                    }
697
+                }
698
+                else
699
+                {
700
+                    detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
701
+                }
702
+
703
+                if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
704
+                {
705
+                    time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
706
+                }
707
+            }
708
+            while(time_left_msec == INFINITE || time_left_msec > 0);
709
+            return false;
710
+        }
711
+
712
+        namespace no_interruption_point
713
+        {
714
+        bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
715
+        {
716
+            detail::win32::handle handles[3]={0};
717
+            unsigned handle_count=0;
718
+            unsigned wait_handle_index=~0U;
719
+            unsigned timeout_index=~0U;
720
+            if(handle_to_wait_for!=detail::win32::invalid_handle_value)
721
+            {
722
+                wait_handle_index=handle_count;
723
+                handles[handle_count++]=handle_to_wait_for;
724
+            }
725
+            detail::win32::handle_manager timer_handle;
726
+
727
+#ifndef UNDER_CE
728
+#if !BOOST_PLAT_WINDOWS_RUNTIME
729
+            // Preferentially use coalescing timers for better power consumption and timer accuracy
730
+            if(timeout != detail::internal_platform_timepoint::getMax())
731
+            {
732
+                boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
733
+                timer_handle=CreateWaitableTimer(NULL,false,NULL);
734
+                if(timer_handle!=0)
735
+                {
736
+                    ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
737
+                    if(time_left_msec/20>tolerable)  // 5%
738
+                        tolerable=static_cast<ULONG>(time_left_msec/20);
739
+                    LARGE_INTEGER due_time={{0,0}};
740
+                    if(time_left_msec>0)
741
+                    {
742
+                        due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
743
+                    }
744
+                    bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
745
+                    if(set_time_succeeded)
746
+                    {
747
+                        timeout_index=handle_count;
748
+                        handles[handle_count++]=timer_handle;
749
+                    }
750
+                }
751
+            }
752
+#endif
753
+#endif
754
+
755
+            bool const using_timer=timeout_index!=~0u;
756
+            boost::intmax_t time_left_msec(INFINITE);
757
+            if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
758
+            {
759
+                time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
760
+                if(time_left_msec < 0)
761
+                {
762
+                    time_left_msec = 0;
763
+                }
764
+            }
765
+
766
+            do
767
+            {
768
+                if(handle_count)
769
+                {
770
+                    unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
771
+                    if(notified_index<handle_count)
772
+                    {
773
+                        if(notified_index==wait_handle_index)
774
+                        {
775
+                            return true;
776
+                        }
777
+                        else if(notified_index==timeout_index)
778
+                        {
779
+                            return false;
780
+                        }
781
+                    }
782
+                }
783
+                else
784
+                {
785
+                    detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
786
+                }
787
+
788
+                if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
789
+                {
790
+                    time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
791
+                }
792
+            }
793
+            while(time_left_msec == INFINITE || time_left_msec > 0);
794
+            return false;
795
+        }
796
+        }
797
+
798
+        thread::id get_id() BOOST_NOEXCEPT
799
+        {
800
+#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
801
+#if BOOST_PLAT_WINDOWS_RUNTIME
802
+            detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
803
+            if (current_thread_data)
804
+            {
805
+                return current_thread_data->id;
806
+            }
807
+#endif
808
+            return winapi::GetCurrentThreadId();
809
+#else
810
+            return thread::id(get_or_make_current_thread_data());
811
+#endif
812
+        }
813
+
814
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
815
+        void interruption_point()
816
+        {
817
+            if(interruption_enabled() && interruption_requested())
818
+            {
819
+                winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
820
+                throw thread_interrupted();
821
+            }
822
+        }
823
+
824
+        bool interruption_enabled() BOOST_NOEXCEPT
825
+        {
826
+            return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
827
+        }
828
+
829
+        bool interruption_requested() BOOST_NOEXCEPT
830
+        {
831
+            return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
832
+        }
833
+#endif
834
+
835
+        void yield() BOOST_NOEXCEPT
836
+        {
837
+            detail::win32::sleep(0);
838
+        }
839
+
840
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
841
+        disable_interruption::disable_interruption() BOOST_NOEXCEPT:
842
+            interruption_was_enabled(interruption_enabled())
843
+        {
844
+            if(interruption_was_enabled)
845
+            {
846
+                detail::get_current_thread_data()->interruption_enabled=false;
847
+            }
848
+        }
849
+
850
+        disable_interruption::~disable_interruption() BOOST_NOEXCEPT
851
+        {
852
+            if(detail::get_current_thread_data())
853
+            {
854
+                detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
855
+            }
856
+        }
857
+
858
+        restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
859
+        {
860
+            if(d.interruption_was_enabled)
861
+            {
862
+                detail::get_current_thread_data()->interruption_enabled=true;
863
+            }
864
+        }
865
+
866
+        restore_interruption::~restore_interruption() BOOST_NOEXCEPT
867
+        {
868
+            if(detail::get_current_thread_data())
869
+            {
870
+                detail::get_current_thread_data()->interruption_enabled=false;
871
+            }
872
+        }
873
+#endif
874
+    }
875
+
876
+    namespace detail
877
+    {
878
+        void add_thread_exit_function(thread_exit_function_base* func)
879
+        {
880
+            detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
881
+            thread_exit_callback_node* const new_node=
882
+                heap_new<thread_exit_callback_node>(
883
+                    func,current_thread_data->thread_exit_callbacks);
884
+            current_thread_data->thread_exit_callbacks=new_node;
885
+        }
886
+
887
+        tss_data_node* find_tss_data(void const* key)
888
+        {
889
+            detail::thread_data_base* const current_thread_data(get_current_thread_data());
890
+            if(current_thread_data)
891
+            {
892
+                std::map<void const*,tss_data_node>::iterator current_node=
893
+                    current_thread_data->tss_data.find(key);
894
+                if(current_node!=current_thread_data->tss_data.end())
895
+                {
896
+                    return &current_node->second;
897
+                }
898
+            }
899
+            return NULL;
900
+        }
901
+
902
+        void* get_tss_data(void const* key)
903
+        {
904
+            if(tss_data_node* const current_node=find_tss_data(key))
905
+            {
906
+                return current_node->value;
907
+            }
908
+            return NULL;
909
+        }
910
+
911
+        void add_new_tss_node(void const* key,
912
+                              detail::tss_data_node::cleanup_caller_t caller,
913
+                              detail::tss_data_node::cleanup_func_t func,
914
+                              void* tss_data)
915
+        {
916
+            detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
917
+            current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data)));
918
+        }
919
+
920
+        void erase_tss_node(void const* key)
921
+        {
922
+            detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
923
+            current_thread_data->tss_data.erase(key);
924
+        }
925
+
926
+        void set_tss_data(void const* key,
927
+                          detail::tss_data_node::cleanup_caller_t caller,
928
+                          detail::tss_data_node::cleanup_func_t func,
929
+                          void* tss_data,bool cleanup_existing)
930
+        {
931
+            if(tss_data_node* const current_node=find_tss_data(key))
932
+            {
933
+                if(cleanup_existing && current_node->func && (current_node->value!=0))
934
+                {
935
+                    (*current_node->caller)(current_node->func,current_node->value);
936
+                }
937
+                if(func || (tss_data!=0))
938
+                {
939
+                    current_node->caller=caller;
940
+                    current_node->func=func;
941
+                    current_node->value=tss_data;
942
+                }
943
+                else
944
+                {
945
+                    erase_tss_node(key);
946
+                }
947
+            }
948
+            else if(func || (tss_data!=0))
949
+            {
950
+                add_new_tss_node(key,caller,func,tss_data);
951
+            }
952
+        }
953
+    }
954
+
955
+    BOOST_THREAD_DECL void __cdecl on_process_enter()
956
+    {}
957
+
958
+    BOOST_THREAD_DECL void __cdecl on_thread_enter()
959
+    {}
960
+
961
+    BOOST_THREAD_DECL void __cdecl on_process_exit()
962
+    {
963
+        boost::cleanup_tls_key();
964
+    }
965
+
966
+    BOOST_THREAD_DECL void __cdecl on_thread_exit()
967
+    {
968
+        boost::run_thread_exit_callbacks();
969
+    }
970
+
971
+    BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
972
+    {
973
+      detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
974
+      if(current_thread_data)
975
+      {
976
+        current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
977
+      }
978
+    }
979
+}
980
+
0 981
new file mode 100755
... ...
@@ -0,0 +1,156 @@
1
+//  thread_primitives.cpp
2
+//
3
+//  (C) Copyright 2018 Andrey Semashev
4
+//
5
+//  Distributed under the Boost Software License, Version 1.0. (See
6
+//  accompanying file LICENSE_1_0.txt or copy at
7
+//  http://www.boost.org/LICENSE_1_0.txt)
8
+
9
+#include <boost/winapi/config.hpp>
10
+#include <boost/winapi/dll.hpp>
11
+#include <boost/winapi/time.hpp>
12
+#include <boost/winapi/event.hpp>
13
+#include <boost/winapi/handles.hpp>
14
+#include <boost/winapi/thread_pool.hpp>
15
+#include <cstdlib>
16
+#include <boost/config.hpp>
17
+#include <boost/cstdint.hpp>
18
+#include <boost/memory_order.hpp>
19
+#include <boost/atomic/atomic.hpp>
20
+#include <boost/thread/win32/interlocked_read.hpp>
21
+#include <boost/thread/win32/thread_primitives.hpp>
22
+
23
+namespace boost {
24
+namespace detail {
25
+namespace win32 {
26
+
27
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
28
+
29
+// Directly use API from Vista and later
30
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64;
31
+
32
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
33
+
34
+namespace {
35
+
36
+enum init_state
37
+{
38
+    uninitialized = 0,
39
+    in_progress,
40
+    initialized
41
+};
42
+
43
+struct get_tick_count64_state
44
+{
45
+    boost::atomic< uint64_t > ticks;
46
+    boost::atomic< init_state > init;
47
+    boost::winapi::HANDLE_ wait_event;
48
+    boost::winapi::HANDLE_ wait_handle;
49
+};
50
+
51
+// Zero-initialized initially
52
+BOOST_ALIGNMENT(64) static get_tick_count64_state g_state;
53
+
54
+//! Artifical implementation of GetTickCount64
55
+ticks_type WINAPI get_tick_count64()
56
+{
57
+    uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
58
+
59
+    uint32_t new_ticks = boost::winapi::GetTickCount();
60
+
61
+    uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
62
+    uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
63
+
64
+    g_state.ticks.store(new_state, boost::memory_order_release);
65
+
66
+    return new_state;
67
+}
68
+
69
+//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
70
+void NTAPI refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_)
71
+{
72
+    get_tick_count64();
73
+}
74
+
75
+//! Cleanup function to stop get_tick_count64 refreshes
76
+void cleanup_get_tick_count64()
77
+{
78
+    if (g_state.wait_handle)
79
+    {
80
+        boost::winapi::UnregisterWait(g_state.wait_handle);
81
+        g_state.wait_handle = NULL;
82
+    }
83
+
84
+    if (g_state.wait_event)
85
+    {
86
+        boost::winapi::CloseHandle(g_state.wait_event);
87
+        g_state.wait_event = NULL;
88
+    }
89
+}
90
+
91
+ticks_type WINAPI get_tick_count_init()
92
+{
93
+    boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
94
+    if (hKernel32)
95
+    {
96
+      // GetProcAddress returns a pointer to some function. It can return
97
+      // pointers to different functions, so it has to return something that is
98
+      // suitable to store any pointer to function. Microsoft chose FARPROC,
99
+      // which is int (WINAPI *)() on 32-bit Windows. The user is supposed to
100
+      // know the signature of the function he requests and perform a cast
101
+      // (which is a nop on this platform). The result is a pointer to function
102
+      // with the required signature, which is bitwise equal to what
103
+      // GetProcAddress returned.
104
+      // However, gcc >= 8 warns about that.
105
+#if defined(BOOST_GCC) && BOOST_GCC >= 80000
106
+#pragma GCC diagnostic push
107
+#pragma GCC diagnostic ignored "-Wcast-function-type"
108
+#endif
109
+        boost::detail::win32::detail::gettickcount64_t p =
110
+            (boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
111
+#if defined(BOOST_GCC) && BOOST_GCC >= 80000
112
+#pragma GCC diagnostic pop
113
+#endif
114
+        if (p)
115
+        {
116
+            // Use native API
117
+            boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
118
+            return p();
119
+        }
120
+    }
121
+
122
+    // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
123
+    init_state old_init = uninitialized;
124
+    if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed))
125
+    {
126
+        if (!g_state.wait_event)
127
+            g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false);
128
+        if (g_state.wait_event)
129
+        {
130
+            boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_);
131
+            if (res)
132
+            {
133
+                std::atexit(&cleanup_get_tick_count64);
134
+
135
+                boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
136
+                g_state.init.store(initialized, boost::memory_order_release);
137
+                goto finish;
138
+            }
139
+        }
140
+
141
+        g_state.init.store(uninitialized, boost::memory_order_release);
142
+    }
143
+
144
+finish:
145
+    return get_tick_count64();
146
+}
147
+
148
+} // namespace
149
+
150
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
151
+
152
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
153
+
154
+} // namespace win32
155
+} // namespace detail
156
+} // namespace boost
0 157
new file mode 100755
... ...
@@ -0,0 +1,87 @@
1
+// (C) Copyright Michael Glassford 2004.
2
+// Use, modification and distribution are subject to the
3
+// Boost Software License, Version 1.0. (See accompanying file
4
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
+
6
+#include <boost/winapi/config.hpp>
7
+#include <boost/thread/detail/config.hpp>
8
+
9
+
10
+#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)
11
+
12
+    #include <boost/thread/detail/tss_hooks.hpp>
13
+
14
+    #include <windows.h>
15
+
16
+    #if defined(BOOST_BORLANDC)
17
+        extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
18
+    #elif defined(BOOST_EMBTC)
19
+        extern "C" int _libmain(DWORD dwReason)
20
+    #elif defined(_WIN32_WCE)
21
+        extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
22
+    #else
23
+        extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
24
+    #endif
25
+    {
26
+        switch(dwReason)
27
+        {
28
+            case DLL_PROCESS_ATTACH:
29
+            {
30
+                boost::on_process_enter();
31
+                boost::on_thread_enter();
32
+                break;
33
+            }
34
+
35
+            case DLL_THREAD_ATTACH:
36
+            {
37
+                boost::on_thread_enter();
38
+                break;
39
+            }
40
+
41
+            case DLL_THREAD_DETACH:
42
+            {
43
+                boost::on_thread_exit();
44
+                break;
45
+            }
46
+
47
+            case DLL_PROCESS_DETACH:
48
+            {
49
+                boost::on_thread_exit();
50
+                boost::on_process_exit();
51
+                break;
52
+            }
53
+        }
54
+
55
+        return TRUE;
56
+    }
57
+
58
+namespace boost
59
+{
60
+    void tss_cleanup_implemented()
61
+    {
62
+        /*
63
+        This function's sole purpose is to cause a link error in cases where
64
+        automatic tss cleanup is not implemented by Boost.Threads as a
65
+        reminder that user code is responsible for calling the necessary
66
+        functions at the appropriate times (and for implementing an a
67
+        tss_cleanup_implemented() function to eliminate the linker's
68
+        missing symbol error).
69
+
70
+        If Boost.Threads later implements automatic tss cleanup in cases
71
+        where it currently doesn't (which is the plan), the duplicate
72
+        symbol error will warn the user that their custom solution is no
73
+        longer needed and can be removed.
74
+        */
75
+    }
76
+}
77
+
78
+#else //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)
79
+
80
+#ifdef _MSC_VER
81
+// Prevent LNK4221 warning with link=static
82
+namespace boost { namespace link_static_warning_inhibit {
83
+    extern __declspec(dllexport) void foo() { }
84
+} }
85
+#endif
86
+
87
+#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)
0 88
new file mode 100755
... ...
@@ -0,0 +1,346 @@
1
+// $Id$
2
+// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
3
+// (C) Copyright 2007 Roland Schwarz
4
+// (C) Copyright 2007 Anthony Williams
5
+// (C) Copyright 2007 David Deakins
6
+// Use, modification and distribution are subject to the
7
+// Boost Software License, Version 1.0. (See accompanying file
8
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
+
10
+#include <boost/winapi/config.hpp>
11
+#include <boost/thread/detail/config.hpp>
12
+
13
+#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB)
14
+
15
+#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
16
+
17
+#include <boost/thread/detail/tss_hooks.hpp>
18
+
19
+#include <windows.h>
20
+
21
+#include <cstdlib>
22
+
23
+namespace boost
24
+{
25
+    void tss_cleanup_implemented() {}
26
+}
27
+
28
+namespace {
29
+    void NTAPI on_tls_callback(void* , DWORD dwReason, PVOID )
30
+    {
31
+        switch (dwReason)
32
+        {
33
+        case DLL_THREAD_DETACH:
34
+        {
35
+            boost::on_thread_exit();
36
+            break;
37
+        }
38
+        }
39
+    }
40
+}
41
+
42
+#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32__) || (__MINGW32_MAJOR_VERSION >3) ||   \
43
+    ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
44
+extern "C"
45
+{
46
+    PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
47
+}
48
+#else
49
+extern "C" {
50
+
51
+    void (* after_ctors )() __attribute__((section(".ctors")))     = boost::on_process_enter;
52
+    void (* before_dtors)() __attribute__((section(".dtors")))     = boost::on_thread_exit;
53
+    void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit;
54
+
55
+    ULONG __tls_index__ = 0;
56
+    char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
57
+    char __tls_start__ __attribute__((section(".tls"))) = 0;
58
+
59
+
60
+    PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
61
+    PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
62
+}
63
+extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
64
+{
65
+        (DWORD) &__tls_start__,
66
+        (DWORD) &__tls_end__,
67
+        (DWORD) &__tls_index__,
68
+        (DWORD) (&__crt_xl_start__+1),
69
+        (DWORD) 0,
70
+        (DWORD) 0
71
+};
72
+#endif
73
+
74
+
75
+#elif  defined(_MSC_VER) && !defined(UNDER_CE)
76
+
77
+    #include <boost/thread/detail/tss_hooks.hpp>
78
+
79
+    #include <stdlib.h>
80
+
81
+    #include <windows.h>
82
+
83
+
84
+// _pRawDllMainOrig can be defined by including boost/thread/win32/mfc_thread_init.hpp
85
+// into your dll; it ensures that MFC-Dll-initialization will be done properly
86
+// The following code is adapted from the MFC-Dll-init code
87
+/*
88
+ * _pRawDllMainOrig MUST be an extern const variable, which will be aliased to
89
+ * _pDefaultRawDllMainOrig if no real user definition is present, thanks to the
90
+ * alternatename directive.
91
+ */
92
+
93
+// work at least with _MSC_VER 1500 (MSVC++ 9.0, VS 2008)
94
+#if (_MSC_VER >= 1500)
95
+
96
+extern "C" {
97
+extern BOOL (WINAPI * const _pRawDllMainOrig)(HINSTANCE, DWORD, LPVOID);
98
+extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HINSTANCE, DWORD, LPVOID) = NULL;
99
+#if defined (_M_IX86)
100
+#pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig")
101
+#elif defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64)
102
+#pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig")
103
+#else  /* unknown Windows target (not x86, x64, ARM, ARM64) */
104
+#error Unsupported platform
105
+#endif  /* defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) */
106
+}
107
+
108
+#endif
109
+
110
+
111
+
112
+
113
+    //Definitions required by implementation
114
+    #if (_MSC_VER < 1300) || ((_MSC_VER > 1900) && (_MSC_VER < 1910)) // 1300 == VC++ 7.0, 1900 == VC++ 14.0, 1910 == VC++ 2017
115
+        typedef void ( __cdecl *_PVFV_ )();
116
+        typedef void ( __cdecl *_PIFV_ )();
117
+        #define INIRETSUCCESS_V
118
+        #define INIRETSUCCESS_I
119
+        #define PVAPI_V void __cdecl
120
+        #define PVAPI_I void __cdecl
121
+    #elif (_MSC_VER >= 1910)
122
+        typedef void ( __cdecl *_PVFV_ )();
123
+        typedef int ( __cdecl *_PIFV_ )();
124
+        #define INIRETSUCCESS_V
125
+        #define INIRETSUCCESS_I 0
126
+        #define PVAPI_V void __cdecl
127
+        #define PVAPI_I int __cdecl
128
+    #else
129
+        typedef int ( __cdecl *_PVFV_ )();
130
+        typedef int ( __cdecl *_PIFV_ )();
131
+        #define INIRETSUCCESS_V 0
132
+        #define INIRETSUCCESS_I 0
133
+        #define PVAPI_V int __cdecl
134
+        #define PVAPI_I int __cdecl
135
+    #endif
136
+
137
+    typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
138
+
139
+    //Symbols for connection to the runtime environment
140
+
141
+    extern "C"
142
+    {
143
+        extern DWORD _tls_used; //the tls directory (located in .rdata segment)
144
+        extern _TLSCB __xl_a[], __xl_z[];    //tls initializers */
145
+    }
146
+
147
+    namespace
148
+    {
149
+        //Forward declarations
150
+
151
+        static PVAPI_I on_tls_prepare();
152
+        static PVAPI_V on_process_init();
153
+        static PVAPI_V on_process_term();
154
+        static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
155
+    }
156
+
157
+    namespace boost
158
+    {
159
+        //The .CRT$Xxx information is taken from Codeguru:
160
+        //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
161
+
162
+        // Variables below are not referenced anywhere and
163
+        // to not be optimized away has to have external linkage
164
+
165
+#if (_MSC_VER >= 1400)
166
+#pragma section(".CRT$XIU",long,read)
167
+#pragma section(".CRT$XCU",long,read)
168
+#pragma section(".CRT$XTU",long,read)
169
+#pragma section(".CRT$XLC",long,read)
170
+        extern const __declspec(allocate(".CRT$XLC")) _TLSCB p_tls_callback = on_tls_callback;
171
+        extern const __declspec(allocate(".CRT$XIU")) _PIFV_ p_tls_prepare = on_tls_prepare;
172
+        extern const __declspec(allocate(".CRT$XCU")) _PVFV_ p_process_init = on_process_init;
173
+        extern const __declspec(allocate(".CRT$XTU")) _PVFV_ p_process_term = on_process_term;
174
+#else
175
+        #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
176
+        #   pragma data_seg(push, old_seg)
177
+        #endif
178
+            //Callback to run tls glue code first.
179
+            //I don't think it is necessary to run it
180
+            //at .CRT$XIB level, since we are only
181
+            //interested in thread detachement. But
182
+            //this could be changed easily if required.
183
+
184
+            #pragma data_seg(".CRT$XIU")
185
+            extern const _PIFV_ p_tls_prepare = on_tls_prepare;
186
+            #pragma data_seg()
187
+
188
+            //Callback after all global ctors.
189
+
190
+            #pragma data_seg(".CRT$XCU")
191
+            extern const _PVFV_ p_process_init = on_process_init;
192
+            #pragma data_seg()
193
+
194
+            //Callback for tls notifications.
195
+
196
+            #pragma data_seg(".CRT$XLB")
197
+            extern const _TLSCB p_thread_callback = on_tls_callback;
198
+            #pragma data_seg()
199
+            //Callback for termination.
200
+
201
+            #pragma data_seg(".CRT$XTU")
202
+            extern const _PVFV_ p_process_term = on_process_term;
203
+            #pragma data_seg()
204
+        #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
205
+        #   pragma data_seg(pop, old_seg)
206
+        #endif
207
+#endif
208
+    } // namespace boost
209
+
210
+    namespace
211
+    {
212
+#ifdef BOOST_MSVC
213
+#pragma warning(push)
214
+#pragma warning(disable:4189)
215
+#endif
216
+
217
+        PVAPI_I on_tls_prepare()
218
+        {
219
+            //The following line has an important side effect:
220
+            //if the TLS directory is not already there, it will
221
+            //be created by the linker. In other words, it forces a tls
222
+            //directory to be generated by the linker even when static tls
223
+            //(i.e. __declspec(thread)) is not used.
224
+            //The volatile should prevent the optimizer
225
+            //from removing the reference.
226
+
227
+            DWORD volatile dw = _tls_used;
228
+
229
+            #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
230
+                _TLSCB* pfbegin = __xl_a;
231
+                _TLSCB* pfend = __xl_z;
232
+                _TLSCB* pfdst = pfbegin;
233
+                //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
234
+
235
+                //The following loop will merge the address pointers
236
+                //into a contiguous area, since the tlssup code seems
237
+                //to require this (at least on MSVC 6)
238
+
239
+                while (pfbegin < pfend)
240
+                {
241
+                    if (*pfbegin != 0)
242
+                    {
243
+                        *pfdst = *pfbegin;
244
+                        ++pfdst;
245
+                    }
246
+                    ++pfbegin;
247
+                }
248
+
249
+                *pfdst = 0;
250
+            #endif
251
+
252
+            return INIRETSUCCESS_I;
253
+        }
254
+#ifdef BOOST_MSVC
255
+#pragma warning(pop)
256
+#endif
257
+
258
+        PVAPI_V on_process_init()
259
+        {
260
+            //Schedule on_thread_exit() to be called for the main
261
+            //thread before destructors of global objects have been
262
+            //called.
263
+
264
+            //It will not be run when 'quick' exiting the
265
+            //library; however, this is the standard behaviour
266
+            //for destructors of global objects, so that
267
+            //shouldn't be a problem.
268
+
269
+            atexit(boost::on_thread_exit);
270
+
271
+            //Call Boost process entry callback here
272
+
273
+            boost::on_process_enter();
274
+
275
+            return INIRETSUCCESS_V;
276
+        }
277
+
278
+        PVAPI_V on_process_term()
279
+        {
280
+            boost::on_process_exit();
281
+            return INIRETSUCCESS_V;
282
+        }
283
+
284
+        void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
285
+        {
286
+            switch (dwReason)
287
+            {
288
+            case DLL_THREAD_DETACH:
289
+                boost::on_thread_exit();
290
+                break;
291
+            }
292
+        }
293
+
294
+#if (_MSC_VER >= 1500)
295
+        BOOL WINAPI dll_callback(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
296
+#else
297
+        BOOL WINAPI dll_callback(HINSTANCE, DWORD dwReason, LPVOID)
298
+#endif
299
+        {
300
+            switch (dwReason)
301
+            {
302
+            case DLL_THREAD_DETACH:
303
+                boost::on_thread_exit();
304
+                break;
305
+            case DLL_PROCESS_DETACH:
306
+                boost::on_process_exit();
307
+                break;
308
+            }
309
+
310
+#if (_MSC_VER >= 1500)
311
+            if( _pRawDllMainOrig )
312
+            {
313
+                return _pRawDllMainOrig(hInstance, dwReason, lpReserved);
314
+            }
315
+#endif
316
+            return true;
317
+        }
318
+    } //namespace
319
+
320
+extern "C"
321
+{
322
+    extern BOOL (WINAPI * const _pRawDllMain)(HINSTANCE, DWORD, LPVOID)=&dll_callback;
323
+}
324
+namespace boost
325
+{
326
+    void tss_cleanup_implemented()
327
+    {
328
+        /*
329
+        This function's sole purpose is to cause a link error in cases where
330
+        automatic tss cleanup is not implemented by Boost.Threads as a
331
+        reminder that user code is responsible for calling the necessary
332
+        functions at the appropriate times (and for implementing an a
333
+        tss_cleanup_implemented() function to eliminate the linker's
334
+        missing symbol error).
335
+
336
+        If Boost.Threads later implements automatic tss cleanup in cases
337
+        where it currently doesn't (which is the plan), the duplicate
338
+        symbol error will warn the user that their custom solution is no
339
+        longer needed and can be removed.
340
+        */
341
+    }
342
+}
343
+
344
+#endif //defined(_MSC_VER) && !defined(UNDER_CE)
345
+
346
+#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB)