/*
* Doing this for both the global and local sessiond.
*/
-static int sem_count = { 2 };
+enum {
+ sem_count_initial_value = 4,
+};
+
+static int sem_count = sem_count_initial_value;
/*
* Counting nesting within lttng-ust. Used to ensure that calling fork()
const char *name;
pthread_t ust_listener; /* listener thread */
int root_handle;
- int constructor_sem_posted;
+ int registration_done;
int allowed;
int global;
int thread_active;
char *wait_shm_mmap;
/* Keep track of lazy state dump not performed yet. */
int statedump_pending;
+ int initial_statedump_done;
};
/* Socket from app (connect) to session daemon (listen) for communication */
.global = 1,
.root_handle = -1,
+ .registration_done = 0,
.allowed = 0,
.thread_active = 0,
.wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME,
.statedump_pending = 0,
+ .initial_statedump_done = 0,
};
/* TODO: allow global_apps_sock_path override */
.name = "local",
.global = 0,
.root_handle = -1,
+ .registration_done = 0,
.allowed = 0, /* Check setuid bit first */
.thread_active = 0,
.notify_socket = -1,
.statedump_pending = 0,
+ .initial_statedump_done = 0,
};
static int wait_poll_fallback;
}
static
-int handle_register_done(struct sock_info *sock_info)
+void decrement_sem_count(unsigned int count)
{
int ret;
- if (sock_info->constructor_sem_posted)
- return 0;
- sock_info->constructor_sem_posted = 1;
+ assert(uatomic_read(&sem_count) >= count);
+
if (uatomic_read(&sem_count) <= 0) {
- return 0;
+ return;
}
- ret = uatomic_add_return(&sem_count, -1);
+
+ ret = uatomic_add_return(&sem_count, -count);
if (ret == 0) {
ret = sem_post(&constructor_wait);
assert(!ret);
}
+}
+
+static
+int handle_register_done(struct sock_info *sock_info)
+{
+ if (sock_info->registration_done)
+ return 0;
+ sock_info->registration_done = 1;
+
+ decrement_sem_count(1);
+
+ return 0;
+}
+
+static
+int handle_register_failed(struct sock_info *sock_info)
+{
+ if (sock_info->registration_done)
+ return 0;
+ sock_info->registration_done = 1;
+ sock_info->initial_statedump_done = 1;
+
+ decrement_sem_count(2);
+
return 0;
}
/*
* Only execute pending statedump after the constructor semaphore has
- * been posted by each listener thread. This means statedump will only
- * be performed after the "registration done" command is received from
- * each session daemon the application is connected to.
+ * been posted by the current listener thread. This means statedump will
+ * only be performed after the "registration done" command is received
+ * from this thread's session daemon.
*
* This ensures we don't run into deadlock issues with the dynamic
* loader mutex, which is held while the constructor is called and
* waiting on the constructor semaphore. All operations requiring this
* dynamic loader lock need to be postponed using this mechanism.
+ *
+ * In a scenario with two session daemons connected to the application,
+ * it is possible that the first listener thread which receives the
+ * registration done command issues its statedump while the dynamic
+ * loader lock is still held by the application constructor waiting on
+ * the semaphore. It will however be allowed to proceed when the
+ * second session daemon sends the registration done command to the
+ * second listener thread. This situation therefore does not produce
+ * a deadlock.
*/
static
void handle_pending_statedump(struct sock_info *sock_info)
{
- int ctor_passed = sock_info->constructor_sem_posted;
-
- if (ctor_passed && sock_info->statedump_pending) {
+ if (sock_info->registration_done && sock_info->statedump_pending) {
sock_info->statedump_pending = 0;
pthread_mutex_lock(&ust_fork_mutex);
lttng_handle_pending_statedump(sock_info);
pthread_mutex_unlock(&ust_fork_mutex);
+
+ if (!sock_info->initial_statedump_done) {
+ sock_info->initial_statedump_done = 1;
+ decrement_sem_count(1);
+ }
}
}
}
sock_info->root_handle = -1;
}
- sock_info->constructor_sem_posted = 0;
+ sock_info->registration_done = 0;
+ sock_info->initial_statedump_done = 0;
/*
* wait_shm_mmap, socket and notify socket are used by listener
* If we cannot find the sessiond daemon, don't delay
* constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
* If we cannot find the sessiond daemon, don't delay
* constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto restart;
* If we cannot register to the sessiond daemon, don't
* delay constructor execution.
*/
- ret = handle_register_done(sock_info);
+ ret = handle_register_failed(sock_info);
assert(!ret);
ust_unlock();
goto end;
exit_tracepoint();
if (!exiting) {
/* Reinitialize values for fork */
- sem_count = 2;
+ sem_count = sem_count_initial_value;
lttng_ust_comm_should_quit = 0;
initialized = 0;
}