Merge branch 'windows' of git.ardour.org:ardour/ardour into windows
[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         pthread_set_name (ts->name.c_str());
84
85         delete ts;
86         /* name will be deleted by the default handler for GStaticPrivate, when the thread exits */
87
88         return thread_work (thread_arg);
89 }
90
91 int  
92 pthread_create_and_store (string name, pthread_t  *thread, void * (*start_routine)(void *), void * arg)
93 {
94         pthread_attr_t default_attr;
95         int ret;
96
97         // set default stack size to sensible default for memlocking
98         pthread_attr_init(&default_attr);
99         pthread_attr_setstacksize(&default_attr, 500000);
100
101         ThreadStartWithName* ts = new ThreadStartWithName (start_routine, arg, name);
102
103         if ((ret = thread_creator (thread, &default_attr, fake_thread_start, ts)) == 0) {
104                 pthread_mutex_lock (&thread_map_lock);
105                 all_threads.push_back (*thread);
106                 pthread_mutex_unlock (&thread_map_lock);
107         }
108
109         pthread_attr_destroy(&default_attr);
110
111         return ret;
112 }
113
114 void
115 pthread_set_name (const char *str)
116 {
117         /* copy string and delete it when exiting */
118         
119         thread_name.set (strdup (str));
120 }
121
122 const char *
123 pthread_name ()
124 {
125         const char* str = thread_name.get ();
126
127         if (str) {
128                 return str;
129         } 
130         return "unknown";
131 }
132
133 void
134 pthread_kill_all (int signum) 
135 {       
136         pthread_mutex_lock (&thread_map_lock);
137         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
138                 if (!pthread_equal ((*i), pthread_self())) {
139                         pthread_kill ((*i), signum);
140                 }
141         }
142         all_threads.clear();
143         pthread_mutex_unlock (&thread_map_lock);
144 }
145
146 void
147 pthread_cancel_all () 
148 {       
149         pthread_mutex_lock (&thread_map_lock);
150         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
151                 if (!pthread_equal ((*i), pthread_self())) {
152                         pthread_cancel ((*i));
153                 }
154         }
155         all_threads.clear();
156         pthread_mutex_unlock (&thread_map_lock);
157 }
158
159 void
160 pthread_cancel_one (pthread_t thread) 
161 {       
162         pthread_mutex_lock (&thread_map_lock);
163         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
164                 if (pthread_equal ((*i), thread)) {
165                         all_threads.erase (i);
166                         break;
167                 }
168         }
169
170         pthread_cancel (thread);
171         pthread_mutex_unlock (&thread_map_lock);
172 }
173
174 void
175 pthread_exit_pbd (void* status) 
176 {       
177         pthread_t thread = pthread_self();
178
179         pthread_mutex_lock (&thread_map_lock);
180         for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
181                 if (pthread_equal ((*i), thread)) {
182                         all_threads.erase (i);
183                         break;
184                 }
185         }
186         pthread_mutex_unlock (&thread_map_lock);
187         pthread_exit (status);
188 }