/[LeafOK_CVS]/lbbs/src/user_list.c
ViewVC logotype

Diff of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.40 by sysadm, Thu Nov 20 02:56:46 2025 UTC Revision 1.44 by sysadm, Thu Nov 20 11:31:56 2025 UTC
# Line 23  Line 23 
23  #include <time.h>  #include <time.h>
24  #include <sys/mman.h>  #include <sys/mman.h>
25  #include <sys/param.h>  #include <sys/param.h>
 #include <sys/sem.h>  
26  #include <sys/stat.h>  #include <sys/stat.h>
27    
28  #if defined(_SEM_SEMUN_UNDEFINED) || defined(__CYGWIN__)  #ifdef HAVE_SYSTEM_V
29    #include <sys/sem.h>
30    
31    #ifdef _SEM_SEMUN_UNDEFINED
32  union semun  union semun
33  {  {
34          int val;                           /* Value for SETVAL */          int val;                           /* Value for SETVAL */
35          struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */          struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
36          unsigned short *array; /* Array for GETALL, SETALL */          unsigned short *array; /* Array for GETALL, SETALL */
37          struct seminfo *__buf; /* Buffer for IPC_INFO          struct seminfo *__buf; /* Buffer for IPC_INFO
38                                                            (Linux-specific) */                                                          (Linux-specific) */
39  };  };
40  #endif // #if defined(_SEM_SEMUN_UNDEFINED)  #endif // #ifdef _SEM_SEMUN_UNDEFINED
41    
42    #else
43    #include <semaphore.h>
44    #endif
45    
46  enum _user_list_constant_t  enum _user_list_constant_t
47  {  {
48          USER_LIST_TRY_LOCK_WAIT_TIME = 1, // second          USER_LIST_TRY_LOCK_WAIT_TIME = 1, // second
49          USER_LIST_TRY_LOCK_TIMES = 10,          USER_LIST_TRY_LOCK_TIMES = 10,
50            USER_LIST_DEAD_LOCK_TIMEOUT = 15, // second
51  };  };
52    
53  struct user_list_pool_t  struct user_list_pool_t
54  {  {
55          size_t shm_size;          size_t shm_size;
56    #ifndef HAVE_SYSTEM_V
57            sem_t sem;
58            uint16_t read_lock_count;
59            uint16_t write_lock_count;
60    #else
61          int semid;          int semid;
62    #endif
63          USER_LIST user_list[2];          USER_LIST user_list[2];
64          int user_list_index_current;          int user_list_index_current;
65          int user_list_index_new;          int user_list_index_new;
# Line 58  struct user_list_pool_t Line 71  struct user_list_pool_t
71  };  };
72  typedef struct user_list_pool_t USER_LIST_POOL;  typedef struct user_list_pool_t USER_LIST_POOL;
73    
74  static char user_list_shm_name[FILE_PATH_LEN];  static char user_list_shm_name[FILE_NAME_LEN];
75  static USER_LIST_POOL *p_user_list_pool = NULL;  static USER_LIST_POOL *p_user_list_pool = NULL;
76  static TRIE_NODE *p_trie_action_dict = NULL;  static TRIE_NODE *p_trie_action_dict = NULL;
77    
# Line 92  static int user_list_rd_unlock(void); Line 105  static int user_list_rd_unlock(void);
105  static int user_list_rw_unlock(void);  static int user_list_rw_unlock(void);
106  static int user_list_rd_lock(void);  static int user_list_rd_lock(void);
107  static int user_list_rw_lock(void);  static int user_list_rw_lock(void);
108    #ifndef HAVE_SYSTEM_V
109    static int user_list_reset_lock(void);
110    #endif
111    
112  static int user_list_load(MYSQL *db, USER_LIST *p_list);  static int user_list_load(MYSQL *db, USER_LIST *p_list);
113  static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list);  static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list);
# Line 393  int user_list_pool_init(const char *file Line 409  int user_list_pool_init(const char *file
409          int fd;          int fd;
410          size_t size;          size_t size;
411          void *p_shm;          void *p_shm;
412    #ifdef HAVE_SYSTEM_V
413          int proj_id;          int proj_id;
414          key_t key;          key_t key;
415          int semid;          int semid;
416          union semun arg;          union semun arg;
417    #endif
418          int i;          int i;
419    
420          if (p_user_list_pool != NULL || p_trie_action_dict != NULL)          if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
# Line 463  int user_list_pool_init(const char *file Line 481  int user_list_pool_init(const char *file
481          p_user_list_pool->shm_size = size;          p_user_list_pool->shm_size = size;
482    
483          // Allocate semaphore as user list pool lock          // Allocate semaphore as user list pool lock
484    #ifndef HAVE_SYSTEM_V
485            if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
486            {
487                    log_error("sem_init() error (%d)\n", errno);
488                    return -3;
489            }
490    
491            p_user_list_pool->read_lock_count = 0;
492            p_user_list_pool->write_lock_count = 0;
493    #else
494          proj_id = (int)(time(NULL) % getpid());          proj_id = (int)(time(NULL) % getpid());
495          key = ftok(filename, proj_id);          key = ftok(filename, proj_id);
496          if (key == -1)          if (key == -1)
# Line 491  int user_list_pool_init(const char *file Line 519  int user_list_pool_init(const char *file
519          }          }
520    
521          p_user_list_pool->semid = semid;          p_user_list_pool->semid = semid;
522    #endif
523    
524          // Set user counts to 0          // Set user counts to 0
525          p_user_list_pool->user_list[0].user_count = 0;          p_user_list_pool->user_list[0].user_count = 0;
# Line 507  int user_list_pool_init(const char *file Line 536  int user_list_pool_init(const char *file
536          return 0;          return 0;
537  }  }
538    
539  int user_list_pool_cleanup(void)  void user_list_pool_cleanup(void)
540  {  {
541          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
542          {          {
543                  return -1;                  return;
544          }          }
545    
546    #ifdef HAVE_SYSTEM_V
547          if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)          if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
548          {          {
549                  log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);                  log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
550          }          }
551    #else
552            if (sem_destroy(&(p_user_list_pool->sem)) == -1)
553            {
554                    log_error("sem_destroy() error (%d)\n", errno);
555            }
556    #endif
557    
558          detach_user_list_pool_shm();          detach_user_list_pool_shm();
559    
# Line 534  int user_list_pool_cleanup(void) Line 570  int user_list_pool_cleanup(void)
570    
571                  p_trie_action_dict = NULL;                  p_trie_action_dict = NULL;
572          }          }
   
         return 0;  
