From 5de59a26aa5d42a04b9f63f5a5a7424021047f63 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Fri, 5 May 2006 07:38:13 +0000 Subject: [PATCH] fix deadlock on event plugin --- src/main.c | 2 + src/plugin.c | 100 +++++++++++++++++++++++++++++++++++----- src/plugins/w32-event.c | 2 +- win32/nsi/mt-daapd.nsi | 13 ++++++ 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/src/main.c b/src/main.c index 4c9c4d8b..d241a216 100644 --- a/src/main.c +++ b/src/main.c @@ -135,6 +135,7 @@ void txt_add(char *txtrecord, char *fmt, ...) { } void main_handler(WS_CONNINFO *pwsc) { + DPRINTF(E_DBG,L_MAIN,"in main_handler\n"); if(plugin_url_candispatch(pwsc)) { DPRINTF(E_DBG,L_MAIN,"Dispatching %s to plugin\n",pwsc->uri); plugin_url_handle(pwsc); @@ -146,6 +147,7 @@ void main_handler(WS_CONNINFO *pwsc) { } int main_auth(WS_CONNINFO *pwsc, char *username, char *password) { + DPRINTF(E_DBG,L_MAIN,"in main_auth\n"); if(plugin_url_candispatch(pwsc)) { DPRINTF(E_DBG,L_MAIN,"Dispatching auth for %s to plugin\n",pwsc->uri); return plugin_auth_handle(pwsc,username,password); diff --git a/src/plugin.c b/src/plugin.c index 38667fbb..36452e87 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -56,6 +56,7 @@ typedef struct tag_pluginentry { } PLUGIN_ENTRY; /* Globals */ +static pthread_key_t _plugin_lock_key; static PLUGIN_ENTRY _plugin_list; static int _plugin_initialized = 0; @@ -72,6 +73,7 @@ void _plugin_readlock(void); void _plugin_writelock(void); void _plugin_unlock(void); int _plugin_error(char **pe, int error, ...); +void _plugin_free(int *pi); /* webserver helpers */ char *pi_ws_uri(WS_CONNINFO *pwsc); @@ -127,9 +129,19 @@ PLUGIN_INPUT_FN pi = { */ int plugin_init(void) { pthread_rwlock_init(&_plugin_lock,NULL); + pthread_key_create(&_plugin_lock_key, (void*)_plugin_free); + return TRUE; } +/** + * free the tls + */ +void _plugin_free(int *pi) { + if(pi) + free(pi); +} + /** * deinitialize stuff for plugins * @@ -141,13 +153,38 @@ int plugin_deinit(void) { /** - * lock the plugin_mutex + * lock the plugin_mutex. As it turns out, there might be one thread that calls + * multiple plug-ins. So we need to be able to just get one readlock, rather than + * multiple. so we'll keep a tls counter. + * + * NO DPRINTFING IN HERE! */ void _plugin_readlock(void) { int err; + int *current_count; - if((err=pthread_rwlock_rdlock(&_plugin_lock))) { - DPRINTF(E_FATAL,L_PLUG,"cannot lock plugin lock: %s\n",strerror(err)); + current_count = pthread_getspecific(_plugin_lock_key); + if(!current_count) { + current_count = (int*)malloc(sizeof(int)); + if(!current_count) { + /* hrm */ + DPRINTF(E_FATAL,L_PLUG,"Malloc error in _plugin_readlock\n"); + } + + *current_count = 0; + } + + DPRINTF(E_DBG,L_PLUG,"Current lock level: %d\n",*current_count); + if(!(*current_count)) { + (*current_count)++; + pthread_setspecific(_plugin_lock_key,(void*)current_count); + + if((err=pthread_rwlock_rdlock(&_plugin_lock))) { + DPRINTF(E_FATAL,L_PLUG,"cannot lock plugin lock: %s\n",strerror(err)); + } + } else { + (*current_count)++; + pthread_setspecific(_plugin_lock_key,(void*)current_count); } } @@ -156,9 +193,30 @@ void _plugin_readlock(void) { */ void _plugin_writelock(void) { int err; + int *current_count; - if((err=pthread_rwlock_wrlock(&_plugin_lock))) { - DPRINTF(E_FATAL,L_PLUG,"cannot lock plugin lock: %s\n",strerror(err)); + current_count = pthread_getspecific(_plugin_lock_key); + if(!current_count) { + current_count = (int*)malloc(sizeof(int)); + if(!current_count) { + DPRINTF(E_FATAL,L_PLUG,"Malloc error in _plugin_readlock\n"); + } + + *current_count = 0; + } + + DPRINTF(E_DBG,L_PLUG,"Current lock level: %d\n",*current_count); + + if(!(*current_count)) { + (*current_count)++; + pthread_setspecific(_plugin_lock_key,(void*)current_count); + + if((err=pthread_rwlock_wrlock(&_plugin_lock))) { + DPRINTF(E_FATAL,L_PLUG,"cannot lock plugin lock: %s\n",strerror(err)); + } + } else { + (*current_count)++; + pthread_setspecific(_plugin_lock_key,(void*)current_count); } } @@ -167,9 +225,22 @@ void _plugin_writelock(void) { */ void _plugin_unlock(void) { int err; + int *current_count; - if((err=pthread_rwlock_unlock(&_plugin_lock))) { - DPRINTF(E_FATAL,L_PLUG,"cannot unlock plugin lock: %s\n",strerror(err)); + current_count = pthread_getspecific(_plugin_lock_key); + if(!current_count) { + DPRINTF(E_FATAL,L_PLUG,"_plug_unlock without tls. wtf?\n"); + } + + (*current_count)--; + + if(!(*current_count)) { + pthread_setspecific(_plugin_lock_key,(void*)current_count); + if((err=pthread_rwlock_unlock(&_plugin_lock))) { + DPRINTF(E_FATAL,L_PLUG,"cannot unlock plugin lock: %s\n",strerror(err)); + } + } else { + pthread_setspecific(_plugin_lock_key,(void*)current_count); } } @@ -269,6 +340,8 @@ int plugin_load(char **pe, char *path) { */ int plugin_url_candispatch(WS_CONNINFO *pwsc) { PLUGIN_ENTRY *ppi; + + DPRINTF(E_DBG,L_PLUG,"Entering candispatch\n"); _plugin_readlock(); ppi = _plugin_list.next; @@ -279,8 +352,8 @@ int plugin_url_candispatch(WS_CONNINFO *pwsc) { _plugin_unlock(); return TRUE; } - ppi = ppi->next; } + ppi = ppi->next; } _plugin_unlock(); return FALSE; @@ -417,12 +490,15 @@ int plugin_auth_handle(WS_CONNINFO *pwsc, char *username, char *pw) { void plugin_event_dispatch(int event_id, int intval, void *vp, int len) { PLUGIN_ENTRY *ppi; - _plugin_readlock(); + fprintf(stderr,"entering plugin_event_dispatch\n"); + +// _plugin_readlock(); ppi = _plugin_list.next; while(ppi) { + fprintf(stderr,"Checking %s\n",ppi->versionstring); if(ppi->type & PLUGIN_EVENT) { - DPRINTF(E_DBG,L_PLUG,"Dispatching event %d to %s\n", - event_id,ppi->versionstring); +/* DPRINTF(E_DBG,L_PLUG,"Dispatching event %d to %s\n", + event_id,ppi->versionstring); */ if((ppi->event_fns) && (ppi->event_fns->handler)) { ppi->event_fns->handler(event_id, intval, vp, len); @@ -430,7 +506,7 @@ void plugin_event_dispatch(int event_id, int intval, void *vp, int len) { } ppi=ppi->next; } - _plugin_unlock(); +// _plugin_unlock(); } diff --git a/src/plugins/w32-event.c b/src/plugins/w32-event.c index 436572a5..e47d65e8 100644 --- a/src/plugins/w32-event.c +++ b/src/plugins/w32-event.c @@ -48,7 +48,7 @@ void plugin_handler(int event_id, int intval, void *vp, int len) { pmsg = (PLUGIN_MSG*)malloc(total_len); if(!pmsg) { - infn->log(E_LOG,"Malloc error in w32-event.c/plugin_handler\n"); +// infn->log(E_LOG,"Malloc error in w32-event.c/plugin_handler\n"); return; } diff --git a/win32/nsi/mt-daapd.nsi b/win32/nsi/mt-daapd.nsi index f345c13f..378e0202 100644 --- a/win32/nsi/mt-daapd.nsi +++ b/win32/nsi/mt-daapd.nsi @@ -64,7 +64,20 @@ ShowInstDetails show ShowUnInstDetails show Section -Pre + nsSCM::QueryStatus "${PRODUCT_NAME}" + Pop $0 + Pop $1 + + StrCmp $0 "success" lbl_stop_service + goto lbl_continue + + lbl_stop_service: + DetailPrint "Stopping Service..." nsSCM::Stop "${PRODUCT_NAME}" + Sleep 3000 + + lbl_continue: + ; should really loop until service stops... !include WinMessages.nsh FindWindow $0 "" "Configuration"