diff options
-rw-r--r-- | src/indmanager/ind_manager.c | 27 | ||||
-rw-r--r-- | src/indmanager/ind_manager.h | 2 |
2 files changed, 26 insertions, 3 deletions
diff --git a/src/indmanager/ind_manager.c b/src/indmanager/ind_manager.c index 462227e..d6cd650 100644 --- a/src/indmanager/ind_manager.c +++ b/src/indmanager/ind_manager.c @@ -677,6 +677,11 @@ static void *manage(void *data) DEBUG("manage thread in infinite loop"); // wait until manager is running pthread_mutex_lock(&manager->_t_mutex); + if (manager->cancelled) { + pthread_mutex_unlock(&manager->_t_mutex); + err = IM_ERR_CANCELLED; + return (void *)err; + } while (!manager->running) { DEBUG("manage thread waiting to indication start"); pthread_cond_wait(&manager->_t_cond, &manager->_t_mutex); @@ -695,6 +700,11 @@ static void *manage(void *data) continue; } pthread_mutex_lock(&manager->_t_mutex); + if (manager->cancelled) { + pthread_mutex_unlock(&manager->_t_mutex); + err = IM_ERR_CANCELLED; + return (void *)err; + } if (manager->polling) { // poll enumerations if (!_im_poll(manager, &err)) { @@ -819,6 +829,7 @@ IMManager* im_create_manager(IMInstGather gather, IMFilterChecker f_checker, manager->filters = NULL; manager->running = false; manager->polling = polling; + manager->cancelled = false; manager->broker = broker; manager->f_checker = f_checker; manager->enums = NULL; @@ -1175,6 +1186,7 @@ bool im_start_ind(IMManager *manager, const CMPIContext *ctx, IMError *err) *err = IM_ERR_THREAD; return false; } + manager->cancelled = false; manager->ctx_main = ctx; manager->ctx_manage = CBPrepareAttachThread(manager->broker, manager->ctx_main); @@ -1205,17 +1217,25 @@ bool im_stop_ind(IMManager *manager, const CMPIContext *ctx, IMError *err) DEBUG("Stopping indications"); manager->running = false; - /* We must lock the mutex so we are sure the thread does not hold it. - * If we destroy the thread with mutex locked, the mutex is locked forever. - */ + /* First lock the mutex so we are sure the thread does not hold it. */ pthread_mutex_lock(&manager->_t_mutex); + /* Then cancel the thread in deferred mode and set a private flag. + * The thread may be doing unlocked stuff that will cancel just fine + * or may be waiting for mutex acquisition where it will cancel and + * unlock right after that using our private flag. + */ + manager->cancelled = true; + /* Note that mutex functions ARE NOT cancellation points! */ if (pthread_cancel(manager->_t_manage)) { *err = IM_ERR_THREAD; pthread_mutex_unlock(&manager->_t_mutex); return false; } + + /* Unlock the mutex and give the thread chance to cancel properly. */ pthread_mutex_unlock(&manager->_t_mutex); + /* Wait until thread cancellation is finished. */ if (pthread_join(manager->_t_manage, NULL)) { *err = IM_ERR_THREAD; return false; @@ -1226,6 +1246,7 @@ bool im_stop_ind(IMManager *manager, const CMPIContext *ctx, IMError *err) manager->data = NULL; /* TODO: properly detach the thread using CBAttachThread(), needs to be called from the thread */ manager->ctx_manage = NULL; + manager->cancelled = false; return true; } diff --git a/src/indmanager/ind_manager.h b/src/indmanager/ind_manager.h index 733cf7a..a684ac6 100644 --- a/src/indmanager/ind_manager.h +++ b/src/indmanager/ind_manager.h @@ -136,6 +136,7 @@ struct _IMManager { IMIndType type; bool running; bool polling; + bool cancelled; const CMPIBroker *broker; const CMPIContext *ctx_main; /* main thread */ CMPIContext *ctx_manage; /* manage thread */ @@ -163,6 +164,7 @@ typedef enum { IM_ERR_THREAD, // some error on threading IM_ERR_CMPI_RC, // CMPI status not OK IM_ERR_OP, // bad or null object path + IM_ERR_CANCELLED, // job has been cancelled } IMError; // Create manager with given properties and callbacks. |