/[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.39 by sysadm, Thu Nov 20 01:54:18 2025 UTC Revision 1.45 by sysadm, Wed Dec 3 05:31:11 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 78  const USER_ACTION_MAP user_action_map[] Line 91  const USER_ACTION_MAP user_action_map[]
91                  {"MENU", "菜单选择"},                  {"MENU", "菜单选择"},
92                  {"POST_ARTICLE", "撰写文章"},                  {"POST_ARTICLE", "撰写文章"},
93                  {"REPLY_ARTICLE", "回复文章"},                  {"REPLY_ARTICLE", "回复文章"},
94                    {"TOP10_MENU", "十大热门"},
95                  {"USER_LIST", "查花名册"},                  {"USER_LIST", "查花名册"},
96                  {"USER_ONLINE", "环顾四周"},                  {"USER_ONLINE", "环顾四周"},
97                  {"VIEW_ARTICLE", "阅读文章"},                  {"VIEW_ARTICLE", "阅读文章"},
# Line 92  static int user_list_rd_unlock(void); Line 106  static int user_list_rd_unlock(void);
106  static int user_list_rw_unlock(void);  static int user_list_rw_unlock(void);
107  static int user_list_rd_lock(void);  static int user_list_rd_lock(void);
108  static int user_list_rw_lock(void);  static int user_list_rw_lock(void);
109    #ifndef HAVE_SYSTEM_V
110    static int user_list_reset_lock(void);
111    #endif
112    
113  static int user_list_load(MYSQL *db, USER_LIST *p_list);  static int user_list_load(MYSQL *db, USER_LIST *p_list);
114  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 410  int user_list_pool_init(const char *file
410          int fd;          int fd;
411          size_t size;          size_t size;
412          void *p_shm;          void *p_shm;
413    #ifdef HAVE_SYSTEM_V
414          int proj_id;          int proj_id;
415          key_t key;          key_t key;
416          int semid;          int semid;
417          union semun arg;          union semun arg;
418    #endif
419          int i;          int i;
420    
421          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 482  int user_list_pool_init(const char *file
482          p_user_list_pool->shm_size = size;          p_user_list_pool->shm_size = size;
483    
484          // Allocate semaphore as user list pool lock          // Allocate semaphore as user list pool lock
485    #ifndef HAVE_SYSTEM_V
486            if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
487            {
488                    log_error("sem_init() error (%d)\n", errno);
489                    return -3;
490            }
491    
492            p_user_list_pool->read_lock_count = 0;
493            p_user_list_pool->write_lock_count = 0;
494    #else
495          proj_id = (int)(time(NULL) % getpid());          proj_id = (int)(time(NULL) % getpid());
496          key = ftok(filename, proj_id);          key = ftok(filename, proj_id);
497          if (key == -1)          if (key == -1)
# Line 491  int user_list_pool_init(const char *file Line 520  int user_list_pool_init(const char *file
520          }          }
521    
522          p_user_list_pool->semid = semid;          p_user_list_pool->semid = semid;
523    #endif
524    
525          // Set user counts to 0          // Set user counts to 0
526          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 537  int user_list_pool_init(const char *file
537          return 0;          return 0;
538  }  }
539    
540  int user_list_pool_cleanup(void)  void user_list_pool_cleanup(void)
541  {  {
542          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
543          {          {
544                  return -1;                  return;
545          }          }
546    
547    #ifdef HAVE_SYSTEM_V
548            if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
549            {
550                    log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
551            }
552    #else
553            if (sem_destroy(&(p_user_list_pool->sem)) == -1)
554            {
555                    log_error("sem_destroy() error (%d)\n", errno);
556            }
557    #endif
558    
559          detach_user_list_pool_shm();          detach_user_list_pool_shm();
560    
561          if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)          if (shm_unlink(user_list_shm_name) == -1 && errno != ENOENT)
562          {          {
563                  log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);                  log_error("shm_unlink(%s) error (%d)\n", user_list_shm_name, errno);
                 return -2;  
564          }          }
565    
566          user_list_shm_name[0] = '\0';          user_list_shm_name[0] = '\0';
# Line 530  int user_list_pool_cleanup(void) Line 571  int user_list_pool_cleanup(void)
571    
572                  p_trie_action_dict = NULL;                  p_trie_action_dict = NULL;
573          }          }
   
         return 0;  
