add PBD::DEBUG bits for WavesAudio and WavesMIDI
[ardour.git] / libs / pbd / pthread_utils.cc
1 /*
2     Copyright (C) 2002 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <set>
22 #include <string>
23 #include <cstring>
24 #include <stdint.h>
25
26 #include "pbd/pthread_utils.h"
27 #ifdef WINE_THREAD_SUPPORT
28 #include <fst.h>
29 #endif
30
31 #ifdef COMPILER_MSVC
32 DECLARE_DEFAULT_COMPARISONS(pthread_t)  // Needed for 'DECLARE_DEFAULT_COMPARISONS'. Objects in an STL container can be
33                                         // searched and sorted. Thus, when instantiating the container, MSVC complains
34                                         // if the type of object being contained has no appropriate comparison operators
35                                         // defined (specifically, if operators '<' and '==' are undefined). This seems
36                                         // to be the case with ptw32 'pthread_t' which is a simple struct.
37 #endif
38
39 using namespace std;
40
41 typedef std::list<pthread_t> ThreadMap;
42 static ThreadMap all_threads;
43 static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
44 static Glib::Threads::Private<char> thread_name (free);
45
46 namespace PBD {
47         PBD::Signal4<void,std::string, pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
48 }
49
50 using namespace PBD;
51
52 static int thread_creator (pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg)
53 {
54 #ifdef WINE_THREAD_SUPPORT
55        return wine_pthread_create (thread_id, attr, function, arg);
56 #else
57        return pthread_create (thread_id, attr, function, arg);
58 #endif
59 }
60
61 void
62 PBD::notify_gui_about_thread_creation (std::string target_gui, pthread_t thread, std::string str, int request_count)
63 {
64         ThreadCreatedWithRequestSize (target_gui, thread, str, request_count);
65 }
66
67 struct ThreadStartWithName {
68     void* (*thread_work)(void*);
69     void* arg;
70     std::string name;
71     
72     ThreadStartWithName (void* (*f)(void*), void* a, const std::string& s)
73             : thread_work (f), arg (a), name (s) {}
74 };
75
76 static void*
77 fake_thread_start (void* arg)
78 {
79         ThreadStartWithName* ts = (ThreadStartWithName*) arg;
80         void* (*thread_work)(void*) = ts->thread_work;
81         void* thread_arg = ts->arg;
82
83         /* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
84
85         pthread_set_name (ts->name.c_str());
86
87         /* we don't need this object anymore */
88
89         delete ts;
90
91         /* actually run the thread's work function */
92
93         void* ret = thread_work (thread_arg);
94
95         /* cleanup */
96
97         pthread_mutex_lock (&thread_map_lock);
98
99         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
100                 if (pthread_equal ((*i), pthread_self())) {
101                         all_threads.erase (i);
102                         break;
103                 }
104         }
105
106         pthread_mutex_unlock (&thread_map_lock);
107
108         /* done */
109
110         return ret;
111 }
112
113 int  
114 pthread_create_and_store (string name, pthread_t  *thread, void * (*start_routine)(void *), void * arg)
115 {
116         pthread_attr_t default_attr;
117         int ret;
118
119         // set default stack size to sensible default for memlocking
120         pthread_attr_init(&default_attr);
121         pthread_attr_setstacksize(&default_attr, 500000);
122
123         ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
124
125         if ((ret = thread_creator (thread, &default_attr, fake_thread_start, ts)) == 0) {
126                 pthread_mutex_lock (&thread_map_lock);
127                 all_threads.push_back (*thread);
128                 pthread_mutex_unlock (&thread_map_lock);
129         }
130
131         pthread_attr_destroy(&default_attr);
132
133         return ret;
134 }
135
136 void
137 pthread_set_name (const char *str)
138 {
139         /* copy string and delete it when exiting */
140         
141         thread_name.set (strdup (str));
142 }
143
144 const char *
145 pthread_name ()
146 {
147         const char* str = thread_name.get ();
148
149         if (str) {
150                 return str;
151         } 
152         return "unknown";
153 }
154
155 void
156 pthread_kill_all (int signum) 
157 {       
158         pthread_mutex_lock (&thread_map_lock);
159         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
160                 if (!pthread_equal ((*i), pthread_self())) {
161                         pthread_kill ((*i), signum);
162                 }
163         }
164         all_threads.clear();
165         pthread_mutex_unlock (&thread_map_lock);
166 }
167
168 void
169 pthread_cancel_all () 
170 {       
171         pthread_mutex_lock (&thread_map_lock);
172
173         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ) {
174
175                 ThreadMap::iterator nxt = i;
176                 ++nxt;
177
178                 if (!pthread_equal ((*i), pthread_self())) {
179                         pthread_cancel ((*i));
180                 }
181
182                 i = nxt;
183         }
184         all_threads.clear();
185         pthread_mutex_unlock (&thread_map_lock);
186 }
187
188 void
189 pthread_cancel_one (pthread_t thread) 
190 {       
191         pthread_mutex_lock (&thread_map_lock);
192         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
193                 if (pthread_equal ((*i), thread)) {
194                         all_threads.erase (i);
195                         break;
196                 }
197         }
198
199         pthread_cancel (thread);
200         pthread_mutex_unlock (&thread_map_lock);
201 }
202