Commit b5a8e8b0 authored by spiiroin's avatar spiiroin

[usb-moded] Provide thread safe access to mode data list. Fixes JB#45312

While the worker thread already caches private copy of mode data,
acquiring this private copy is hazardous due to iterating list owned
by the main thread.

Add usbmoded_dup_modedata() function that does the list iteration and
duplication while holding mutex, and utilize it for looking up mode
data from the worker thread.
Signed-off-by: spiiroin's avatarSimo Piiroinen <simo.piiroinen@jollamobile.com>
parent d3df6947
...@@ -579,6 +579,7 @@ worker_switch_to_mode(const char *mode) ...@@ -579,6 +579,7 @@ worker_switch_to_mode(const char *mode)
LOG_REGISTER_CONTEXT; LOG_REGISTER_CONTEXT;
const char *override = 0; const char *override = 0;
modedata_t *data = 0;
/* set return to 1 to be sure to error out if no matching mode is found either */ /* set return to 1 to be sure to error out if no matching mode is found either */
...@@ -612,8 +613,7 @@ worker_switch_to_mode(const char *mode) ...@@ -612,8 +613,7 @@ worker_switch_to_mode(const char *mode)
goto FAILED; goto FAILED;
} }
const modedata_t *data = usbmoded_get_modedata(mode); if( (data = usbmoded_dup_modedata(mode)) ) {
if( data ) {
log_debug("Matching mode %s found.\n", mode); log_debug("Matching mode %s found.\n", mode);
/* set data before calling any of the dynamic mode functions /* set data before calling any of the dynamic mode functions
...@@ -704,6 +704,8 @@ SUCCESS: ...@@ -704,6 +704,8 @@ SUCCESS:
worker_notify(); worker_notify();
modedata_free(data);
return; return;
} }
......
...@@ -111,6 +111,7 @@ GList *usbmoded_get_modelist (void); ...@@ -111,6 +111,7 @@ GList *usbmoded_get_modelist (void);
void usbmoded_load_modelist (void); void usbmoded_load_modelist (void);
void usbmoded_free_modelist (void); void usbmoded_free_modelist (void);
const modedata_t *usbmoded_get_modedata (const char *modename); const modedata_t *usbmoded_get_modedata (const char *modename);
modedata_t *usbmoded_dup_modedata (const char *modename);
bool usbmoded_get_rescue_mode (void); bool usbmoded_get_rescue_mode (void);
void usbmoded_set_rescue_mode (bool rescue_mode); void usbmoded_set_rescue_mode (bool rescue_mode);
bool usbmoded_get_diag_mode (void); bool usbmoded_get_diag_mode (void);
...@@ -150,6 +151,22 @@ static bool usbmoded_systemd_notify = false; ...@@ -150,6 +151,22 @@ static bool usbmoded_systemd_notify = false;
#endif #endif
static bool usbmoded_auto_exit = false; static bool usbmoded_auto_exit = false;
static pthread_mutex_t usbmoded_mutex = PTHREAD_MUTEX_INITIALIZER;
#define USBMODED_LOCKED_ENTER do {\
if( pthread_mutex_lock(&usbmoded_mutex) != 0 ) { \
log_crit("USBMODED LOCK FAILED");\
_exit(EXIT_FAILURE);\
}\
}while(0)
#define USBMODED_LOCKED_LEAVE do {\
if( pthread_mutex_unlock(&usbmoded_mutex) != 0 ) { \
log_crit("USBMODED UNLOCK FAILED");\
_exit(EXIT_FAILURE);\
}\
}while(0)
/* ========================================================================= * /* ========================================================================= *
* Functions * Functions
* ========================================================================= */ * ========================================================================= */
...@@ -158,8 +175,18 @@ static bool usbmoded_auto_exit = false; ...@@ -158,8 +175,18 @@ static bool usbmoded_auto_exit = false;
* MODELIST * MODELIST
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/** List of mode data items read from configuration files
*
* Note: Worker thread should access this only via #usbmoded_dup_modedata().
*/
static GList *usbmoded_modelist = 0; static GList *usbmoded_modelist = 0;
/** Get list of dynamic mode data items
*
* Note: This function should be called only from the main thread.
*
* @returns List of mode data objects, or NULL
*/
GList * GList *
usbmoded_get_modelist(void) usbmoded_get_modelist(void)
{ {
...@@ -168,32 +195,58 @@ usbmoded_get_modelist(void) ...@@ -168,32 +195,58 @@ usbmoded_get_modelist(void)
return usbmoded_modelist; return usbmoded_modelist;
} }
/** Load dynamic mode data items
*
* Note: This function should be called only from the main thread.
*/
void void
usbmoded_load_modelist(void) usbmoded_load_modelist(void)
{ {
LOG_REGISTER_CONTEXT; LOG_REGISTER_CONTEXT;
USBMODED_LOCKED_ENTER;
if( !usbmoded_modelist ) { if( !usbmoded_modelist ) {
log_notice("load modelist"); log_notice("load modelist");
usbmoded_modelist = modelist_load(usbmoded_get_diag_mode()); usbmoded_modelist = modelist_load(usbmoded_get_diag_mode());
} }
USBMODED_LOCKED_LEAVE;
} }
/** Free dynamic mode data items
*
* Note: This function should be called only from the main thread.
*/
void void
usbmoded_free_modelist(void) usbmoded_free_modelist(void)
{ {
LOG_REGISTER_CONTEXT; LOG_REGISTER_CONTEXT;
USBMODED_LOCKED_ENTER;
if( usbmoded_modelist ) { if( usbmoded_modelist ) {
log_notice("free modelist"); log_notice("free modelist");
modelist_free(usbmoded_modelist), modelist_free(usbmoded_modelist),
usbmoded_modelist = 0; usbmoded_modelist = 0;
} }
USBMODED_LOCKED_LEAVE;
} }
/** Lookup dynamic mode data by name
*
* Note: This function should be called only from the main thread.
*
* @param modename Name of mode to lookup
*
* @return Mode data object, or NULL
*/
const modedata_t * const modedata_t *
usbmoded_get_modedata(const char *modename) usbmoded_get_modedata(const char *modename)
{ {
LOG_REGISTER_CONTEXT;
modedata_t *modedata = 0; modedata_t *modedata = 0;
for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) { for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) {
...@@ -206,6 +259,30 @@ usbmoded_get_modedata(const char *modename) ...@@ -206,6 +259,30 @@ usbmoded_get_modedata(const char *modename)
return modedata; return modedata;
} }
/** Lookup and clone dynamic mode data by name
*
* Note: This function is safe to call from worker thread too.
*
* Caller must release the returned object via #modedata_free().
*
* @param modename Name of mode to lookup
*
* @return Mode data object, or NULL
*/
modedata_t *
usbmoded_dup_modedata(const char *modename)
{
LOG_REGISTER_CONTEXT;
USBMODED_LOCKED_ENTER;
modedata_t *modedata = modedata_copy(usbmoded_get_modedata(modename));
USBMODED_LOCKED_LEAVE;
return modedata;
}
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* RESCUE_MODE * RESCUE_MODE
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
......
...@@ -70,6 +70,7 @@ GList *usbmoded_get_modelist (void); ...@@ -70,6 +70,7 @@ GList *usbmoded_get_modelist (void);
void usbmoded_load_modelist (void); void usbmoded_load_modelist (void);
void usbmoded_free_modelist (void); void usbmoded_free_modelist (void);
const modedata_t *usbmoded_get_modedata (const char *modename); const modedata_t *usbmoded_get_modedata (const char *modename);
modedata_t *usbmoded_dup_modedata (const char *modename);
bool usbmoded_get_rescue_mode (void); bool usbmoded_get_rescue_mode (void);
void usbmoded_set_rescue_mode (bool rescue_mode); void usbmoded_set_rescue_mode (bool rescue_mode);
bool usbmoded_get_diag_mode (void); bool usbmoded_get_diag_mode (void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment