% % threads.tex: description of threads interface for VideoLAN client % (c)1999 VideoLAN % \section{A common thread interface} This document describes how the different threads in the VideoLAN client are organized, their API and functionnment. % % Thread properties % \subsection{Thread properties} A thread is described by a \csymbol{X\_thread\_t} structure (i.e. \csymbol{vout\_thread\_t}), which is used to reference the thread in calls to its API. This structure includes beside following thread-specific data the following fields: \begin{csource} typedef struct X_thread_s \{ pthread_t thread_id; /* thread id for pthreads */ boolean_t b_die; /* `die' flag */ boolean_t b_run; /* `run' flag */ boolean_t b_error; /* `error' flag */ boolean_t b_active; /* `active' flag */ ... other fields ... \} X_thread_t; \end{csource} % % Meaning of common flags % \subsection{Meaning of common flags} \begin{description} \item[\csymbol{die}]: The \csymbol{die} flag means that the thread received a destruction request from another thread. It must terminate as soon as possible. This field is written (set to 1) by other threads and read by the thread itself. It cannot be reset to 0 once it has been set. Note that when the \csymbol{die} flag is set, no other thread should feed the dying one, and all shared structures should have been freed (i.e. the images and video streams for the video output thread). \item[\csymbol{run}]: The \csymbol{run} flag tells the other threads that the concerned thread is ready to receive data. It is set to 1 by the thread itself when the second phase of the initialization has succeeded, and set to 0 again by the thread once it exited. \item[\csymbol{error}]: The \csymbol{error} flag tells the other threads that a fatal error occured in the concerned thread. It can be set by all threads, and is read by the thread itself and the controlling thread. When a thread is in \csymbol{error} state, it runs in a special loop, accepting feed from other threads, but trashing eveything, waiting for a \csymbol{die} signal. Therefore, the controlling thread should check periodically if a thread has an \csymbol{error} set and, if yes, set its \csymbol{die} flag after having destroyed all depending threads. This flag is optionnal, but recommanded if an error can be envisaged in a later extension. \item[\csymbol{active}]: This flag's purpose is to avoid using useless resources. An in-\csymbol{active} thread must accept input as if it was inactive, but can treat its input differently. In example: the video output thread will set itself as in-\csymbol{active} when it is unmapped, and continue to sort and trash images, but will not render or display them to avoid consumming useless CPU. When a video decoder thread will detect that its related output thread is inactive, it will set itself inactive and trash everything except I images. The \csymbol{active} flag can be set and read by anyone. Precautions should be taken to avoid too long wake-up times. This flag is optionnal, but recommanded if its use can be envisaged in a later extension. \end{description} % % API % \subsection{API} This API is only a recommandation. % Creation \subsubsection{Creation} \begin{csource} X_thread_t * X_CreateThread( X_cfg_t *p_cfg ) \end{csource} This function will allocate thread descriptor, perform basic (and fast) initialization steps, and create the thread itself using \csymbol{pthread\_create}. Once it has been called, all flags are set to 0. It will return the thread descriptor or \csymbol{NULL} on failure. % Termination \subsubsection{Termination} \begin{csource} void X_TerminateThread( X_thread_t * p_X ); \end{csource} This function will set the \csymbol{die} flag of the thread and and return immediately. % Destruction \subsubsection{Destruction} \begin{csource} int X_DestroyThread( X_thread_t *p_X ); \end{csource} This function will try to destroy the thread descriptor, if it is possible (if the \csymbol{run} flag is not set). It will return 0 if it succeeded, and non 0 if the thread was still active. % % Local functions names % \subsection{Local functions names} The following functions names are recommanded to implement the different parts of the thread creation and destruction: \begin{csource} int InitThread(); /* second phase of initialization */ int RunThread(); /* main loop */ int RunError(); /* error loop */ int DestroyThread(); /* thread destruction */ \end{csource} \csymbol{X\_CreateThread()} will spawn a thread using \csymbol{RunThread()} function, which will call \csymbol{InitThread()}, enter its main loop, eventually call \csymbol{RunError()} and finally calls \csymbol{DestroyThread} when \csymbol{die} is received. % % Order of operations % \subsection{Order of operations} % Creation \subsubsection{Creation} \begin{tabular}{l|l} Controlling thread & Thread \\ \hline \csymbol{p\_X = X\_CreateThread( p\_cfg )}: & \\ descriptor allocation and initialization & \\ all flags are set to 0 & \\ base structures initialization & \\ If \csymbol{p\_X == NULL}: error & \\ \csymbol{X\_DestroyThread( p\_X )}: & \\ destruction of the descriptor & \\ end... Else, continuation.... & \csymbol{pthread\_create()} \\ & Second step of initialization \\ & On error: \\ & \csymbol{b\_error = 1} \\ & destruction of structures \\ & Else: \\ & \csymbol{b\_run = 1} \\ & beginning of main loop \\ \hline Wait for \csymbol{b\_run} or \csymbol{b\_error}...& main loop... \\ If \csymbol{b\_error}: & \\ \csymbol{X\_DestroyThread( p\_X )} & \\ end... & \\ Else (\csymbol{b\_run == 1}): & \\ the thread is ready and can be feeded... & \\ \hline \end{tabular} Notes: \begin{enumerate} \item The configuration structure can have been destroyed just after \csymbol{X\_CreateThread()}. Therefore, it should not be used during second initialization step. \item When an error occurs during second initialization step, the allocated structures are automatically destroyed (except the thread descriptor). Therefore, a call to \csymbol{X\_TerminateThread} is not required. \end{enumerate} % Main loop \subsubsection{Main loop} \begin{tabular}{l|l} Controlling thread & Thread \\ \hline Periodically check for \csymbol{b\_error} & Periodically check for \\ If set, then: & \csymbol{b\_error} and \csymbol{b\_die}\\ terminate all dependant threads & \\ destroy all dependant threads & \\ terminate and destroy thread & \\ \hline \end{tabular} % Destruction \subsubsection{Destruction} \begin{tabular}{l|l} Controlling thread & Thread \\ \hline \csymbol{X\_TerminateThread( p\_X )}: & \\ set \csymbol{b\_die} & \\ all flags are set to 0 & If \csymbol{DEBUG}, check if \\ & all shared structures are ok. \\ & Destroy and close everything, but \\ & keep descriptor. \\ & Set \csymbol{b\_run} to 0. \\ & Exit thread. \\ \hline Loop until \csymbol{X\_DestroyThread} is 0: & \\ check if \csymbol{b\_run == 0} & \\ if yes: & \\ destroy descriptor & \\ return 0 & \\ else: & \\ return 1 & \\ \hline \end{tabular}