Skip to content

Commit 40c41b3

Browse files
author
roman
committed
session client BUGFIX monitoring thread locking
1 parent e9be3c3 commit 40c41b3

3 files changed

Lines changed: 35 additions & 30 deletions

File tree

src/session_client.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3336,6 +3336,11 @@ nc_client_monitoring_session_stop(struct nc_session *session, int lock)
33363336
pthread_mutex_lock(&mtarg->lock);
33373337
}
33383338

3339+
/* session is no longer monitored (is being freed) */
3340+
if (!(session->flags & NC_SESSION_CLIENT_MONITORED)) {
3341+
goto cleanup;
3342+
}
3343+
33393344
/* find the session */
33403345
for (i = 0; i < mtarg->session_count; i++) {
33413346
if (mtarg->sessions[i] == session) {
@@ -3344,7 +3349,7 @@ nc_client_monitoring_session_stop(struct nc_session *session, int lock)
33443349
}
33453350
if (i == mtarg->session_count) {
33463351
/* not found */
3347-
ERR(session, "Session is not being monitored.");
3352+
ERRINT;
33483353
goto cleanup;
33493354
}
33503355

@@ -3382,7 +3387,7 @@ nc_client_monitoring_thread(void *arg)
33823387
int r;
33833388
struct nc_client_monitoring_thread_arg *mtarg;
33843389
nfds_t i;
3385-
struct nc_session *session;
3390+
struct nc_session *session = NULL;
33863391

33873392
/* set this thread's context to the one from the thread that started the monitoring thread */
33883393
nc_client_set_thread_context(arg);
@@ -3416,52 +3421,36 @@ nc_client_monitoring_thread(void *arg)
34163421
goto next_iter;
34173422
}
34183423

3419-
/* check the events */
3420-
i = 0;
3421-
while (i < mtarg->pfd_count) {
3424+
for (i = 0; i < mtarg->pfd_count; i++) {
34223425
if (mtarg->pfds[i].revents & (POLLHUP | POLLNVAL)) {
3423-
/* call the callback and free the session */
3426+
/* save the session and stop monitoring it, callback will be called outside of the lock */
34243427
session = mtarg->sessions[i];
34253428
session->status = NC_STATUS_INVALID;
34263429
session->term_reason = NC_SESSION_TERM_DROPPED;
3427-
mtarg->clb(session, mtarg->clb_data);
3428-
3429-
/* session will be removed from the list, continue from the same index */
34303430
nc_client_monitoring_session_stop(session, 0);
3431-
nc_session_free(session, NULL);
3432-
} else {
3433-
i++;
3431+
break;
34343432
}
34353433
}
34363434

34373435
next_iter:
34383436
/* UNLOCK */
34393437
pthread_mutex_unlock(&mtarg->lock);
34403438

3439+
/* if an event occurred, call the callback */
3440+
if (session) {
3441+
mtarg->clb(session, mtarg->clb_data);
3442+
}
3443+
session = NULL;
3444+
34413445
usleep(NC_CLIENT_MONITORING_BACKOFF * 1000);
34423446

34433447
/* LOCK */
34443448
pthread_mutex_lock(&mtarg->lock);
34453449
}
34463450

34473451
cleanup:
3448-
client_opts.monitoring_thread_data = NULL;
3449-
34503452
/* UNLOCK */
34513453
pthread_mutex_unlock(&mtarg->lock);
3452-
3453-
if (mtarg->clb_free_data) {
3454-
mtarg->clb_free_data(mtarg->clb_data);
3455-
}
3456-
for (i = 0; i < mtarg->session_count; i++) {
3457-
mtarg->sessions[i]->flags &= ~NC_SESSION_CLIENT_MONITORED;
3458-
}
3459-
free(mtarg->sessions);
3460-
free(mtarg->pfds);
3461-
pthread_mutex_destroy(&mtarg->lock);
3462-
3463-
free(mtarg);
3464-
34653454
VRB(NULL, "Client monitoring thread exit.");
34663455
return NULL;
34673456
}
@@ -3518,7 +3507,7 @@ nc_client_monitoring_thread_start(nc_client_monitoring_clb monitoring_clb, void
35183507
API void
35193508
nc_client_monitoring_thread_stop(void)
35203509
{
3521-
int r;
3510+
int r, i;
35223511
pthread_t tid;
35233512
struct nc_client_monitoring_thread_arg *mtarg;
35243513

@@ -3534,6 +3523,12 @@ nc_client_monitoring_thread_stop(void)
35343523

35353524
mtarg->thread_running = 0;
35363525
tid = mtarg->tid;
3526+
client_opts.monitoring_thread_data = NULL;
3527+
3528+
/* remove the flag from the session while the lock is held */
3529+
for (i = 0; i < mtarg->session_count; i++) {
3530+
mtarg->sessions[i]->flags &= ~NC_SESSION_CLIENT_MONITORED;
3531+
}
35373532

35383533
/* UNLOCK */
35393534
pthread_mutex_unlock(&mtarg->lock);
@@ -3542,6 +3537,15 @@ nc_client_monitoring_thread_stop(void)
35423537
if (r) {
35433538
ERR(NULL, "Failed to join the client monitoring thread (%s).", strerror(r));
35443539
}
3540+
3541+
if (mtarg->clb_free_data) {
3542+
mtarg->clb_free_data(mtarg->clb_data);
3543+
}
3544+
free(mtarg->sessions);
3545+
free(mtarg->pfds);
3546+
pthread_mutex_destroy(&mtarg->lock);
3547+
3548+
free(mtarg);
35453549
}
35463550

35473551
API void

src/session_client.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,9 @@ void nc_client_session_set_not_strict(struct nc_session *session);
620620
/**
621621
* @brief Callback for monitoring client sessions.
622622
*
623-
* This callback is called whenever the client finds out that a session was terminated by the server.
623+
* This callback is called whenever the client finds out that a session was disconnected by the server.
624624
*
625-
* @param[in] session Terminated session, which will be freed after the callback finishes executing.
625+
* @param[in] session Disconnected session. The session will not be freed, so it is safe to call nc_session_free() on it.
626626
* @param[in] user_data Arbitrary user data passed to the callback.
627627
*/
628628
typedef void (*nc_client_monitoring_clb)(struct nc_session *session, void *user_data);

tests/test_client_monitoring.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ monitoring_clb(struct nc_session *sess, void *user_data)
4141
/* signal the main thread that the monitoring callback was called */
4242
pthread_barrier_wait(barrier);
4343
printf("Session with ID %d disconnected by the server.\n", nc_session_get_id(sess));
44+
nc_session_free(sess, NULL);
4445
}
4546

4647
static void *

0 commit comments

Comments
 (0)