X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;ds=sidebyside;f=liblttng-ust-comm%2Flttng-ust-fd-tracker.c;h=a2227e62115cb137369a44cb3d12eb33bbcad3ab;hb=refs%2Fheads%2Fstable-2.12;hp=1bc186bf08453f870001446ebf17dbb0e2ab2054;hpb=5a4d96d170a38f29bf147b84e248a47d45ee7d8e;p=lttng-ust.git diff --git a/liblttng-ust-comm/lttng-ust-fd-tracker.c b/liblttng-ust-comm/lttng-ust-fd-tracker.c index 1bc186bf..a2227e62 100644 --- a/liblttng-ust-comm/lttng-ust-fd-tracker.c +++ b/liblttng-ust-comm/lttng-ust-fd-tracker.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include "../liblttng-ust/compat.h" @@ -61,13 +64,19 @@ * Protect the lttng_fd_set. Nests within the ust_lock, and therefore * within the libc dl lock. Therefore, we need to fixup the TLS before * nesting into this lock. + * + * The ust_safe_guard_fd_mutex nests within the ust_mutex. This mutex + * is also held across fork. */ static pthread_mutex_t ust_safe_guard_fd_mutex = PTHREAD_MUTEX_INITIALIZER; + /* * Track whether we are within lttng-ust or application, for close - * system call override by LD_PRELOAD library. + * system call override by LD_PRELOAD library. This also tracks whether + * we are invoking close() from a signal handler nested on an + * application thread. */ -static DEFINE_URCU_TLS(int, thread_fd_tracking); +static DEFINE_URCU_TLS(int, ust_fd_mutex_nest); /* fd_set used to book keep fd being used by lttng-ust. */ static fd_set *lttng_fd_set; @@ -80,7 +89,7 @@ static int init_done; */ void lttng_ust_fixup_fd_tracker_tls(void) { - asm volatile ("" : : "m" (URCU_TLS(thread_fd_tracking))); + asm volatile ("" : : "m" (URCU_TLS(ust_fd_mutex_nest))); } /* @@ -124,24 +133,56 @@ void lttng_ust_init_fd_tracker(void) void lttng_ust_lock_fd_tracker(void) { - URCU_TLS(thread_fd_tracking) = 1; - /* - * Ensure the compiler don't move the store after the close() - * call in case close() would be marked as leaf. - */ - cmm_barrier(); - pthread_mutex_lock(&ust_safe_guard_fd_mutex); + sigset_t sig_all_blocked, orig_mask; + int ret; + + if (lttng_ust_cancelstate_disable_push()) { + ERR("lttng_ust_cancelstate_disable_push"); + } + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (!URCU_TLS(ust_fd_mutex_nest)++) { + /* + * Ensure the compiler don't move the store after the close() + * call in case close() would be marked as leaf. + */ + cmm_barrier(); + pthread_mutex_lock(&ust_safe_guard_fd_mutex); + } + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } } void lttng_ust_unlock_fd_tracker(void) { - pthread_mutex_unlock(&ust_safe_guard_fd_mutex); + sigset_t sig_all_blocked, orig_mask; + int ret; + + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } /* * Ensure the compiler don't move the store before the close() * call, in case close() would be marked as leaf. */ cmm_barrier(); - URCU_TLS(thread_fd_tracking) = 0; + if (!--URCU_TLS(ust_fd_mutex_nest)) { + pthread_mutex_unlock(&ust_safe_guard_fd_mutex); + } + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (lttng_ust_cancelstate_disable_pop()) { + ERR("lttng_ust_cancelstate_disable_pop"); + } } static int dup_std_fd(int fd) @@ -231,7 +272,7 @@ int lttng_ust_add_fd_to_tracker(int fd) * constructors. */ lttng_ust_init_fd_tracker(); - assert(URCU_TLS(thread_fd_tracking)); + assert(URCU_TLS(ust_fd_mutex_nest)); if (IS_FD_STD(fd)) { ret = dup_std_fd(fd); @@ -264,7 +305,7 @@ void lttng_ust_delete_fd_from_tracker(int fd) */ lttng_ust_init_fd_tracker(); - assert(URCU_TLS(thread_fd_tracking)); + assert(URCU_TLS(ust_fd_mutex_nest)); /* Not a valid fd. */ assert(IS_FD_VALID(fd)); /* Deleting an fd which was not set. */ @@ -294,7 +335,7 @@ int lttng_ust_safe_close_fd(int fd, int (*close_cb)(int fd)) * If called from lttng-ust, we directly call close without * validating whether the FD is part of the tracked set. */ - if (URCU_TLS(thread_fd_tracking)) + if (URCU_TLS(ust_fd_mutex_nest)) return close_cb(fd); lttng_ust_lock_fd_tracker(); @@ -330,7 +371,7 @@ int lttng_ust_safe_fclose_stream(FILE *stream, int (*fclose_cb)(FILE *stream)) * If called from lttng-ust, we directly call fclose without * validating whether the FD is part of the tracked set. */ - if (URCU_TLS(thread_fd_tracking)) + if (URCU_TLS(ust_fd_mutex_nest)) return fclose_cb(stream); fd = fileno(stream); @@ -393,7 +434,7 @@ int lttng_ust_safe_closefrom_fd(int lowfd, int (*close_cb)(int fd)) * If called from lttng-ust, we directly call close without * validating whether the FD is part of the tracked set. */ - if (URCU_TLS(thread_fd_tracking)) { + if (URCU_TLS(ust_fd_mutex_nest)) { for (i = lowfd; i < lttng_ust_max_fd; i++) { if (close_cb(i) < 0) { switch (errno) { @@ -438,3 +479,62 @@ int lttng_ust_safe_closefrom_fd(int lowfd, int (*close_cb)(int fd)) end: return ret; } + +/* + * Implement helper for close_range() override. + */ +int lttng_ust_safe_close_range_fd(unsigned int first, unsigned int last, int flags, + int (*close_range_cb)(unsigned int first, unsigned int last, int flags)) +{ + int ret = 0, i; + + lttng_ust_fixup_fd_tracker_tls(); + + /* + * Ensure the tracker is initialized when called from + * constructors. + */ + lttng_ust_init_fd_tracker(); + + if (first > last || last > INT_MAX) { + ret = -1; + errno = EINVAL; + goto end; + } + /* + * If called from lttng-ust, we directly call close_range + * without validating whether the FD is part of the tracked set. + */ + if (URCU_TLS(ust_fd_mutex_nest)) { + if (close_range_cb(first, last, flags) < 0) { + ret = -1; + goto end; + } + } else { + int last_check = last; + + if (last > lttng_ust_max_fd) + last_check = lttng_ust_max_fd; + lttng_ust_lock_fd_tracker(); + for (i = first; i <= last_check; i++) { + if (IS_FD_VALID(i) && IS_FD_SET(i, lttng_fd_set)) + continue; + if (close_range_cb(i, i, flags) < 0) { + ret = -1; + /* propagate errno from close_range_cb. */ + lttng_ust_unlock_fd_tracker(); + goto end; + } + } + if (last > lttng_ust_max_fd) { + if (close_range_cb(lttng_ust_max_fd + 1, last, flags) < 0) { + ret = -1; + lttng_ust_unlock_fd_tracker(); + goto end; + } + } + lttng_ust_unlock_fd_tracker(); + } +end: + return ret; +}