573  }  }
574    
575  int set_user_list_pool_shm_readonly(void)  int set_user_list_pool_shm_readonly(void)
# Line 647  cleanup: Line 681  cleanup:
681    
682  int user_list_try_rd_lock(int wait_sec)  int user_list_try_rd_lock(int wait_sec)
683  {  {
684    #ifdef HAVE_SYSTEM_V
685          struct sembuf sops[2];          struct sembuf sops[2];
 #ifndef __CYGWIN__  
         struct timespec timeout;  
686  #endif  #endif
687          int ret;          struct timespec timeout;
688            int ret = 0;
689    
690          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
691          {          {
# Line 659  int user_list_try_rd_lock(int wait_sec) Line 693  int user_list_try_rd_lock(int wait_sec)
693                  return -1;                  return -1;
694          }          }
695    
696            timeout.tv_sec = wait_sec;
697            timeout.tv_nsec = 0;
698    
699    #ifdef HAVE_SYSTEM_V
700          sops[0].sem_num = 1; // w_sem          sops[0].sem_num = 1; // w_sem
701          sops[0].sem_op = 0;      // wait until unlocked          sops[0].sem_op = 0;      // wait until unlocked
702          sops[0].sem_flg = 0;          sops[0].sem_flg = 0;
# Line 667  int user_list_try_rd_lock(int wait_sec) Line 705  int user_list_try_rd_lock(int wait_sec)
705          sops[1].sem_op = 1;                     // lock          sops[1].sem_op = 1;                     // lock
706          sops[1].sem_flg = SEM_UNDO; // undo on terminate          sops[1].sem_flg = SEM_UNDO; // undo on terminate
707    
 #ifdef __CYGWIN__  
         ret = semop(p_user_list_pool->semid, sops, 2);  
 #else  
         timeout.tv_sec = wait_sec;  
         timeout.tv_nsec = 0;  
   
708          ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);          ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);
 #endif  
