+# ifdef REPORT_RWLOCK_CONTENTION
+/*
+ * Normally we would use a BIO here to do this, but we create locks during
+ * library initialization, and creating a bio too early, creates a recursive set
+ * of stack calls that leads us to call CRYPTO_thread_run_once while currently
+ * executing the init routine for various run_once functions, which leads to
+ * deadlock. Avoid that by just using a FILE pointer. Also note that we
+ * directly use a pthread_mutex_t to protect access from multiple threads
+ * to the contention log file. We do this because we want to avoid use
+ * of the CRYPTO_THREAD api so as to prevent recursive blocking reports.
+ */
+static FILE *contention_fp = NULL;
+static CRYPTO_ONCE init_contention_fp = CRYPTO_ONCE_STATIC_INIT;
+static int rwlock_count = 0;
+pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
+CRYPTO_THREAD_LOCAL thread_contention_data;
+
+static void destroy_contention_data(void *data)
+{
+ OPENSSL_free(data);
+}
+
+struct stack_info {
+ unsigned int nptrs;
+ int write;
+ OSSL_TIME start;
+ OSSL_TIME duration;
+ char **strings;
+};
+
+# define STACKS_COUNT 32
+struct stack_traces {
+ int lock_depth;
+ size_t idx;
+ struct stack_info stacks[STACKS_COUNT];
+};
+
+static void init_contention_fp_once(void)
+{
+# ifdef FIPS_MODULE
+ contention_fp = fopen("lock-contention-log-fips.txt", "w");
+# else
+ contention_fp = fopen("lock-contention-log.txt", "w");
+# endif
+ if (contention_fp == NULL)
+ fprintf(stderr, "Contention log file could not be opened, log will not be recorded\n");
+
+ /*
+ * Create a thread local key here to store our list of stack traces
+ * to be printed when we unlock the lock we are holding
+ */
+ CRYPTO_THREAD_init_local(&thread_contention_data, destroy_contention_data);
+ return;
+}
+# endif
+