]> git.sesse.net Git - vlc/blob - src/misc/threads.c
Merge branch 'master' into lpcm_encoder
[vlc] / src / misc / threads.c
1 /*****************************************************************************
2  * threads.c : threads implementation for the VideoLAN client
3  *****************************************************************************
4  * Copyright (C) 1999-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *          Clément Sténac
11  *          Rémi Denis-Courmont
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33
34 #include "libvlc.h"
35 #include <assert.h>
36 #include <errno.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40
41 #if defined( LIBVLC_USE_PTHREAD )
42 # include <sched.h>
43 #endif
44
45 struct vlc_thread_boot
46 {
47     void * (*entry) (vlc_object_t *);
48     vlc_object_t *object;
49 };
50
51 static void *thread_entry (void *data)
52 {
53     vlc_object_t *obj = ((struct vlc_thread_boot *)data)->object;
54     void *(*func) (vlc_object_t *) = ((struct vlc_thread_boot *)data)->entry;
55
56     free (data);
57     msg_Dbg (obj, "thread started");
58     func (obj);
59     msg_Dbg (obj, "thread ended");
60
61     return NULL;
62 }
63
64 #undef vlc_thread_create
65 /*****************************************************************************
66  * vlc_thread_create: create a thread
67  *****************************************************************************
68  * Note that i_priority is only taken into account on platforms supporting
69  * userland real-time priority threads.
70  *****************************************************************************/
71 int vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line,
72                        const char *psz_name, void *(*func) ( vlc_object_t * ),
73                        int i_priority )
74 {
75     int i_ret;
76     vlc_object_internals_t *p_priv = vlc_internals( p_this );
77
78     struct vlc_thread_boot *boot = malloc (sizeof (*boot));
79     if (boot == NULL)
80         return errno;
81     boot->entry = func;
82     boot->object = p_this;
83
84     /* Make sure we don't re-create a thread if the object has already one */
85     assert( !p_priv->b_thread );
86
87     p_priv->b_thread = true;
88     i_ret = vlc_clone( &p_priv->thread_id, thread_entry, boot, i_priority );
89     if( i_ret == 0 )
90         msg_Dbg( p_this, "thread (%s) created at priority %d (%s:%d)",
91                  psz_name, i_priority, psz_file, i_line );
92     else
93     {
94         p_priv->b_thread = false;
95         errno = i_ret;
96         msg_Err( p_this, "%s thread could not be created at %s:%d (%m)",
97                          psz_name, psz_file, i_line );
98     }
99
100     return i_ret;
101 }
102
103 #undef vlc_thread_set_priority
104 /*****************************************************************************
105  * vlc_thread_set_priority: set the priority of the current thread when we
106  * couldn't set it in vlc_thread_create (for instance for the main thread)
107  *****************************************************************************/
108 int vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file,
109                              int i_line, int i_priority )
110 {
111     vlc_object_internals_t *p_priv = vlc_internals( p_this );
112
113     if( !p_priv->b_thread )
114     {
115         msg_Err( p_this, "couldn't set priority of non-existent thread" );
116         return ESRCH;
117     }
118
119 #if defined( LIBVLC_USE_PTHREAD )
120 # ifndef __APPLE__
121     if( var_InheritBool( p_this, "rt-priority" ) )
122 # endif
123     {
124         int i_error, i_policy;
125         struct sched_param param;
126
127         memset( &param, 0, sizeof(struct sched_param) );
128         if( config_GetType( p_this, "rt-offset" ) )
129             i_priority += var_InheritInteger( p_this, "rt-offset" );
130         if( i_priority <= 0 )
131         {
132             param.sched_priority = (-1) * i_priority;
133             i_policy = SCHED_OTHER;
134         }
135         else
136         {
137             param.sched_priority = i_priority;
138             i_policy = SCHED_RR;
139         }
140         if( (i_error = pthread_setschedparam( p_priv->thread_id,
141                                               i_policy, &param )) )
142         {
143             errno = i_error;
144             msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m",
145                       psz_file, i_line );
146             i_priority = 0;
147         }
148     }
149
150 #elif defined( WIN32 ) || defined( UNDER_CE )
151     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
152
153 #ifndef UNDER_CE
154     if( !SetThreadPriority(p_priv->thread_id, i_priority) )
155 #else
156     if( !SetThreadPriority(p_priv->thread_id->handle, i_priority) )
157 #endif
158     {
159         msg_Warn( p_this, "couldn't set a faster priority" );
160         return 1;
161     }
162
163 #endif
164
165     return 0;
166 }
167
168 #undef vlc_thread_join
169 /*****************************************************************************
170  * vlc_thread_join: wait until a thread exits, inner version
171  *****************************************************************************/
172 void vlc_thread_join( vlc_object_t *p_this )
173 {
174     vlc_object_internals_t *p_priv = vlc_internals( p_this );
175
176 #if defined( WIN32 ) && !defined( UNDER_CE )
177     HANDLE hThread;
178     FILETIME create_ft, exit_ft, kernel_ft, user_ft;
179     int64_t real_time, kernel_time, user_time;
180
181     if( ! DuplicateHandle(GetCurrentProcess(),
182             p_priv->thread_id,
183             GetCurrentProcess(),
184             &hThread,
185             0,
186             FALSE,
187             DUPLICATE_SAME_ACCESS) )
188     {
189         p_priv->b_thread = false;
190         return; /* We have a problem! */
191     }
192 #endif
193
194     vlc_join( p_priv->thread_id, NULL );
195
196 #if defined( WIN32 ) && !defined( UNDER_CE )
197     /* FIXME: this could work on WinCE too... except that it seems always to
198      * return 0 for exit_ft and kernel_ft */
199     if( GetThreadTimes( hThread, &create_ft, &exit_ft, &kernel_ft, &user_ft ) )
200     {
201         real_time =
202           ((((int64_t)exit_ft.dwHighDateTime)<<32)| exit_ft.dwLowDateTime) -
203           ((((int64_t)create_ft.dwHighDateTime)<<32)| create_ft.dwLowDateTime);
204         real_time /= 10;
205
206         kernel_time =
207           ((((int64_t)kernel_ft.dwHighDateTime)<<32)|
208            kernel_ft.dwLowDateTime) / 10;
209
210         user_time =
211           ((((int64_t)user_ft.dwHighDateTime)<<32)|
212            user_ft.dwLowDateTime) / 10;
213
214         msg_Dbg( p_this, "thread times: "
215                  "real %"PRId64"m%fs, kernel %"PRId64"m%fs, user %"PRId64"m%fs",
216                  real_time/60/1000000,
217                  (double)((real_time%(60*1000000))/1000000.0),
218                  kernel_time/60/1000000,
219                  (double)((kernel_time%(60*1000000))/1000000.0),
220                  user_time/60/1000000,
221                  (double)((user_time%(60*1000000))/1000000.0) );
222     }
223     CloseHandle( hThread );
224 #endif
225
226     p_priv->b_thread = false;
227 }
228
229 void vlc_thread_cancel (vlc_object_t *obj)
230 {
231     vlc_object_internals_t *priv = vlc_internals (obj);
232
233     if (priv->b_thread)
234         vlc_cancel (priv->thread_id);
235 }
236
237 /*** Global locks ***/
238
239 void vlc_global_mutex (unsigned n, bool acquire)
240 {
241     static vlc_mutex_t locks[] = {
242         VLC_STATIC_MUTEX,
243         VLC_STATIC_MUTEX,
244         VLC_STATIC_MUTEX,
245     };
246     assert (n < (sizeof (locks) / sizeof (locks[0])));
247     vlc_mutex_t *lock = locks + n;
248
249     if (acquire)
250         vlc_mutex_lock (lock);
251     else
252         vlc_mutex_unlock (lock);
253
254     /* Compile-time assertion ;-) */
255     char enough_locks[(sizeof (locks) / sizeof (locks[0])) - VLC_MAX_MUTEX];
256     (void) enough_locks;
257 }