709          if (ret == -1 && errno != EAGAIN && errno != EINTR)          if (ret == -1 && errno != EAGAIN && errno != EINTR)
710          {          {
711                  log_error("semop(lock read) error %d\n", errno);                  log_error("semop(lock read) error %d\n", errno);
712          }          }
713    #else
714            if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
715            {
716                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
717                    {
718                            log_error("sem_timedwait() error %d\n", errno);
719                    }
720                    return -1;
721            }
722    
723            if (p_user_list_pool->write_lock_count == 0)
724            {
725                    p_user_list_pool->read_lock_count++;
726            }
727            else
728            {
729                    errno = EAGAIN;
730                    ret = -1;
731            }
732    
733            if (sem_post(&(p_user_list_pool->sem)) == -1)
734            {
735                    log_error("sem_post() error %d\n", errno);
736                    return -1;
737            }
738    #endif
739    
740          return ret;          return ret;
741  }  }
742    
743  int user_list_try_rw_lock(int wait_sec)  int user_list_try_rw_lock(int wait_sec)
744  {  {
745    #ifdef HAVE_SYSTEM_V
746          struct sembuf sops[3];          struct sembuf sops[3];
 #ifndef __CYGWIN__  
         struct timespec timeout;  
747  #endif  #endif
748          int ret;          struct timespec timeout;
749            int ret = 0;
750    
751          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
752          {          {
# Line 697  int user_list_try_rw_lock(int wait_sec) Line 754  int user_list_try_rw_lock(int wait_sec)
754                  return -1;                  return -1;
755          }          }
756    
757            timeout.tv_sec = wait_sec;
758            timeout.tv_nsec = 0;
759    
760    #ifdef HAVE_SYSTEM_V
761          sops[0].sem_num = 1; // w_sem          sops[0].sem_num = 1; // w_sem
762          sops[0].sem_op = 0;      // wait until unlocked          sops[0].sem_op = 0;      // wait until unlocked
763          sops[0].sem_flg = 0;          sops[0].sem_flg = 0;
# Line 709  int user_list_try_rw_lock(int wait_sec) Line 770  int user_list_try_rw_lock(int wait_sec)
770          sops[2].sem_op = 0;      // wait until unlocked          sops[2].sem_op = 0;      // wait until unlocked
771          sops[2].sem_flg = 0;          sops[2].sem_flg = 0;
772    
 #ifdef __CYGWIN__  
         ret = semop(p_user_list_pool->semid, sops, 3);  
 #else  
         timeout.tv_sec = wait_sec;  
         timeout.tv_nsec = 0;  
   
773          ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);          ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);
 #endif  
