/************************************************************************
 * AUTHOR: NiuJiuRu
 * FILENAME: sw_rwlock.c
 * DESCRIPTION: 读写锁, 也称共享锁
 * NOTE: 主要用于多线程同步访问全局共享资源
 * HISTORY:
 * 1, [2014-01-24] created by NiuJiuRu
 * 2, [2026-03-17] 优化修改"sw_rwlock_rdlock()"和"sw_rwlock_wrlock()"函数,
 *                 避免依赖系统时间, 导致的超时误差或跳变问题
 ***********************************************************************/
#include "swapi.h"
#include "swmem.h"
#include "sw_rwlock.h"

/* 创建读写锁 */
void *sw_rwlock_create()
{
    pthread_rwlock_t *rwlock = NULL;
    pthread_rwlockattr_t attr;
    
    rwlock = (pthread_rwlock_t *)sw_heap_malloc(sizeof(pthread_rwlock_t));
    if(rwlock)
    {
        if(pthread_rwlockattr_init(&attr) != 0) { sw_heap_free(rwlock); return NULL; }
        // note: "If the process-shared attribute is PTHREAD_PRO-CESS_PRIVATE, the read-write lock shall only be 
        // operated upon by threads created within the same process as the thread that initialized the read-write lock;
        // if threads of differing processes attempt to operate on such a read-write lock, the behavior is undefined."
        if(pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0 || pthread_rwlock_init(rwlock, &attr) != 0) { sw_heap_free(rwlock); rwlock = NULL; }
        pthread_rwlockattr_destroy(&attr);
    }
    
    return rwlock;
}

/* 销毁读写锁 */
void sw_rwlock_destroy(void *hRWLock)
{
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)hRWLock;
    pthread_rwlock_destroy(rwlock);
    sw_heap_free(rwlock);
}

/* 读写锁上锁-读(超时设置的时间单位为: 毫秒, 并且当timeout = -1时表示无限等待) */
int sw_rwlock_rdlock(void *hRWLock, int timeout)
{
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)hRWLock;
    struct timespec start, now; int ret;
    
    if(timeout < 0)
    {
        return pthread_rwlock_rdlock(rwlock);
    }
	
	clock_gettime(CLOCK_MONOTONIC, &start);
	while((ret = pthread_rwlock_tryrdlock(rwlock)) == EBUSY)
	{
		clock_gettime(CLOCK_MONOTONIC, &now);
		long long elapsed = (now.tv_sec*1000LL + now.tv_nsec/1000000) - (start.tv_sec*1000LL + start.tv_nsec/1000000);
		if(elapsed >= timeout) { errno = ETIMEDOUT; return -1; }
		else delay_ms(1); // 释放CPU占用, 避免过载
	}
	
	return ret == 0 ? 0 : -1;
}

/* 读写锁上锁-写(超时设置的时间单位为: 毫秒, 并且当timeout = -1时表示无限等待) */
int sw_rwlock_wrlock(void *hRWLock, int timeout)
{
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)hRWLock;
    struct timespec start, now; int ret;
    
    if(timeout < 0)
    {
        return pthread_rwlock_wrlock(rwlock);
    }
	
    clock_gettime(CLOCK_MONOTONIC, &start);
	while((ret = pthread_rwlock_trywrlock(rwlock)) == EBUSY)
	{
		clock_gettime(CLOCK_MONOTONIC, &now);
		long long elapsed = (now.tv_sec*1000LL + now.tv_nsec/1000000) - (start.tv_sec*1000LL + start.tv_nsec/1000000);
		if(elapsed >= timeout) { errno = ETIMEDOUT; return -1; }
		else delay_ms(1); // 释放CPU占用, 避免过载
	}
	
	return ret == 0 ? 0 : -1;
}

/* 读写锁解锁 */
void sw_rwlock_unlock(void *hRWLock)
{
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)hRWLock;
    pthread_rwlock_unlock(rwlock);
}
