1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3  *  Main authors:
4  *     Christian Schulte <schulte@gecode.org>
5  *
6  *  Copyright:
7  *     Christian Schulte, 2009
8  *
9  *  Bugfixes provided by:
10  *     David Rijsman <david.rijsman@quintiq.com>
11  *
12  *  This file is part of Gecode, the generic constraint
13  *  development environment:
14  *     http://www.gecode.org
15  *
16  *  Permission is hereby granted, free of charge, to any person obtaining
17  *  a copy of this software and associated documentation files (the
18  *  "Software"), to deal in the Software without restriction, including
19  *  without limitation the rights to use, copy, modify, merge, publish,
20  *  distribute, sublicense, and/or sell copies of the Software, and to
21  *  permit persons to whom the Software is furnished to do so, subject to
22  *  the following conditions:
23  *
24  *  The above copyright notice and this permission notice shall be
25  *  included in all copies or substantial portions of the Software.
26  *
27  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34  *
35  */
36 
37 #include <cstddef>
38 
39 #ifdef GECODE_THREADS_WINDOWS
40 
41 #ifndef NOMINMAX
42 #  define NOMINMAX
43 #endif
44 
45 #ifndef _WIN32_WINNT
46 #  define _WIN32_WINNT 0x400
47 #endif
48 
49 #ifndef WIN32_LEAN_AND_MEAN
50 #  define WIN32_LEAN_AND_MEAN
51 #endif
52 
53 #include <windows.h>
54 
55 #endif
56 
57 #ifdef GECODE_THREADS_PTHREADS
58 
59 #include <pthread.h>
60 
61 #ifdef GECODE_THREADS_OSX_UNFAIR
62 
63 #include <os/lock.h>
64 #include <libkern/OSAtomic.h>
65 
66 #endif
67 
68 #endif
69 
70 /**
71  * \defgroup FuncSupportThread Simple thread and synchronization support
72  *
73  * This is very simplistic, just enough for parallel search engines. Do
74  * not mistake it for a full-fledged thread package.
75  *
76  * If the platform supports threads, the macro GECODE_HAS_THREADS is
77  * defined. If threads are not supported, all classes are
78  * still available, but are noops with the exception of trying to
79  * create a new thread which will throw an exception.
80  *
81  *
82  * \ingroup FuncSupport
83  */
84 
85 namespace Gecode { namespace Support {
86 
87   /**
88    * \brief A mutex for mutual exclausion among several threads
89    *
90    * It is not specified whether the mutex is recursive or not.
91    * Likewise, there is no guarantee of fairness among the
92    * blocking threads.
93    *
94    * \ingroup FuncSupportThread
95    */
96   class Mutex {
97   private:
98 #if defined(GECODE_THREADS_WINDOWS)
99     /// Use a simple but more efficient critical section on Windows
100     CRITICAL_SECTION w_cs;
101 #elif defined(GECODE_THREADS_OSX_UNFAIR)
102     /// Use unfair lock on macOS if available, OSSpinLock on older macOS
103     union {
104       os_unfair_lock unfair_lck;
105 #pragma clang diagnostic push
106 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
107       OSSpinLock spin_lck;
108 #pragma clang diagnostic pop
109     } u;
110 #elif defined(GECODE_THREADS_PTHREADS)
111     /// The Pthread mutex
112     pthread_mutex_t p_m;
113 #else
114 #error No suitable mutex implementation found
115 #endif
116   public:
117     /// Initialize mutex
118     Mutex(void);
119     /// Acquire the mutex and possibly block
120     void acquire(void);
121     /// Try to acquire the mutex, return true if succesful
122     bool tryacquire(void);
123     /// Release the mutex
124     void release(void);
125     /// Delete mutex
126     ~Mutex(void);
127     /// Allocate memory from heap
128     static void* operator new(size_t s);
129     /// Free memory allocated from heap
130     static void  operator delete(void* p);
131   private:
132     /// A mutex cannot be copied
Mutex(const Mutex &)133     Mutex(const Mutex&) {}
134     /// A mutex cannot be assigned
operator =(const Mutex &)135     void operator=(const Mutex&) {}
136   };
137 
138 #ifndef GECODE_THREADS_PTHREADS_SPINLOCK
139 
140   typedef Mutex FastMutex;
141 
142 #else
143 
144   /**
145    * \brief A fast mutex for mutual exclausion among several threads
146    *
147    * This mutex is implemeneted using spin locks on some platforms
148    * and is not guaranteed to be compatible with events. It should be used
149    * for low-contention locks that are only acquired for short periods of
150    * time.
151    *
152    * It is not specified whether the mutex is recursive or not.
153    * Likewise, there is no guarantee of fairness among the
154    * blocking threads.
155    *
156    * \ingroup FuncSupportThread
157    */
158   class FastMutex {
159   private:
160     /// The Pthread spinlock
161     pthread_spinlock_t p_s;
162   public:
163     /// Initialize mutex
164     FastMutex(void);
165     /// Acquire the mutex and possibly block
166     void acquire(void);
167     /// Try to acquire the mutex, return true if succesful
168     bool tryacquire(void);
169     /// Release the mutex
170     void release(void);
171     /// Delete mutex
172     ~FastMutex(void);
173     /// Allocate memory from heap
174     static void* operator new(size_t s);
175     /// Free memory allocated from heap
176     static void  operator delete(void* p);
177   private:
178     /// A mutex cannot be copied
FastMutex(const FastMutex &)179     FastMutex(const FastMutex&) {}
180     /// A mutex cannot be assigned
operator =(const FastMutex &)181     void operator=(const FastMutex&) {}
182   };
183 
184 #endif
185 
186   /**
187    * \brief A lock as a scoped frontend for a mutex
188    *
189    * \ingroup FuncSupportThread
190    */
191   class Lock {
192   private:
193     /// The mutex used for the lock
194     Mutex& m;
195   public:
196     /// Enter lock
197     Lock(Mutex& m0);
198     /// Leave lock
199     ~Lock(void);
200   private:
201     /// A lock cannot be copied
Lock(const Lock & l)202     Lock(const Lock& l) : m(l.m) {}
203     /// A lock cannot be assigned
operator =(const Lock &)204     void operator=(const Lock&) {}
205   };
206 
207   /**
208    * \brief An event for synchronization
209    *
210    * An event can be waited on by a single thread until the event is
211    * signalled.
212    *
213    * \ingroup FuncSupportThread
214    */
215   class Event {
216   private:
217 #ifdef GECODE_THREADS_WINDOWS
218     /// The Windows specific handle to an event
219     HANDLE w_h;
220 #endif
221 #ifdef GECODE_THREADS_PTHREADS
222     /// The Pthread mutex
223     pthread_mutex_t p_m;
224     /// The Pthread condition variable
225     pthread_cond_t p_c;
226     /// Whether the event is signalled
227     bool p_s;
228 #endif
229   public:
230     /// Initialize event
231     Event(void);
232     /// Signal the event
233     void signal(void);
234     /// Wait until the event becomes signalled
235     void wait(void);
236     /// Delete event
237     ~Event(void);
238   private:
239     /// An event cannot be copied
Event(const Event &)240     Event(const Event&) {}
241     /// An event cannot be assigned
operator =(const Event &)242     void operator=(const Event&) {}
243   };
244 
245   /**
246    * \brief An interface for objects that can be called after a
247    *        thread has terminated (after running the thread's destructor)
248    *
249    * \ingroup FuncSupportThread
250    */
251   class Terminator {
252   public:
253     /// Destructor
~Terminator()254     virtual ~Terminator() {}
255     /// The function that is called when the thread has terminated
256     virtual void terminated(void) = 0;
257   };
258 
259   /**
260    * \brief An interface for objects that can be run by a thread
261    *
262    * \ingroup FuncSupportThread
263    */
264   class Runnable {
265   private:
266     /// Whether to delete the object when terminated
267     bool d;
268   public:
269     /// Initialize, \a d defines whether object is deleted when terminated
270     Runnable(bool d=true);
271     /// Set whether to delete upon termination
272     void todelete(bool d);
273     /// Return whether to be deleted upon termination
274     bool todelete(void) const;
275     /// Return terminator object
terminator(void) const276     virtual Terminator* terminator(void) const { return nullptr; }
277     /// The function that is executed when the thread starts
278     virtual void run(void) = 0;
279     /// Destructor
~Runnable(void)280     virtual ~Runnable(void) {}
281     /// Allocate memory from heap
282     static void* operator new(size_t s);
283     /// Free memory allocated from heap
284     static void  operator delete(void* p);
285   };
286 
287   /**
288    * \brief Simple threads
289    *
290    * Threads cannot be created, only runnable objects can be submitted
291    * for execution by a thread. Threads are pooled to avoid
292    * creation/destruction of threads as much as possible.
293    *
294    * \ingroup FuncSupportThread
295    */
296   class Thread {
297   public:
298     /// A real thread
299     class Run {
300     public:
301       /// Next idle thread
302       Run* n;
303       /// Runnable object to execute
304       Runnable* r;
305       /// Event to wait for next runnable object to execute
306       Event e;
307       /// Mutex for synchronization
308       Mutex m;
309       /// Create a new thread
310       GECODE_SUPPORT_EXPORT Run(Runnable* r);
311       /// Infinite loop for execution
312       GECODE_SUPPORT_EXPORT void exec(void);
313       /// Run a runnable object
314       void run(Runnable* r);
315       /// Allocate memory from heap
316       static void* operator new(size_t s);
317       /// Free memory allocated from heap
318       static void  operator delete(void* p);
319     };
320     /// Mutex for synchronization
321     GECODE_SUPPORT_EXPORT static Mutex* m(void);
322     /// Idle runners
323     GECODE_SUPPORT_EXPORT static Run* idle;
324   public:
325     /**
326      * \brief Construct a new thread and run \a r
327      *
328      * After \a r terminates, \a r is deleted. After that, the thread
329      * terminates.
330      *
331      * If the operating system does not support any threads, throws an
332      * exception of type Support::OperatingSystemError.
333      */
334     static void run(Runnable* r);
335     /// Put current thread to sleep for \a ms milliseconds
336     static void sleep(unsigned int ms);
337     /// Return number of processing units (1 if information not available)
338     static unsigned int npu(void);
339     /// acquire mutex \a m globally and possibly lock
340     GECODE_SUPPORT_EXPORT static void acquireGlobalMutex(Mutex* m);
341     /// release globally acquired mutex \a m
342     GECODE_SUPPORT_EXPORT static void releaseGlobalMutex(Mutex* m);
343   private:
344     /// A thread cannot be copied
Thread(const Thread &)345     Thread(const Thread&) {}
346     /// A thread cannot be assigned
operator =(const Thread &)347     void operator=(const Thread&) {}
348   };
349 
350 }}
351 
352 // STATISTICS: support-any
353