774          if (ret == -1 && errno != EAGAIN && errno != EINTR)          if (ret == -1 && errno != EAGAIN && errno != EINTR)
775          {          {
776                  log_error("semop(lock write) error %d\n", errno);                  log_error("semop(lock write) error %d\n", errno);
777          }          }
778    #else
779            if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
780            {
781                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
782                    {
783                            log_error("sem_timedwait() error %d\n", errno);
784                    }
785                    return -1;
786            }
787    
788            if (p_user_list_pool->read_lock_count == 0 && p_user_list_pool->write_lock_count == 0)
789            {
790                    p_user_list_pool->write_lock_count++;
791            }
792            else
793            {
794                    errno = EAGAIN;
795                    ret = -1;
796            }
797    
798            if (sem_post(&(p_user_list_pool->sem)) == -1)
799            {
800                    log_error("sem_post() error %d\n", errno);
801                    return -1;
802            }
803    #endif
804    
805          return ret;          return ret;
806  }  }
807    
808  int user_list_rd_unlock(void)  int user_list_rd_unlock(void)
809  {  {
810    #ifdef HAVE_SYSTEM_V
811          struct sembuf sops[2];          struct sembuf sops[2];
812          int ret;  #endif
813            int ret = 0;
814    
815          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
816          {          {
# Line 736  int user_list_rd_unlock(void) Line 818  int user_list_rd_unlock(void)
818                  return -1;                  return -1;
819          }          }
820    
821    #ifdef HAVE_SYSTEM_V
822          sops[0].sem_num = 0;                                     // r_sem          sops[0].sem_num = 0;                                     // r_sem
823          sops[0].sem_op = -1;                                     // unlock          sops[0].sem_op = -1;                                     // unlock
824          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
# Line 745  int user_list_rd_unlock(void) Line 828  int user_list_rd_unlock(void)
828          {          {
829                  log_error("semop(unlock read) error %d\n", errno);                  log_error("semop(unlock read) error %d\n", errno);
830          }          }
831    #else
832            if (sem_wait(&(p_user_list_pool->sem)) == -1)
833            {
834                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
835                    {
836                            log_error("sem_wait() error %d\n", errno);
837                    }
838                    return -1;
839            }
840    
841            if (p_user_list_pool->read_lock_count > 0)
842            {
843                    p_user_list_pool->read_lock_count--;
844            }
845            else
846            {
847                    log_error("read_lock_count already 0\n");
848            }
849    
850            if (sem_post(&(p_user_list_pool->sem)) == -1)
851            {
852                    log_error("sem_post() error %d\n", errno);
853                    return -1;
854            }
855    #endif
856    
857          return ret;          return ret;
858  }  }
859    
860  int user_list_rw_unlock(void)  int user_list_rw_unlock(void)
861  {  {
862    #ifdef HAVE_SYSTEM_V
863          struct sembuf sops[1];          struct sembuf sops[1];
864          int ret;  #endif
865            int ret = 0;
866    
867          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
868          {          {
# Line 760  int user_list_rw_unlock(void) Line 870  int user_list_rw_unlock(void)
870                  return -1;                  return -1;
871          }          }
872    
873    #ifdef HAVE_SYSTEM_V
874          sops[0].sem_num = 1;                                     // w_sem          sops[0].sem_num = 1;                                     // w_sem
875          sops[0].sem_op = -1;                                     // unlock          sops[0].sem_op = -1;                                     // unlock
876          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
# Line 769  int user_list_rw_unlock(void) Line 880  int user_list_rw_unlock(void)
880          {          {
881                  log_error("semop(unlock write) error %d\n", errno);                  log_error("semop(unlock write) error %d\n", errno);
882          }          }
883    #else
884            if (sem_wait(&(p_user_list_pool->sem)) == -1)
885            {
886                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
887                    {
888                            log_error("sem_wait() error %d\n", errno);
889                    }
890                    return -1;
891            }
892    
893            if (p_user_list_pool->write_lock_count > 0)
894            {
895                    p_user_list_pool->write_lock_count--;
896            }
897            else
898            {
899                    log_error("write_lock_count already 0\n");
900            }
901    
902            if (sem_post(&(p_user_list_pool->sem)) == -1)
903            {
904                    log_error("sem_post() error %d\n", errno);
905                    return -1;
906            }
907    #endif
908    
909          return ret;          return ret;
910  }  }
# Line 777  int user_list_rd_lock(void) Line 913  int user_list_rd_lock(void)
913  {  {
914          int timer = 0;          int timer = 0;
915          int ret = -1;          int ret = -1;
916            time_t tm_first_failure = 0;
917    
918          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
919          {          {
# Line 797  int user_list_rd_lock(void) Line 934  int user_list_rd_lock(void)
934                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
935                          {                          {
936                                  log_error("user_list_try_rd_lock() tried %d times\n", timer);                                  log_error("user_list_try_rd_lock() tried %d times\n", timer);
937    
938                                    if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
939                                    {
940                                            log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
941    #ifndef HAVE_SYSTEM_V
942                                            user_list_reset_lock();
943                                            log_error("Reset POSIX semaphore to resolve dead lock\n");
944    #endif
945                                            break;
946                                    }
947                          }                          }
948                            usleep(100 * 1000); // 0.1 second
949                  }                  }
950                  else // failed                  else // failed
951                  {                  {
# Line 813  int user_list_rw_lock(void) Line 961  int user_list_rw_lock(void)
961  {  {
962          int timer = 0;          int timer = 0;
963          int ret = -1;          int ret = -1;
964            time_t tm_first_failure = 0;
965    
966          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
967          {          {
# Line 833  int user_list_rw_lock(void) Line 982  int user_list_rw_lock(void)
982                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
983                          {                          {
984                                  log_error("user_list_try_rw_lock() tried %d times\n", timer);                                  log_error("user_list_try_rw_lock() tried %d times\n", timer);
985    
986                                    if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
987                                    {
988                                            log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
989    #ifndef HAVE_SYSTEM_V
990                                            user_list_reset_lock();
991                                            log_error("Reset POSIX semaphore to resolve dead lock\n");
992    #endif
993                                            break;
994                                    }
995                          }                          }
996                            usleep(100 * 1000); // 0.1 second
997                  }                  }
998                  else // failed                  else // failed
999                  {                  {
# Line 845  int user_list_rw_lock(void) Line 1005  int user_list_rw_lock(void)
1005          return ret;          return ret;
1006  }  }
1007    
1008    #ifndef HAVE_SYSTEM_V
1009    int user_list_reset_lock(void)
1010    {
1011            if (p_user_list_pool == NULL)
1012            {
1013                    log_error("p_user_list_pool not initialized\n");
1014                    return -1;
1015            }
1016    
1017            if (sem_destroy(&(p_user_list_pool->sem)) == -1)
1018            {
1019                    log_error("sem_destroy() error (%d)\n", errno);
1020            }
1021    
1022            p_user_list_pool->read_lock_count = 0;
1023            p_user_list_pool->write_lock_count = 0;
1024    
1025            if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
1026            {
1027                    log_error("sem_init() error (%d)\n", errno);
1028            }
1029    
1030            return 0;
1031    }
1032    #endif
1033    
1034  int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)  int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
1035  {  {
1036          int ret = 0;          int ret = 0;


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1