18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#define _GNU_SOURCE 38c2ecf20Sopenharmony_ci#include <pthread.h> 48c2ecf20Sopenharmony_ci#include <stdio.h> 58c2ecf20Sopenharmony_ci#include <dlfcn.h> 68c2ecf20Sopenharmony_ci#include <stdlib.h> 78c2ecf20Sopenharmony_ci#include <sysexits.h> 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include "include/liblockdep/mutex.h" 108c2ecf20Sopenharmony_ci#include "../../include/linux/rbtree.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/** 138c2ecf20Sopenharmony_ci * struct lock_lookup - liblockdep's view of a single unique lock 148c2ecf20Sopenharmony_ci * @orig: pointer to the original pthread lock, used for lookups 158c2ecf20Sopenharmony_ci * @dep_map: lockdep's dep_map structure 168c2ecf20Sopenharmony_ci * @key: lockdep's key structure 178c2ecf20Sopenharmony_ci * @node: rb-tree node used to store the lock in a global tree 188c2ecf20Sopenharmony_ci * @name: a unique name for the lock 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistruct lock_lookup { 218c2ecf20Sopenharmony_ci void *orig; /* Original pthread lock, used for lookups */ 228c2ecf20Sopenharmony_ci struct lockdep_map dep_map; /* Since all locks are dynamic, we need 238c2ecf20Sopenharmony_ci * a dep_map and a key for each lock */ 248c2ecf20Sopenharmony_ci /* 258c2ecf20Sopenharmony_ci * Wait, there's no support for key classes? Yup :( 268c2ecf20Sopenharmony_ci * Most big projects wrap the pthread api with their own calls to 278c2ecf20Sopenharmony_ci * be compatible with different locking methods. This means that 288c2ecf20Sopenharmony_ci * "classes" will be brokes since the function that creates all 298c2ecf20Sopenharmony_ci * locks will point to a generic locking function instead of the 308c2ecf20Sopenharmony_ci * actual code that wants to do the locking. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci struct lock_class_key key; 338c2ecf20Sopenharmony_ci struct rb_node node; 348c2ecf20Sopenharmony_ci#define LIBLOCKDEP_MAX_LOCK_NAME 22 358c2ecf20Sopenharmony_ci char name[LIBLOCKDEP_MAX_LOCK_NAME]; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* This is where we store our locks */ 398c2ecf20Sopenharmony_cistatic struct rb_root locks = RB_ROOT; 408c2ecf20Sopenharmony_cistatic pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* pthread mutex API */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#ifdef __GLIBC__ 458c2ecf20Sopenharmony_ciextern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); 468c2ecf20Sopenharmony_ciextern int __pthread_mutex_lock(pthread_mutex_t *mutex); 478c2ecf20Sopenharmony_ciextern int __pthread_mutex_trylock(pthread_mutex_t *mutex); 488c2ecf20Sopenharmony_ciextern int __pthread_mutex_unlock(pthread_mutex_t *mutex); 498c2ecf20Sopenharmony_ciextern int __pthread_mutex_destroy(pthread_mutex_t *mutex); 508c2ecf20Sopenharmony_ci#else 518c2ecf20Sopenharmony_ci#define __pthread_mutex_init NULL 528c2ecf20Sopenharmony_ci#define __pthread_mutex_lock NULL 538c2ecf20Sopenharmony_ci#define __pthread_mutex_trylock NULL 548c2ecf20Sopenharmony_ci#define __pthread_mutex_unlock NULL 558c2ecf20Sopenharmony_ci#define __pthread_mutex_destroy NULL 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_cistatic int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex, 588c2ecf20Sopenharmony_ci const pthread_mutexattr_t *attr) = __pthread_mutex_init; 598c2ecf20Sopenharmony_cistatic int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock; 608c2ecf20Sopenharmony_cistatic int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock; 618c2ecf20Sopenharmony_cistatic int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock; 628c2ecf20Sopenharmony_cistatic int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* pthread rwlock API */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#ifdef __GLIBC__ 678c2ecf20Sopenharmony_ciextern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); 688c2ecf20Sopenharmony_ciextern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 698c2ecf20Sopenharmony_ciextern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 708c2ecf20Sopenharmony_ciextern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 718c2ecf20Sopenharmony_ciextern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 728c2ecf20Sopenharmony_ciextern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 738c2ecf20Sopenharmony_ciextern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock); 748c2ecf20Sopenharmony_ci#else 758c2ecf20Sopenharmony_ci#define __pthread_rwlock_init NULL 768c2ecf20Sopenharmony_ci#define __pthread_rwlock_destroy NULL 778c2ecf20Sopenharmony_ci#define __pthread_rwlock_wrlock NULL 788c2ecf20Sopenharmony_ci#define __pthread_rwlock_trywrlock NULL 798c2ecf20Sopenharmony_ci#define __pthread_rwlock_rdlock NULL 808c2ecf20Sopenharmony_ci#define __pthread_rwlock_tryrdlock NULL 818c2ecf20Sopenharmony_ci#define __pthread_rwlock_unlock NULL 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock, 858c2ecf20Sopenharmony_ci const pthread_rwlockattr_t *attr) = __pthread_rwlock_init; 868c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy; 878c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock; 888c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock; 898c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock; 908c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock; 918c2ecf20Sopenharmony_cistatic int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cienum { none, prepare, done, } __init_state; 948c2ecf20Sopenharmony_cistatic void init_preload(void); 958c2ecf20Sopenharmony_cistatic void try_init_preload(void) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci if (__init_state != done) 988c2ecf20Sopenharmony_ci init_preload(); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct rb_node **node = &locks.rb_node; 1048c2ecf20Sopenharmony_ci struct lock_lookup *l; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci *parent = NULL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci while (*node) { 1098c2ecf20Sopenharmony_ci l = rb_entry(*node, struct lock_lookup, node); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci *parent = *node; 1128c2ecf20Sopenharmony_ci if (lock < l->orig) 1138c2ecf20Sopenharmony_ci node = &l->node.rb_left; 1148c2ecf20Sopenharmony_ci else if (lock > l->orig) 1158c2ecf20Sopenharmony_ci node = &l->node.rb_right; 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci return node; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return node; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#ifndef LIBLOCKDEP_STATIC_ENTRIES 1248c2ecf20Sopenharmony_ci#define LIBLOCKDEP_STATIC_ENTRIES 1024 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; 1288c2ecf20Sopenharmony_cistatic int __locks_nr; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline bool is_static_lock(struct lock_lookup *lock) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct lock_lookup *alloc_lock(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci if (__init_state != done) { 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * Some programs attempt to initialize and use locks in their 1408c2ecf20Sopenharmony_ci * allocation path. This means that a call to malloc() would 1418c2ecf20Sopenharmony_ci * result in locks being initialized and locked. 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Why is it an issue for us? dlsym() below will try allocating 1448c2ecf20Sopenharmony_ci * to give us the original function. Since this allocation will 1458c2ecf20Sopenharmony_ci * result in a locking operations, we have to let pthread deal 1468c2ecf20Sopenharmony_ci * with it, but we can't! we don't have the pointer to the 1478c2ecf20Sopenharmony_ci * original API since we're inside dlsym() trying to get it 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci int idx = __locks_nr++; 1518c2ecf20Sopenharmony_ci if (idx >= ARRAY_SIZE(__locks)) { 1528c2ecf20Sopenharmony_ci dprintf(STDERR_FILENO, 1538c2ecf20Sopenharmony_ci "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); 1548c2ecf20Sopenharmony_ci exit(EX_UNAVAILABLE); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci return __locks + idx; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return malloc(sizeof(struct lock_lookup)); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic inline void free_lock(struct lock_lookup *lock) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci if (likely(!is_static_lock(lock))) 1658c2ecf20Sopenharmony_ci free(lock); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/** 1698c2ecf20Sopenharmony_ci * __get_lock - find or create a lock instance 1708c2ecf20Sopenharmony_ci * @lock: pointer to a pthread lock function 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * Try to find an existing lock in the rbtree using the provided pointer. If 1738c2ecf20Sopenharmony_ci * one wasn't found - create it. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic struct lock_lookup *__get_lock(void *lock) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct rb_node **node, *parent; 1788c2ecf20Sopenharmony_ci struct lock_lookup *l; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ll_pthread_rwlock_rdlock(&locks_rwlock); 1818c2ecf20Sopenharmony_ci node = __get_lock_node(lock, &parent); 1828c2ecf20Sopenharmony_ci ll_pthread_rwlock_unlock(&locks_rwlock); 1838c2ecf20Sopenharmony_ci if (*node) { 1848c2ecf20Sopenharmony_ci return rb_entry(*node, struct lock_lookup, node); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* We didn't find the lock, let's create it */ 1888c2ecf20Sopenharmony_ci l = alloc_lock(); 1898c2ecf20Sopenharmony_ci if (l == NULL) 1908c2ecf20Sopenharmony_ci return NULL; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci l->orig = lock; 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Currently the name of the lock is the ptr value of the pthread lock, 1958c2ecf20Sopenharmony_ci * while not optimal, it makes debugging a bit easier. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * TODO: Get the real name of the lock using libdwarf 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci sprintf(l->name, "%p", lock); 2008c2ecf20Sopenharmony_ci lockdep_init_map(&l->dep_map, l->name, &l->key, 0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ll_pthread_rwlock_wrlock(&locks_rwlock); 2038c2ecf20Sopenharmony_ci /* This might have changed since the last time we fetched it */ 2048c2ecf20Sopenharmony_ci node = __get_lock_node(lock, &parent); 2058c2ecf20Sopenharmony_ci rb_link_node(&l->node, parent, node); 2068c2ecf20Sopenharmony_ci rb_insert_color(&l->node, &locks); 2078c2ecf20Sopenharmony_ci ll_pthread_rwlock_unlock(&locks_rwlock); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return l; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void __del_lock(struct lock_lookup *lock) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci ll_pthread_rwlock_wrlock(&locks_rwlock); 2158c2ecf20Sopenharmony_ci rb_erase(&lock->node, &locks); 2168c2ecf20Sopenharmony_ci ll_pthread_rwlock_unlock(&locks_rwlock); 2178c2ecf20Sopenharmony_ci free_lock(lock); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciint pthread_mutex_init(pthread_mutex_t *mutex, 2218c2ecf20Sopenharmony_ci const pthread_mutexattr_t *attr) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci int r; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * We keep trying to init our preload module because there might be 2278c2ecf20Sopenharmony_ci * code in init sections that tries to touch locks before we are 2288c2ecf20Sopenharmony_ci * initialized, in that case we'll need to manually call preload 2298c2ecf20Sopenharmony_ci * to get us going. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Funny enough, kernel's lockdep had the same issue, and used 2328c2ecf20Sopenharmony_ci * (almost) the same solution. See look_up_lock_class() in 2338c2ecf20Sopenharmony_ci * kernel/locking/lockdep.c for details. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci try_init_preload(); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci r = ll_pthread_mutex_init(mutex, attr); 2388c2ecf20Sopenharmony_ci if (r == 0) 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * We do a dummy initialization here so that lockdep could 2418c2ecf20Sopenharmony_ci * warn us if something fishy is going on - such as 2428c2ecf20Sopenharmony_ci * initializing a held lock. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci __get_lock(mutex); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return r; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ciint pthread_mutex_lock(pthread_mutex_t *mutex) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int r; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci try_init_preload(); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, 2568c2ecf20Sopenharmony_ci (unsigned long)_RET_IP_); 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Here's the thing with pthread mutexes: unlike the kernel variant, 2598c2ecf20Sopenharmony_ci * they can fail. 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * This means that the behaviour here is a bit different from what's 2628c2ecf20Sopenharmony_ci * going on in the kernel: there we just tell lockdep that we took the 2638c2ecf20Sopenharmony_ci * lock before actually taking it, but here we must deal with the case 2648c2ecf20Sopenharmony_ci * that locking failed. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * To do that we'll "release" the lock if locking failed - this way 2678c2ecf20Sopenharmony_ci * we'll get lockdep doing the correct checks when we try to take 2688c2ecf20Sopenharmony_ci * the lock, and if that fails - we'll be back to the correct 2698c2ecf20Sopenharmony_ci * state by releasing it. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci r = ll_pthread_mutex_lock(mutex); 2728c2ecf20Sopenharmony_ci if (r) 2738c2ecf20Sopenharmony_ci lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return r; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciint pthread_mutex_trylock(pthread_mutex_t *mutex) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci int r; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci try_init_preload(); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); 2858c2ecf20Sopenharmony_ci r = ll_pthread_mutex_trylock(mutex); 2868c2ecf20Sopenharmony_ci if (r) 2878c2ecf20Sopenharmony_ci lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return r; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciint pthread_mutex_unlock(pthread_mutex_t *mutex) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci int r; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci try_init_preload(); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci lock_release(&__get_lock(mutex)->dep_map, (unsigned long)_RET_IP_); 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * Just like taking a lock, only in reverse! 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * If we fail releasing the lock, tell lockdep we're holding it again. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci r = ll_pthread_mutex_unlock(mutex); 3058c2ecf20Sopenharmony_ci if (r) 3068c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return r; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciint pthread_mutex_destroy(pthread_mutex_t *mutex) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci try_init_preload(); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * Let's see if we're releasing a lock that's held. 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * TODO: Hook into free() and add that check there as well. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci debug_check_no_locks_freed(mutex, sizeof(*mutex)); 3218c2ecf20Sopenharmony_ci __del_lock(__get_lock(mutex)); 3228c2ecf20Sopenharmony_ci return ll_pthread_mutex_destroy(mutex); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/* This is the rwlock part, very similar to what happened with mutex above */ 3268c2ecf20Sopenharmony_ciint pthread_rwlock_init(pthread_rwlock_t *rwlock, 3278c2ecf20Sopenharmony_ci const pthread_rwlockattr_t *attr) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int r; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci try_init_preload(); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_init(rwlock, attr); 3348c2ecf20Sopenharmony_ci if (r == 0) 3358c2ecf20Sopenharmony_ci __get_lock(rwlock); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return r; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint pthread_rwlock_destroy(pthread_rwlock_t *rwlock) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci try_init_preload(); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci debug_check_no_locks_freed(rwlock, sizeof(*rwlock)); 3458c2ecf20Sopenharmony_ci __del_lock(__get_lock(rwlock)); 3468c2ecf20Sopenharmony_ci return ll_pthread_rwlock_destroy(rwlock); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciint pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci int r; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci init_preload(); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_); 3568c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_rdlock(rwlock); 3578c2ecf20Sopenharmony_ci if (r) 3588c2ecf20Sopenharmony_ci lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return r; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciint pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int r; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci init_preload(); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_); 3708c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_tryrdlock(rwlock); 3718c2ecf20Sopenharmony_ci if (r) 3728c2ecf20Sopenharmony_ci lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return r; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ciint pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int r; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci init_preload(); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); 3848c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_trywrlock(rwlock); 3858c2ecf20Sopenharmony_ci if (r) 3868c2ecf20Sopenharmony_ci lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return r; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ciint pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int r; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci init_preload(); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); 3988c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_wrlock(rwlock); 3998c2ecf20Sopenharmony_ci if (r) 4008c2ecf20Sopenharmony_ci lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return r; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ciint pthread_rwlock_unlock(pthread_rwlock_t *rwlock) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci int r; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci init_preload(); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci lock_release(&__get_lock(rwlock)->dep_map, (unsigned long)_RET_IP_); 4128c2ecf20Sopenharmony_ci r = ll_pthread_rwlock_unlock(rwlock); 4138c2ecf20Sopenharmony_ci if (r) 4148c2ecf20Sopenharmony_ci lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return r; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci__attribute__((constructor)) static void init_preload(void) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci if (__init_state == done) 4228c2ecf20Sopenharmony_ci return; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci#ifndef __GLIBC__ 4258c2ecf20Sopenharmony_ci __init_state = prepare; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init"); 4288c2ecf20Sopenharmony_ci ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock"); 4298c2ecf20Sopenharmony_ci ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock"); 4308c2ecf20Sopenharmony_ci ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); 4318c2ecf20Sopenharmony_ci ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init"); 4348c2ecf20Sopenharmony_ci ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy"); 4358c2ecf20Sopenharmony_ci ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock"); 4368c2ecf20Sopenharmony_ci ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock"); 4378c2ecf20Sopenharmony_ci ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock"); 4388c2ecf20Sopenharmony_ci ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock"); 4398c2ecf20Sopenharmony_ci ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); 4408c2ecf20Sopenharmony_ci#endif 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci __init_state = done; 4438c2ecf20Sopenharmony_ci} 444