swsignal.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /************************************************************************
  2. * AUTHOR: NiuJiuRu
  3. * FILENAME: swsignal.c
  4. * DESCRIPTION: 信号量
  5. * NOTE: 主要用于状态通知
  6. * HISTORY:
  7. * 1, [2010-12-17] created by NiuJiuRu
  8. * 2, [2025-11-24] 优化修改"sw_signal_wait()"函数, 避免依赖系统时间, 导致的
  9. * 超时误差或跳变问题
  10. ***********************************************************************/
  11. #include "swapi.h"
  12. #include "swmem.h"
  13. #include "swsignal.h"
  14. /* 创建信号量 */
  15. void *sw_signal_create()
  16. {
  17. sem_t *sem = NULL;
  18. sem = (sem_t *)sw_heap_malloc(sizeof(sem_t));
  19. if(sem && sem_init(sem, 0, 0) != 0)
  20. {
  21. sw_heap_free(sem); sem = NULL;
  22. }
  23. return sem;
  24. }
  25. /* 销毁信号量 */
  26. void sw_signal_destroy(void *hSignal)
  27. {
  28. sem_t *sem = (sem_t *)hSignal;
  29. sem_destroy(sem);
  30. sw_heap_free(sem);
  31. }
  32. /* 等待信号量, timeout(ms) = -1时表示无限等待 */
  33. int sw_signal_wait(void *hSignal, int timeout)
  34. {
  35. sem_t *sem = (sem_t *)hSignal;
  36. int ret;
  37. if(timeout < 0)
  38. {
  39. wait_p1:
  40. ret = sem_wait(sem);
  41. if(ret < 0 && errno == EINTR) goto wait_p1;
  42. else return ret;
  43. }
  44. else
  45. {
  46. #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 30)
  47. struct timespec ts, now;
  48. clock_gettime(CLOCK_MONOTONIC/*单调时钟, 不受系统时间影响*/, &now);
  49. ts.tv_sec = now.tv_sec + timeout/1000;
  50. ts.tv_nsec = now.tv_nsec + (timeout%1000)*1000*1000;
  51. if(ts.tv_nsec >= (1000*1000*1000))
  52. {
  53. ts.tv_sec += ts.tv_nsec/(1000*1000*1000);
  54. ts.tv_nsec %= (1000*1000*1000);
  55. }
  56. wait_p2:
  57. ret = sem_clockwait(sem, CLOCK_MONOTONIC, &ts); // 非POSIX标准, GNU扩展, 需定义:"_GNU_SOURCE"支持
  58. // , 同时glic库版本需大于等于2.30
  59. if(ret < 0 && errno == EINTR) goto wait_p2;
  60. else return ret;
  61. #else
  62. struct timespec start, now; clock_gettime(CLOCK_MONOTONIC, &start);
  63. while((ret = sem_trywait(sem)) < 0 && errno == EAGAIN)
  64. {
  65. clock_gettime(CLOCK_MONOTONIC, &now);
  66. long long elapsed = (now.tv_sec*1000LL + now.tv_nsec/1000000) - (start.tv_sec*1000LL + start.tv_nsec/1000000);
  67. if(elapsed >= timeout) { errno = ETIMEDOUT; return -1; }
  68. else delay_ms(1); // 释放CPU占用, 避免过载
  69. }
  70. return ret;
  71. #endif
  72. }
  73. }
  74. /* 点亮信号量 */
  75. void sw_signal_give(void *hSignal)
  76. {
  77. sem_t *sem = (sem_t *)hSignal;
  78. sem_post(sem);
  79. }