@@ -3270,7 +3270,7 @@ nc_connect_ch_endpt(struct nc_ch_endpt *endpt, nc_server_ch_session_acquire_ctx_
32703270 *
32713271 * @param[in] client_name Name of the Call Home client.
32723272 * @param[out] idle_timeout Idle timeout in seconds.
3273- * @return 0 on success, 1 if the client was not found.
3273+ * @return 0 on success, 1 if the client was not found, -1 on error .
32743274 */
32753275static int
32763276nc_server_ch_client_get_idle_timeout (const char * client_name , uint32_t * idle_timeout )
@@ -3280,7 +3280,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
32803280
32813281 /* CONFIG READ LOCK */
32823282 if (nc_rwlock_lock (& server_opts .config_lock , NC_RWLOCK_READ , NC_CONFIG_LOCK_TIMEOUT , __func__ ) != 1 ) {
3283- return 1 ;
3283+ return - 1 ;
32843284 }
32853285
32863286 client = nc_server_ch_client_get (client_name );
@@ -3301,6 +3301,33 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
33013301 return ret ;
33023302}
33033303
3304+ /**
3305+ * @brief Checks if a Call Home thread should terminate.
3306+ *
3307+ * Checks the shared boolean variable thread_running. This should be done everytime
3308+ * before entering a critical section.
3309+ *
3310+ * @param[in] data Call Home thread's data.
3311+ * @return 1 if running, 0 if the thread should terminate, -1 on error.
3312+ */
3313+ static int
3314+ nc_server_ch_client_thread_is_running (struct nc_server_ch_thread_arg * data )
3315+ {
3316+ int rc = -1 ;
3317+
3318+ /* COND LOCK */
3319+ if (nc_mutex_lock (& data -> cond_lock , NC_CH_COND_LOCK_TIMEOUT , __func__ ) != 1 ) {
3320+ return -1 ;
3321+ }
3322+
3323+ rc = data -> thread_running ;
3324+
3325+ /* COND UNLOCK */
3326+ nc_mutex_unlock (& data -> cond_lock , __func__ );
3327+
3328+ return rc ;
3329+ }
3330+
33043331/**
33053332 * @brief Wait for any event after a NC session was established on a CH client.
33063333 *
@@ -3313,7 +3340,7 @@ nc_server_ch_client_get_idle_timeout(const char *client_name, uint32_t *idle_tim
33133340static int
33143341nc_server_ch_client_thread_session_cond_wait (struct nc_server_ch_thread_arg * data , struct nc_session * session )
33153342{
3316- int rc = 0 , r ;
3343+ int rc = 0 , r , terminate ;
33173344 uint32_t idle_timeout ;
33183345 struct timespec ts ;
33193346
@@ -3369,26 +3396,39 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33693396 /* CH UNLOCK */
33703397 nc_mutex_unlock (& session -> opts .server .ch_lock , __func__ );
33713398
3399+ terminate = 0 ;
3400+
33723401 /* check if the client still exists and get its idle timeout */
33733402 r = nc_server_ch_client_get_idle_timeout (data -> client_name , & idle_timeout );
33743403 if (r ) {
3375- /* client was removed, finish thread */
3376- VRB (session , "Call Home client \"%s\" removed, but an established session will not be terminated." ,
3377- data -> client_name );
3378- rc = 1 ;
3404+ if (r == 1 ) {
3405+ /* the client must always be found, because if we delete it, then the configuring thread calls
3406+ * pthread_join() on this thread with the old config where the client still exists */
3407+ ERRINT ;
3408+ }
3409+ rc = -1 ;
3410+ terminate = 1 ;
3411+ }
33793412
3380- /* CH LOCK - to remain consistent */
3381- if (nc_mutex_lock (& session -> opts .server .ch_lock , NC_SESSION_CH_LOCK_TIMEOUT , __func__ ) != 1 ) {
3382- return -1 ;
3413+ /* check if the thread should terminate */
3414+ r = nc_server_ch_client_thread_is_running (data );
3415+ if (r != 1 ) {
3416+ if (r == -1 ) {
3417+ rc = -1 ;
33833418 }
3384- break ;
3419+ terminate = 1 ;
33853420 }
33863421
33873422 /* CH LOCK */
33883423 if (nc_mutex_lock (& session -> opts .server .ch_lock , NC_SESSION_CH_LOCK_TIMEOUT , __func__ ) != 1 ) {
33893424 return -1 ;
33903425 }
33913426
3427+ if (terminate ) {
3428+ /* the purpose of this is to break only after we've acquired the ch_lock */
3429+ break ;
3430+ }
3431+
33923432 nc_timeouttime_get (& ts , 0 );
33933433 if (!nc_session_get_notif_status (session ) && idle_timeout && (ts .tv_sec >= session -> opts .server .last_rpc + idle_timeout )) {
33943434 VRB (session , "Call Home client \"%s\": session idle timeout elapsed." , data -> client_name );
@@ -3398,6 +3438,12 @@ nc_server_ch_client_thread_session_cond_wait(struct nc_server_ch_thread_arg *dat
33983438 } while (session -> status == NC_STATUS_RUNNING );
33993439 /* broke out of the loop, but still holding the ch_lock */
34003440
3441+ if (session -> status == NC_STATUS_RUNNING ) {
3442+ /* thread is terminating but the session is still running, so just log it */
3443+ VRB (session , "Call Home client \"%s\" removed, but an established session will not be terminated." ,
3444+ data -> client_name );
3445+ }
3446+
34013447 /* signal to nc_session_free() that CH thread is terminating */
34023448 session -> flags &= ~NC_SESSION_CH_THREAD ;
34033449 pthread_cond_signal (& session -> opts .server .ch_cond );
@@ -3453,35 +3499,6 @@ nc_server_ch_client_thread_is_running_wait(struct nc_session *session, struct nc
34533499 return ret ;
34543500}
34553501
3456- /**
3457- * @brief Checks if a Call Home thread should terminate.
3458- *
3459- * Checks the shared boolean variable thread_running. This should be done everytime
3460- * before entering a critical section.
3461- *
3462- * @param[in] data Call Home thread's data.
3463- *
3464- * @return 0 if the thread should stop running, -1 if it can continue.
3465- */
3466- static int
3467- nc_server_ch_client_thread_is_running (struct nc_server_ch_thread_arg * data )
3468- {
3469- int ret = -1 ;
3470-
3471- /* COND LOCK */
3472- if (nc_mutex_lock (& data -> cond_lock , NC_CH_COND_LOCK_TIMEOUT , __func__ ) != 1 ) {
3473- return ret ;
3474- }
3475- if (!data -> thread_running ) {
3476- /* thread should stop running */
3477- ret = 0 ;
3478- }
3479- /* COND UNLOCK */
3480- nc_mutex_unlock (& data -> cond_lock , __func__ );
3481-
3482- return ret ;
3483- }
3484-
34853502/**
34863503 * @brief Wait for a Call Home client to have at least one endpoint defined.
34873504 *
@@ -3848,6 +3865,8 @@ _nc_connect_ch_client_dispatch(struct nc_ch_client *ch_client, nc_server_ch_sess
38483865cleanup :
38493866 if (arg ) {
38503867 free (arg -> client_name );
3868+ pthread_mutex_destroy (& arg -> cond_lock );
3869+ pthread_cond_destroy (& arg -> cond );
38513870 free (arg );
38523871 }
38533872 return rc ;
0 commit comments