574  }  }
575    
576  int set_user_list_pool_shm_readonly(void)  int set_user_list_pool_shm_readonly(void)
# Line 643  cleanup: Line 682  cleanup:
682    
683  int user_list_try_rd_lock(int wait_sec)  int user_list_try_rd_lock(int wait_sec)
684  {  {
685    #ifdef HAVE_SYSTEM_V
686          struct sembuf sops[2];          struct sembuf sops[2];
 #ifndef __CYGWIN__  
         struct timespec timeout;  
687  #endif  #endif
688          int ret;          struct timespec timeout;
689            int ret = 0;
690    
691          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
692          {          {
# Line 655  int user_list_try_rd_lock(int wait_sec) Line 694  int user_list_try_rd_lock(int wait_sec)
694                  return -1;                  return -1;
695          }          }
696    
697            timeout.tv_sec = wait_sec;
698            timeout.tv_nsec = 0;
699    
700    #ifdef HAVE_SYSTEM_V
701          sops[0].sem_num = 1; // w_sem          sops[0].sem_num = 1; // w_sem
702          sops[0].sem_op = 0;      // wait until unlocked          sops[0].sem_op = 0;      // wait until unlocked
703          sops[0].sem_flg = 0;          sops[0].sem_flg = 0;
# Line 663  int user_list_try_rd_lock(int wait_sec) Line 706  int user_list_try_rd_lock(int wait_sec)
706          sops[1].sem_op = 1;                     // lock          sops[1].sem_op = 1;                     // lock
707          sops[1].sem_flg = SEM_UNDO; // undo on terminate          sops[1].sem_flg = SEM_UNDO; // undo on terminate
708    
 #ifdef __CYGWIN__  
         ret = semop(p_user_list_pool->semid, sops, 2);  
 #else  
         timeout.tv_sec = wait_sec;  
         timeout.tv_nsec = 0;  
   
709          ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);          ret = semtimedop(p_user_list_pool->semid, sops, 2, &timeout);
 #endif  
710          if (ret == -1 && errno != EAGAIN && errno != EINTR)          if (ret == -1 && errno != EAGAIN && errno != EINTR)
711          {          {
712                  log_error("semop(lock read) error %d\n", errno);                  log_error("semop(lock read) error %d\n", errno);
713          }          }
714    #else
715            if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
716            {
717                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
718                    {
719                            log_error("sem_timedwait() error %d\n", errno);
720                    }
721                    return -1;
722            }
723    
724            if (p_user_list_pool->write_lock_count == 0)
725            {
726                    p_user_list_pool->read_lock_count++;
727            }
728            else
729            {
730                    errno = EAGAIN;
731                    ret = -1;
732            }
733    
734            if (sem_post(&(p_user_list_pool->sem)) == -1)
735            {
736                    log_error("sem_post() error %d\n", errno);
737                    return -1;
738            }
739    #endif
740    
741          return ret;          return ret;
742  }  }
743    
744  int user_list_try_rw_lock(int wait_sec)  int user_list_try_rw_lock(int wait_sec)
745  {  {
746    #ifdef HAVE_SYSTEM_V
747          struct sembuf sops[3];          struct sembuf sops[3];
 #ifndef __CYGWIN__  
         struct timespec timeout;  
748  #endif  #endif
749          int ret;          struct timespec timeout;
750            int ret = 0;
751    
752          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
753          {          {
# Line 693  int user_list_try_rw_lock(int wait_sec) Line 755  int user_list_try_rw_lock(int wait_sec)
755                  return -1;                  return -1;
756          }          }
757    
758            timeout.tv_sec = wait_sec;
759            timeout.tv_nsec = 0;
760    
761    #ifdef HAVE_SYSTEM_V
762          sops[0].sem_num = 1; // w_sem          sops[0].sem_num = 1; // w_sem
763          sops[0].sem_op = 0;      // wait until unlocked          sops[0].sem_op = 0;      // wait until unlocked
764          sops[0].sem_flg = 0;          sops[0].sem_flg = 0;
# Line 705  int user_list_try_rw_lock(int wait_sec) Line 771  int user_list_try_rw_lock(int wait_sec)
771          sops[2].sem_op = 0;      // wait until unlocked          sops[2].sem_op = 0;      // wait until unlocked
772          sops[2].sem_flg = 0;          sops[2].sem_flg = 0;
773    
 #ifdef __CYGWIN__  
         ret = semop(p_user_list_pool->semid, sops, 3);  
 #else  
         timeout.tv_sec = wait_sec;  
         timeout.tv_nsec = 0;  
   
774          ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);          ret = semtimedop(p_user_list_pool->semid, sops, 3, &timeout);
 #endif  
775          if (ret == -1 && errno != EAGAIN && errno != EINTR)          if (ret == -1 && errno != EAGAIN && errno != EINTR)
776          {          {
777                  log_error("semop(lock write) error %d\n", errno);                  log_error("semop(lock write) error %d\n", errno);
778          }          }
779    #else
780            if (sem_timedwait(&(p_user_list_pool->sem), &timeout) == -1)
781            {
782                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
783                    {
784                            log_error("sem_timedwait() error %d\n", errno);
785                    }
786                    return -1;
787            }
788    
789            if (p_user_list_pool->read_lock_count == 0 && p_user_list_pool->write_lock_count == 0)
790            {
791                    p_user_list_pool->write_lock_count++;
792            }
793            else
794            {
795                    errno = EAGAIN;
796                    ret = -1;
797            }
798    
799            if (sem_post(&(p_user_list_pool->sem)) == -1)
800            {
801                    log_error("sem_post() error %d\n", errno);
802                    return -1;
803            }
804    #endif
805    
806          return ret;          return ret;
807  }  }
808    
809  int user_list_rd_unlock(void)  int user_list_rd_unlock(void)
810  {  {
811    #ifdef HAVE_SYSTEM_V
812          struct sembuf sops[2];          struct sembuf sops[2];
813          int ret;  #endif
814            int ret = 0;
815    
816          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
817          {          {
# Line 732  int user_list_rd_unlock(void) Line 819  int user_list_rd_unlock(void)
819                  return -1;                  return -1;
820          }          }
821    
822    #ifdef HAVE_SYSTEM_V
823          sops[0].sem_num = 0;                                     // r_sem          sops[0].sem_num = 0;                                     // r_sem
824          sops[0].sem_op = -1;                                     // unlock          sops[0].sem_op = -1;                                     // unlock
825          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
# Line 741  int user_list_rd_unlock(void) Line 829  int user_list_rd_unlock(void)
829          {          {
830                  log_error("semop(unlock read) error %d\n", errno);                  log_error("semop(unlock read) error %d\n", errno);
831          }          }
832    #else
833            if (sem_wait(&(p_user_list_pool->sem)) == -1)
834            {
835                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
836                    {
837                            log_error("sem_wait() error %d\n", errno);
838                    }
839                    return -1;
840            }
841    
842            if (p_user_list_pool->read_lock_count > 0)
843            {
844                    p_user_list_pool->read_lock_count--;
845            }
846            else
847            {
848                    log_error("read_lock_count already 0\n");
849            }
850    
851            if (sem_post(&(p_user_list_pool->sem)) == -1)
852            {
853                    log_error("sem_post() error %d\n", errno);
854                    return -1;
855            }
856    #endif
857    
858          return ret;          return ret;
859  }  }
860    
861  int user_list_rw_unlock(void)  int user_list_rw_unlock(void)
862  {  {
863    #ifdef HAVE_SYSTEM_V
864          struct sembuf sops[1];          struct sembuf sops[1];
865          int ret;  #endif
866            int ret = 0;
867    
868          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
869          {          {
# Line 756  int user_list_rw_unlock(void) Line 871  int user_list_rw_unlock(void)
871                  return -1;                  return -1;
872          }          }
873    
874    #ifdef HAVE_SYSTEM_V
875          sops[0].sem_num = 1;                                     // w_sem          sops[0].sem_num = 1;                                     // w_sem
876          sops[0].sem_op = -1;                                     // unlock          sops[0].sem_op = -1;                                     // unlock
877          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait          sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
# Line 765  int user_list_rw_unlock(void) Line 881  int user_list_rw_unlock(void)
881          {          {
882                  log_error("semop(unlock write) error %d\n", errno);                  log_error("semop(unlock write) error %d\n", errno);
883          }          }
884    #else
885            if (sem_wait(&(p_user_list_pool->sem)) == -1)
886            {
887                    if (errno != ETIMEDOUT && errno != EAGAIN && errno != EINTR)
888                    {
889                            log_error("sem_wait() error %d\n", errno);
890                    }
891                    return -1;
892            }
893    
894            if (p_user_list_pool->write_lock_count > 0)
895            {
896                    p_user_list_pool->write_lock_count--;
897            }
898            else
899            {
900                    log_error("write_lock_count already 0\n");
901            }
902    
903            if (sem_post(&(p_user_list_pool->sem)) == -1)
904            {
905                    log_error("sem_post() error %d\n", errno);
906                    return -1;
907            }
908    #endif
909    
910          return ret;          return ret;
911  }  }
# Line 773  int user_list_rd_lock(void) Line 914  int user_list_rd_lock(void)
914  {  {
915          int timer = 0;          int timer = 0;
916          int ret = -1;          int ret = -1;
917            time_t tm_first_failure = 0;
918    
919          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
920          {          {
# Line 793  int user_list_rd_lock(void) Line 935  int user_list_rd_lock(void)
935                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
936                          {                          {
937                                  log_error("user_list_try_rd_lock() tried %d times\n", timer);                                  log_error("user_list_try_rd_lock() tried %d times\n", timer);
938    
939                                    if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
940                                    {
941                                            log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
942    #ifndef HAVE_SYSTEM_V
943                                            user_list_reset_lock();
944                                            log_error("Reset POSIX semaphore to resolve dead lock\n");
945    #endif
946                                            break;
947                                    }
948                          }                          }
949                            usleep(100 * 1000); // 0.1 second
950                  }                  }
951                  else // failed                  else // failed
952                  {                  {
# Line 809  int user_list_rw_lock(void) Line 962  int user_list_rw_lock(void)
962  {  {
963          int timer = 0;          int timer = 0;
964          int ret = -1;          int ret = -1;
965            time_t tm_first_failure = 0;
966    
967          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
968          {          {
# Line 829  int user_list_rw_lock(void) Line 983  int user_list_rw_lock(void)
983                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)                          if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
984                          {                          {
985                                  log_error("user_list_try_rw_lock() tried %d times\n", timer);                                  log_error("user_list_try_rw_lock() tried %d times\n", timer);
986    
987                                    if (time(NULL) - tm_first_failure >= USER_LIST_DEAD_LOCK_TIMEOUT)
988                                    {
989                                            log_error("Unable to acquire rw_lock for %d seconds\n", time(NULL) - tm_first_failure);
990    #ifndef HAVE_SYSTEM_V
991                                            user_list_reset_lock();
992                                            log_error("Reset POSIX semaphore to resolve dead lock\n");
993    #endif
994                                            break;
995                                    }
996                          }                          }
997                            usleep(100 * 1000); // 0.1 second
998                  }                  }
999                  else // failed                  else // failed
1000                  {                  {
# Line 841  int user_list_rw_lock(void) Line 1006  int user_list_rw_lock(void)
1006          return ret;          return ret;
1007  }  }
1008    
1009    #ifndef HAVE_SYSTEM_V
1010    int user_list_reset_lock(void)
1011    {
1012            if (p_user_list_pool == NULL)
1013            {
1014                    log_error("p_user_list_pool not initialized\n");
1015                    return -1;
1016            }
1017    
1018            if (sem_destroy(&(p_user_list_pool->sem)) == -1)
1019            {
1020                    log_error("sem_destroy() error (%d)\n", errno);
1021            }
1022    
1023            p_user_list_pool->read_lock_count = 0;
1024            p_user_list_pool->write_lock_count = 0;
1025    
1026            if (sem_init(&(p_user_list_pool->sem), 1, 1) == -1)
1027            {
1028                    log_error("sem_init() error (%d)\n", errno);
1029            }
1030    
1031            return 0;
1032    }
1033    #endif
1034    
1035  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)
1036  {  {
1037          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