Make the pthread_rwlock implementation header-only macros [2/2]

While using mutrace, the phtread-rwlock based isc_rwlock implementation
would be all tracked in the rwlock.c unit losing all useful information
as all rwlocks would be traced in a single place.  Rewrite the
pthread_rwlock based implementation to be header-only macros, so we can
use mutrace to properly track the rwlock contention without heavily
patching mutrace to understand the libisc synchronization primitives.
This commit is contained in:
Ondřej Surý
2022-10-14 12:54:57 +02:00
parent 6bd201ccec
commit 0492bbf590
6 changed files with 110 additions and 100 deletions

View File

@@ -622,6 +622,7 @@ AS_IF([test "$enable_pthread_rwlock" = "yes"],
[AC_MSG_ERROR([pthread_rwlock_rdlock requested but not found])])
AC_DEFINE([USE_PTHREAD_RWLOCK],[1],[Define if you want to use pthread rwlock implementation])
])
AM_CONDITIONAL([USE_ISC_RWLOCK], [test "$enable_pthread_rwlock" != "yes"])
CRYPTO=OpenSSL

View File

@@ -189,7 +189,6 @@ libisc_la_SOURCES = \
region.c \
resource.c \
result.c \
rwlock.c \
safe.c \
serial.c \
signal.c \
@@ -216,6 +215,11 @@ libisc_la_SOURCES = \
xml.c \
work.c
if USE_ISC_RWLOCK
libisc_la_SOURCES += \
rwlock.c
endif USE_ISC_RWLOCK
libisc_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBISC_CFLAGS) \

View File

@@ -28,6 +28,12 @@
ISC_LANG_BEGINDECLS
/*
* We use macros instead of static inline functions so that the exact code
* location can be reported when PTHREADS_RUNTIME_CHECK() fails or when mutrace
* reports lock contention.
*/
#ifdef ISC_TRACK_PTHREADS_OBJECTS
typedef pthread_cond_t *isc_condition_t;

View File

@@ -25,6 +25,12 @@
ISC_LANG_BEGINDECLS
/*
* We use macros instead of static inline functions so that the exact code
* location can be reported when PTHREADS_RUNTIME_CHECK() fails or when mutrace
* reports lock contention.
*/
#ifdef ISC_TRACK_PTHREADS_OBJECTS
typedef pthread_mutex_t *isc_mutex_t;

View File

@@ -35,6 +35,12 @@ typedef enum {
#if USE_PTHREAD_RWLOCK
#include <pthread.h>
/*
* We use macros instead of static inline functions so that the exact code
* location can be reported when PTHREADS_RUNTIME_CHECK() fails or when mutrace
* reports lock contention.
*/
#if ISC_TRACK_PTHREADS_OBJECTS
typedef pthread_rwlock_t *isc_rwlock_t;
@@ -69,6 +75,89 @@ typedef pthread_rwlock_t isc__rwlock_t;
#endif /* ISC_TRACK_PTHREADS_OBJECTS */
#define isc__rwlock_init(rwl, read_quota, write_quote) \
{ \
int _ret = pthread_rwlock_init(rwl, NULL); \
PTHREADS_RUNTIME_CHECK(pthread_rwlock_init, _ret); \
}
#define isc__rwlock_lock(rwl, type) \
{ \
int _ret; \
switch (type) { \
case isc_rwlocktype_read: \
_ret = pthread_rwlock_rdlock(rwl); \
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rdlock, _ret); \
break; \
case isc_rwlocktype_write: \
_ret = pthread_rwlock_wrlock(rwl); \
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rwlock, _ret); \
break; \
default: \
UNREACHABLE(); \
} \
}
#define isc__rwlock_trylock(rwl, type) \
({ \
int _ret = 0; \
isc_result_t _res = ISC_R_UNSET; \
\
switch (type) { \
case isc_rwlocktype_read: \
_ret = pthread_rwlock_tryrdlock(rwl); \
break; \
case isc_rwlocktype_write: \
_ret = pthread_rwlock_trywrlock(rwl); \
break; \
default: \
UNREACHABLE(); \
} \
\
switch (_ret) { \
case 0: \
_res = ISC_R_SUCCESS; \
break; \
case EBUSY: \
case EAGAIN: \
_res = ISC_R_LOCKBUSY; \
break; \
default: \
switch (type) { \
case isc_rwlocktype_read: \
PTHREADS_RUNTIME_CHECK( \
pthread_rwlock_tryrdlock, _ret); \
break; \
case isc_rwlocktype_write: \
PTHREADS_RUNTIME_CHECK( \
pthread_rwlock_trywrlock, _ret); \
break; \
default: \
UNREACHABLE(); \
} \
UNREACHABLE(); \
} \
_res; \
})
#define isc__rwlock_unlock(rwl, type) \
{ \
int _ret = pthread_rwlock_unlock(rwl); \
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rwlock, _ret); \
}
#define isc__rwlock_tryupgrade(rwl) \
({ \
UNUSED(rwl); \
ISC_R_LOCKBUSY; \
})
#define isc__rwlock_destroy(rwl) \
{ \
int _ret = pthread_rwlock_destroy(rwl); \
PTHREADS_RUNTIME_CHECK(pthread_rwlock_destroy, _ret); \
}
#else /* USE_PTHREAD_RWLOCK */
struct isc_rwlock {
@@ -117,8 +206,6 @@ typedef struct isc_rwlock isc__rwlock_t;
#define isc_rwlock_tryupgrade(rwl) isc__rwlock_tryupgrade(rwl)
#define isc_rwlock_destroy(rwl) isc__rwlock_destroy(rwl)
#endif /* USE_PTHREAD_RWLOCK */
void
isc__rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota);
@@ -138,4 +225,6 @@ isc__rwlock_tryupgrade(isc__rwlock_t *rwl);
void
isc__rwlock_destroy(isc__rwlock_t *rwl);
#endif /* USE_PTHREAD_RWLOCK */
ISC_LANG_ENDDECLS

