1 /*****************************************************************************
2 * threads.c : threads implementation for the VideoLAN client
3 *****************************************************************************
4 * Copyright (C) 1999-2008 the VideoLAN team
7 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
32 #include <vlc_common.h>
41 #if defined( LIBVLC_USE_PTHREAD )
45 struct vlc_thread_boot
47 void * (*entry
) (vlc_object_t
*);
51 static void *thread_entry (void *data
)
53 vlc_object_t
*obj
= ((struct vlc_thread_boot
*)data
)->object
;
54 void *(*func
) (vlc_object_t
*) = ((struct vlc_thread_boot
*)data
)->entry
;
57 msg_Dbg (obj
, "thread started");
59 msg_Dbg (obj
, "thread ended");
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
* ),
76 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
78 struct vlc_thread_boot
*boot
= malloc (sizeof (*boot
));
82 boot
->object
= p_this
;
84 /* Make sure we don't re-create a thread if the object has already one */
85 assert( !p_priv
->b_thread
);
87 p_priv
->b_thread
= true;
88 i_ret
= vlc_clone( &p_priv
->thread_id
, thread_entry
, boot
, i_priority
);
90 msg_Dbg( p_this
, "thread (%s) created at priority %d (%s:%d)",
91 psz_name
, i_priority
, psz_file
, i_line
);
94 p_priv
->b_thread
= false;
96 msg_Err( p_this
, "%s thread could not be created at %s:%d (%m)",
97 psz_name
, psz_file
, i_line
);
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
)
111 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
113 if( !p_priv
->b_thread
)
115 msg_Err( p_this
, "couldn't set priority of non-existent thread" );
119 #if defined( LIBVLC_USE_PTHREAD )
121 if( var_InheritBool( p_this
, "rt-priority" ) )
124 int i_error
, i_policy
;
125 struct sched_param param
;
127 memset( ¶m
, 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 )
132 param
.sched_priority
= (-1) * i_priority
;
133 i_policy
= SCHED_OTHER
;
137 param
.sched_priority
= i_priority
;
140 if( (i_error
= pthread_setschedparam( p_priv
->thread_id
,
141 i_policy
, ¶m
)) )
144 msg_Warn( p_this
, "couldn't set thread priority (%s:%d): %m",
150 #elif defined( WIN32 ) || defined( UNDER_CE )
151 VLC_UNUSED( psz_file
); VLC_UNUSED( i_line
);
154 if( !SetThreadPriority(p_priv
->thread_id
, i_priority
) )
156 if( !SetThreadPriority(p_priv
->thread_id
->handle
, i_priority
) )
159 msg_Warn( p_this
, "couldn't set a faster priority" );
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
)
174 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
176 #if defined( WIN32 ) && !defined( UNDER_CE )
178 FILETIME create_ft
, exit_ft
, kernel_ft
, user_ft
;
179 int64_t real_time
, kernel_time
, user_time
;
181 if( ! DuplicateHandle(GetCurrentProcess(),
187 DUPLICATE_SAME_ACCESS
) )
189 p_priv
->b_thread
= false;
190 return; /* We have a problem! */
194 vlc_join( p_priv
->thread_id
, NULL
);
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
) )
202 ((((int64_t)exit_ft
.dwHighDateTime
)<<32)| exit_ft
.dwLowDateTime
) -
203 ((((int64_t)create_ft
.dwHighDateTime
)<<32)| create_ft
.dwLowDateTime
);
207 ((((int64_t)kernel_ft
.dwHighDateTime
)<<32)|
208 kernel_ft
.dwLowDateTime
) / 10;
211 ((((int64_t)user_ft
.dwHighDateTime
)<<32)|
212 user_ft
.dwLowDateTime
) / 10;
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) );
223 CloseHandle( hThread
);
226 p_priv
->b_thread
= false;
229 void vlc_thread_cancel (vlc_object_t
*obj
)
231 vlc_object_internals_t
*priv
= vlc_internals (obj
);
234 vlc_cancel (priv
->thread_id
);