]> git.sesse.net Git - vlc/blob - src/playlist/thread.c
Partial rewrite of stats to avoid lookups (Closes:#693)
[vlc] / src / playlist / thread.c
1 /*****************************************************************************
2  * playlist.c : Playlist management functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          ClĂ©ment Stenac <zorglub@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 #include <vlc/vlc.h>
25 #include <vlc_es.h>
26 #include <vlc_input.h>
27 #include "vlc_playlist.h"
28 #include "vlc_interaction.h"
29
30 /*****************************************************************************
31  * Local prototypes
32  *****************************************************************************/
33 static void RunControlThread ( playlist_t * );
34 static void RunPreparse( playlist_preparse_t * );
35
36 static playlist_t * CreatePlaylist( vlc_object_t *p_parent );
37 static void HandlePlaylist( playlist_t * );
38 static void EndPlaylist( playlist_t * );
39 static void DestroyPlaylist( playlist_t * );
40
41 static void HandleStats( playlist_t *, int );
42
43 static void HandleInteraction( playlist_t * );
44 static void DestroyInteraction( playlist_t * );
45
46 /*****************************************************************************
47  * Main functions for the global thread
48  *****************************************************************************/
49
50 /**
51  * Create the main playlist thread
52  * Additionally to the playlist, this thread controls :
53  *    - Interaction
54  *    - Statistics
55  *    - VLM
56  * \param p_parent
57  * \return an object with a started thread
58  */
59 playlist_t * __playlist_ThreadCreate( vlc_object_t *p_parent )
60 {
61     playlist_t *p_playlist;
62     p_playlist = CreatePlaylist( p_parent );
63
64     if( !p_playlist ) return NULL;
65
66     // Stats
67     p_playlist->p_stats = (global_stats_t *)malloc( sizeof( global_stats_t ) );
68     vlc_mutex_init( p_playlist, &p_playlist->p_stats->lock );
69
70     // Interaction
71     p_playlist->p_interaction = NULL;
72
73     // Preparse
74     p_playlist->p_preparse = vlc_object_create( p_playlist,
75                                   sizeof( playlist_preparse_t ) );
76     if( !p_playlist->p_preparse )
77     {
78         msg_Err( p_playlist, "unable to create preparser" );
79         vlc_object_destroy( p_playlist );
80         return NULL;
81     }
82     p_playlist->p_preparse->i_waiting = 0;
83     p_playlist->p_preparse->pp_waiting = NULL;
84
85     vlc_object_attach( p_playlist->p_preparse, p_playlist );
86     if( vlc_thread_create( p_playlist->p_preparse, "preparser",
87                            RunPreparse, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
88     {
89         msg_Err( p_playlist, "cannot spawn preparse thread" );
90         vlc_object_detach( p_playlist->p_preparse );
91         vlc_object_destroy( p_playlist->p_preparse );
92         return NULL;
93     }
94
95     // Start the thread
96     if( vlc_thread_create( p_playlist, "playlist", RunControlThread,
97                            VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
98     {
99         msg_Err( p_playlist, "cannot spawn playlist thread" );
100         vlc_object_destroy( p_playlist );
101         return NULL;
102     }
103
104     /* The object has been initialized, now attach it */
105     vlc_object_attach( p_playlist, p_parent );
106
107     return p_playlist;
108 }
109
110 /**
111  * Destroy the playlist global thread.
112  *
113  * Deinits all things controlled by the playlist global thread
114  * \param p_playlist the playlist thread to destroy
115  * \return VLC_SUCCESS or an error
116  */
117 int playlist_ThreadDestroy( playlist_t * p_playlist )
118 {
119     p_playlist->b_die = 1;
120
121     DestroyInteraction( p_playlist );
122     DestroyPlaylist( p_playlist );
123
124     return VLC_SUCCESS;
125 }
126
127 /**
128  * Run the main control thread itself
129  */
130 static void RunControlThread ( playlist_t *p_playlist )
131 {
132    int i_loops = 0;
133
134    /* Tell above that we're ready */
135    vlc_thread_ready( p_playlist );
136
137     while( !p_playlist->b_die )
138     {
139         i_loops++;
140
141         HandleInteraction( p_playlist );
142         HandleStats( p_playlist, i_loops );
143
144         HandlePlaylist( p_playlist );
145
146         msleep( INTF_IDLE_SLEEP / 2 );
147
148         /* Stop sleeping earlier if we have work */
149         /* TODO : statistics about this */
150         if ( p_playlist->request.b_request &&
151                         p_playlist->status.i_status == PLAYLIST_RUNNING )
152         {
153             continue;
154         }
155
156         msleep( INTF_IDLE_SLEEP / 2 );
157     }
158
159     EndPlaylist( p_playlist );
160 }
161
162
163 /*****************************************************************************
164  * Playlist-specific functions
165  *****************************************************************************/
166 static playlist_t * CreatePlaylist( vlc_object_t *p_parent )
167 {
168     return playlist_Create( p_parent );
169 }
170
171 static void DestroyPlaylist( playlist_t *p_playlist )
172 {
173     playlist_Destroy( p_playlist );
174 }
175
176 static void HandlePlaylist( playlist_t *p_playlist )
177 {
178     playlist_MainLoop( p_playlist );
179 }
180
181 static void EndPlaylist( playlist_t *p_playlist )
182 {
183     playlist_LastLoop( p_playlist );
184 }
185
186 /*****************************************************************************
187  * Preparse-specific functions
188  *****************************************************************************/
189 static void RunPreparse ( playlist_preparse_t *p_obj )
190 {
191     playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
192     /* Tell above that we're ready */
193     vlc_thread_ready( p_obj );
194
195     while( !p_playlist->b_die )
196     {
197         playlist_PreparseLoop(  p_obj );
198         if( p_obj->i_waiting == 0 )
199         {
200             msleep( INTF_IDLE_SLEEP );
201         }
202     }
203 }
204
205 /*****************************************************************************
206  * Interaction functions
207  *****************************************************************************/
208 static void DestroyInteraction( playlist_t *p_playlist )
209 {
210     if( p_playlist->p_interaction )
211     {
212         intf_InteractionDestroy( p_playlist->p_interaction );
213     }
214 }
215
216 static void HandleInteraction( playlist_t *p_playlist )
217 {
218     if( p_playlist->p_interaction )
219     {
220         stats_TimerStart( p_playlist, "Interaction thread",
221                           STATS_TIMER_INTERACTION );
222         intf_InteractionManage( p_playlist );
223         stats_TimerStop( p_playlist, STATS_TIMER_INTERACTION );
224     }
225 }
226
227
228 /*****************************************************************************
229  * Stats functions
230  *****************************************************************************/
231 static void HandleStats( playlist_t *p_playlist, int i_loops )
232 {
233     if( i_loops %5 == 0 && p_playlist->p_stats )
234     {
235         stats_ComputeGlobalStats( p_playlist, p_playlist->p_stats );
236         if( p_playlist->p_input )
237         {
238             stats_ComputeInputStats( p_playlist->p_input,
239                                 p_playlist->p_input->input.p_item->p_stats );
240         }
241     }
242 }