View File

@@ -27,100 +27,6 @@
#include <isc/rwlock.h>
#include <isc/util.h>
#if USE_PTHREAD_RWLOCK
#include <errno.h>
#include <pthread.h>
void
isc__rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
int ret;
UNUSED(read_quota);
UNUSED(write_quota);
ret = pthread_rwlock_init(rwl, NULL);
PTHREADS_RUNTIME_CHECK(pthread_rwlock_init, ret);
}
void
isc__rwlock_lock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int ret;
switch (type) {
case isc_rwlocktype_read:
ret = pthread_rwlock_rdlock(rwl);
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rdlock, ret);
break;
case isc_rwlocktype_write:
ret = pthread_rwlock_wrlock(rwl);
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rwlock, ret);
break;
default:
UNREACHABLE();
}
}
isc_result_t
isc__rwlock_trylock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int ret = 0;
switch (type) {
case isc_rwlocktype_read:
ret = pthread_rwlock_tryrdlock(rwl);
break;
case isc_rwlocktype_write:
ret = pthread_rwlock_trywrlock(rwl);
break;
default:
UNREACHABLE();
}
switch (ret) {
case 0:
return (ISC_R_SUCCESS);
case EBUSY:
return (ISC_R_LOCKBUSY);
case EAGAIN:
return (ISC_R_LOCKBUSY);
default:
break;
}
switch (type) {
case isc_rwlocktype_read:
PTHREADS_RUNTIME_CHECK(pthread_rwlock_tryrdlock, ret);
break;
case isc_rwlocktype_write:
PTHREADS_RUNTIME_CHECK(pthread_rwlock_trywrlock, ret);
break;
default:
break;
}
UNREACHABLE();
}
void
isc__rwlock_unlock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int ret;
UNUSED(type);
ret = pthread_rwlock_unlock(rwl);
PTHREADS_RUNTIME_CHECK(pthread_rwlock_rwlock, ret);
}
isc_result_t
isc__rwlock_tryupgrade(isc__rwlock_t *rwl) {
UNUSED(rwl);
return (ISC_R_LOCKBUSY);
}
void
isc__rwlock_destroy(isc__rwlock_t *rwl) {
int ret = pthread_rwlock_destroy(rwl);
PTHREADS_RUNTIME_CHECK(pthread_rwlock_destroy, ret);
}
#else /* if USE_PTHREAD_RWLOCK */
#define RWLOCK_MAGIC ISC_MAGIC('R', 'W', 'L', 'k')
#define VALID_RWLOCK(rwl) ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC)
@@ -178,7 +84,7 @@ print_lock(const char *operation, isc__rwlock_t *rwl, isc_rwlocktype_t type) {
atomic_load_acquire(&rwl->cnt_and_flag), rwl->readers_waiting,
atomic_load_acquire(&rwl->write_granted), rwl->write_quota);
}
#endif /* ISC_RWLOCK_TRACE */
#endif /* ISC_RWLOCK_TRACE */
void
isc__rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
@@ -595,5 +501,3 @@ isc__rwlock_unlock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
print_lock("postunlock", rwl, type);
#endif /* ifdef ISC_RWLOCK_TRACE */
}
#endif /* USE_PTHREAD_RWLOCK */