threads.c 5.85 KB
Newer Older
1 2 3
/*****************************************************************************
 * threads.c : threads implementation for the VideoLAN client
 *****************************************************************************
4
 * Copyright (C) 1999-2008 the VideoLAN team
5
 * $Id$
6 7 8 9
 *
 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
 *          Samuel Hocevar <sam@zoy.org>
 *          Gildas Bazin <gbazin@netcourrier.com>
10
 *          Clément Sténac
11
 *          Rémi Denis-Courmont
12 13 14 15 16
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
17
 *
18 19 20 21 22 23 24
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 27
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33

34
#include "libvlc.h"
35
#include <assert.h>
36
#include <errno.h>
37 38 39
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
40

41
#if defined( LIBVLC_USE_PTHREAD )
42
# include <sched.h>
43 44
#endif

45 46
struct vlc_thread_boot
{
47
    void * (*entry) (vlc_object_t *);
48 49 50
    vlc_object_t *object;
};

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 57 58 59

    free (data);
    msg_Dbg (obj, "thread started");
    func (obj);
    msg_Dbg (obj, "thread ended");
60

61
    return NULL;
62 63
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
64
#undef vlc_thread_create
65
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
66
 * vlc_thread_create: create a thread
67 68 69
 *****************************************************************************
 * Note that i_priority is only taken into account on platforms supporting
 * userland real-time priority threads.
70
 *****************************************************************************/
71
int vlc_thread_create( vlc_object_t *p_this, void *(*func) ( vlc_object_t * ),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
72
                       int i_priority )
73 74
{
    int i_ret;
75
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
76

77 78 79 80 81 82
    struct vlc_thread_boot *boot = malloc (sizeof (*boot));
    if (boot == NULL)
        return errno;
    boot->entry = func;
    boot->object = p_this;

83 84 85
    /* Make sure we don't re-create a thread if the object has already one */
    assert( !p_priv->b_thread );

86
    i_ret = vlc_clone( &p_priv->thread_id, thread_entry, boot, i_priority );
87
    if( i_ret == 0 )
88
        p_priv->b_thread = true;
89 90
    else
    {
91
        errno = i_ret;
92 93
        msg_Err( p_this, "cannot create thread (%m)" );
        free (boot);
94 95 96 97 98
    }

    return i_ret;
}

99
#undef vlc_thread_set_priority
100 101 102 103
/*****************************************************************************
 * vlc_thread_set_priority: set the priority of the current thread when we
 * couldn't set it in vlc_thread_create (for instance for the main thread)
 *****************************************************************************/
104
int vlc_thread_set_priority( vlc_object_t *p_this, int i_priority )
105
{
106
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
107

108 109 110 111 112 113
    if( !p_priv->b_thread )
    {
        msg_Err( p_this, "couldn't set priority of non-existent thread" );
        return ESRCH;
    }

114
#if defined( LIBVLC_USE_PTHREAD )
115
# ifndef __APPLE__
116
    if( var_InheritBool( p_this, "rt-priority" ) )
117
# endif
118
    {
119
        int i_error, i_policy;
120
        struct sched_param param;
121

122
        memset( &param, 0, sizeof(struct sched_param) );
123
        if( config_GetType( p_this, "rt-offset" ) )
124
            i_priority += var_InheritInteger( p_this, "rt-offset" );
125
        if( i_priority <= 0 )
126 127 128 129 130 131 132 133 134
        {
            param.sched_priority = (-1) * i_priority;
            i_policy = SCHED_OTHER;
        }
        else
        {
            param.sched_priority = i_priority;
            i_policy = SCHED_RR;
        }
135
        if( (i_error = pthread_setschedparam( p_priv->thread_id,
136
                                              i_policy, &param )) )
137
        {
138
            errno = i_error;
139
            msg_Warn( p_this, "cannot set thread priority (%m)" );
140
            i_priority = 0;
141 142
        }
    }
143 144 145

#elif defined( WIN32 ) || defined( UNDER_CE )

146 147
#warning vlc_thread_set_priority() is BROKEN
    if( true /*!SetThreadPriority(p_priv->thread_id->id, i_priority)*/ )
148 149 150 151 152
    {
        msg_Warn( p_this, "couldn't set a faster priority" );
        return 1;
    }

153
#endif
gbazin's avatar
 
gbazin committed
154 155

    return 0;
156 157
}

158
#undef vlc_thread_join
159 160 161
/*****************************************************************************
 * vlc_thread_join: wait until a thread exits, inner version
 *****************************************************************************/
162
void vlc_thread_join( vlc_object_t *p_this )
163
{
164
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
165

166
    vlc_join( p_priv->thread_id, NULL );
167
    p_priv->b_thread = false;
168
}
169

170 171 172 173 174 175 176
void vlc_thread_cancel (vlc_object_t *obj)
{
    vlc_object_internals_t *priv = vlc_internals (obj);

    if (priv->b_thread)
        vlc_cancel (priv->thread_id);
}
177 178 179 180 181 182 183 184

/*** Global locks ***/

void vlc_global_mutex (unsigned n, bool acquire)
{
    static vlc_mutex_t locks[] = {
        VLC_STATIC_MUTEX,
        VLC_STATIC_MUTEX,
185
        VLC_STATIC_MUTEX,
186 187 188 189 190 191 192 193 194 195 196 197 198
    };
    assert (n < (sizeof (locks) / sizeof (locks[0])));
    vlc_mutex_t *lock = locks + n;

    if (acquire)
        vlc_mutex_lock (lock);
    else
        vlc_mutex_unlock (lock);

    /* Compile-time assertion ;-) */
    char enough_locks[(sizeof (locks) / sizeof (locks[0])) - VLC_MAX_MUTEX];
    (void) enough_locks;
}