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

Diff of /lbbs/src/section_list.c

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

Revision 1.4 by sysadm, Wed May 21 09:09:30 2025 UTC Revision 1.59 by sysadm, Mon Nov 17 12:16:48 2025 UTC
# Line 1  Line 1 
1  /***************************************************************************  /* SPDX-License-Identifier: GPL-3.0-or-later */
2                                             section_list.c  -  description  /*
3                                                           -------------------   * section_list
4          Copyright            : (C) 2004-2025 by Leaflet   *   - data models and basic operations of section and article
5          Email                : leaflet@leafok.com   *
6   ***************************************************************************/   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7     */
8  /***************************************************************************  
9   *                                                                         *  #ifdef HAVE_CONFIG_H
10   *   This program is free software; you can redistribute it and/or modify  *  #include "config.h"
11   *   it under the terms of the GNU General Public License as published by  *  #endif
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
12    
 #include "section_list.h"  
13  #include "log.h"  #include "log.h"
14    #include "section_list.h"
15  #include "trie_dict.h"  #include "trie_dict.h"
16    #include "user_list.h"
17    #include <errno.h>
18    #include <signal.h>
19  #include <stdio.h>  #include <stdio.h>
20    #include <stdlib.h>
21  #include <string.h>  #include <string.h>
 #include <signal.h>  
22  #include <unistd.h>  #include <unistd.h>
 #include <stdlib.h>  
 #include <errno.h>  
 #include <sys/shm.h>  
23  #include <sys/ipc.h>  #include <sys/ipc.h>
24    #include <sys/param.h>
25    #include <sys/sem.h>
26    #include <sys/shm.h>
27    
28  // ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT should be  #if defined(_SEM_SEMUN_UNDEFINED) || defined(__MSYS__) || defined(__MINGW32__)
29  // no less than BBS_article_block_limit_per_section * BBS_max_section,  union semun
30  // in order to allocate enough memory for blocks  {
31  #define ARTICLE_BLOCK_PER_SHM 400 // sizeof(ARTICLE_BLOCK) * ARTICLE_BLOCK_PER_SHM is the size of each shm segment to allocate          int val;                           /* Value for SETVAL */
32  #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 256 // limited by length (8-bit) of proj_id in ftok(path, proj_id)          struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
33            unsigned short *array; /* Array for GETALL, SETALL */
34            struct seminfo *__buf; /* Buffer for IPC_INFO
35                                                              (Linux-specific) */
36    };
37    #endif // #if defined(_SEM_SEMUN_UNDEFINED)
38    
39  struct article_block_shm_t  enum _section_list_constant_t
40    {
41            SECTION_TRY_LOCK_WAIT_TIME = 1, // second
42            SECTION_TRY_LOCK_TIMES = 10,
43    
44            ARTICLE_BLOCK_PER_SHM = 1000,           // sizeof(ARTICLE_BLOCK) * ARTICLE_BLOCK_PER_SHM is the size of each shm segment to allocate
45            ARTICLE_BLOCK_SHM_COUNT_LIMIT = 80, // limited by length (8-bit) of proj_id in ftok(path, proj_id)
46            ARTICLE_BLOCK_PER_POOL = (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT),
47    
48            CALCULATE_PAGE_THRESHOLD = 100, // Adjust to tune performance of moving topic between sections
49    
50            SID_STR_LEN = 5, // 32-bit + NULL
51    };
52    
53    struct article_block_t
54    {
55            ARTICLE articles[BBS_article_count_per_block];
56            int article_count;
57            struct article_block_t *p_next_block;
58    };
59    typedef struct article_block_t ARTICLE_BLOCK;
60    
61    struct article_block_pool_t
62  {  {
63          int shmid;          int shmid;
64          void *p_shm;          struct
65            {
66                    int shmid;
67                    void *p_shm;
68            } shm_pool[ARTICLE_BLOCK_SHM_COUNT_LIMIT];
69            int shm_count;
70            ARTICLE_BLOCK *p_block_free_list;
71            ARTICLE_BLOCK *p_block[ARTICLE_BLOCK_PER_POOL];
72            int block_count;
73  };  };
74  typedef struct article_block_shm_t ARTICLE_BLOCK_SHM;  typedef struct article_block_pool_t ARTICLE_BLOCK_POOL;
75    
76  static ARTICLE_BLOCK_SHM *p_article_block_shm_pool;  static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;
 static int article_block_shm_count;  
 static ARTICLE_BLOCK *p_article_block_free_list;  
77    
78  static SECTION_DATA *p_section_data_pool;  SECTION_LIST_POOL *p_section_list_pool = NULL;
 static int section_data_count;  
 static TRIE_NODE *p_trie_dict_section_data;  
79    
80  int section_data_pool_init(const char *filename, int article_block_count)  int article_block_init(const char *filename, int block_count)
81  {  {
82          int shmid;          int shmid;
83          int proj_id;          int proj_id;
# Line 55  int section_data_pool_init(const char *f Line 85  int section_data_pool_init(const char *f
85          size_t size;          size_t size;
86          void *p_shm;          void *p_shm;
87          int i;          int i;
88          int article_block_count_in_shm;          int block_count_in_shm;
89          ARTICLE_BLOCK *p_article_block_in_shm;          ARTICLE_BLOCK *p_block_in_shm;
90          ARTICLE_BLOCK **pp_article_block_next;          ARTICLE_BLOCK **pp_block_next;
91    
92          if (p_article_block_shm_pool != NULL ||          if (p_article_block_pool != NULL)
                 p_article_block_free_list != NULL ||  
                 p_section_data_pool != NULL ||  
                 p_trie_dict_section_data != NULL)  
93          {          {
94                  log_error("section_data_pool already initialized\n");                  log_error("article_block_pool already initialized\n");
95                  return -1;                  return -1;
96          }          }
97    
98          if (article_block_count > ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)          if (block_count <= 0 || block_count > ARTICLE_BLOCK_PER_POOL)
99          {          {
100                  log_error("article_block_count exceed limit %d\n", ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT);                  log_error("article_block_count exceed limit %d\n", ARTICLE_BLOCK_PER_POOL);
101                  return -2;                  return -2;
102          }          }
103    
104          p_article_block_shm_pool = calloc((size_t)article_block_count / ARTICLE_BLOCK_PER_SHM + 1, sizeof(ARTICLE_BLOCK_SHM));          // Allocate shared memory
105          if (p_article_block_shm_pool == NULL)          proj_id = ARTICLE_BLOCK_SHM_COUNT_LIMIT; // keep different from proj_id used to create block shm
106            key = ftok(filename, proj_id);
107            if (key == -1)
108          {          {
109                  log_error("calloc(%d ARTICLE_BLOCK_SHM) OOM\n", article_block_count / ARTICLE_BLOCK_PER_SHM + 1);                  log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
110                  return -2;                  return -3;
111          }          }
112    
113          p_section_data_pool = calloc(BBS_max_section, sizeof(SECTION_DATA));          size = sizeof(ARTICLE_BLOCK_POOL);
114          if (p_section_data_pool == NULL)          shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
115            if (shmid == -1)
116          {          {
117                  log_error("calloc(%d SECTION_DATA) OOM\n", BBS_max_section);                  log_error("shmget(article_block_pool_shm, size = %d) error (%d)\n", size, errno);
118                  return -2;                  return -3;
119          }          }
120          section_data_count = 0;          p_shm = shmat(shmid, NULL, 0);
121            if (p_shm == (void *)-1)
         p_trie_dict_section_data = trie_dict_create();  
         if (p_trie_dict_section_data == NULL)  
122          {          {
123                  log_error("trie_dict_create() OOM\n", BBS_max_section);                  log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
124                  return -2;                  return -3;
125          }          }
126    
127          // Allocate shared memory          p_article_block_pool = p_shm;
128          article_block_shm_count = 0;          p_article_block_pool->shmid = shmid;
129          pp_article_block_next = &p_article_block_free_list;  
130            p_article_block_pool->shm_count = 0;
131            pp_block_next = &(p_article_block_pool->p_block_free_list);
132    
133          while (article_block_count > 0)          while (block_count > 0)
134          {          {
135                  article_block_count_in_shm =                  block_count_in_shm = MIN(block_count, ARTICLE_BLOCK_PER_SHM);
136                          (article_block_count < ARTICLE_BLOCK_PER_SHM ? article_block_count : ARTICLE_BLOCK_PER_SHM);                  block_count -= block_count_in_shm;
                 article_block_count -= article_block_count_in_shm;  
137    
138                  proj_id = getpid() + article_block_shm_count;                  proj_id = p_article_block_pool->shm_count;
139                  key = ftok(filename, proj_id);                  key = ftok(filename, proj_id);
140                  if (key == -1)                  if (key == -1)
141                  {                  {
142                          log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);                          log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
143                          section_data_pool_cleanup();                          article_block_cleanup();
144                          return -3;                          return -3;
145                  }                  }
146    
147                  size = sizeof(shmid) + sizeof(ARTICLE_BLOCK) * (size_t)article_block_count_in_shm;                  size = sizeof(ARTICLE_BLOCK) * (size_t)block_count_in_shm;
148                  shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);                  shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
149                  if (shmid == -1)                  if (shmid == -1)
150                  {                  {
151                          log_error("shmget(shm_index = %d, size = %d) error (%d)\n", article_block_shm_count, size, errno);                          log_error("shmget(shm_index = %d, size = %d) error (%d)\n", p_article_block_pool->shm_count, size, errno);
152                          section_data_pool_cleanup();                          article_block_cleanup();
153                          return -3;                          return -3;
154                  }                  }
155                  p_shm = shmat(shmid, NULL, 0);                  p_shm = shmat(shmid, NULL, 0);
156                  if (p_shm == (void *)-1)                  if (p_shm == (void *)-1)
157                  {                  {
158                          log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);                          log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
159                          section_data_pool_cleanup();                          article_block_cleanup();
160                          return -3;                          return -3;
161                  }                  }
162    
163                  (p_article_block_shm_pool + article_block_shm_count)->shmid = shmid;                  (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->shmid = shmid;
164                  (p_article_block_shm_pool + article_block_shm_count)->p_shm = p_shm;                  (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->p_shm = p_shm;
165                  article_block_shm_count++;                  p_article_block_pool->shm_count++;
166    
167                  p_article_block_in_shm = p_shm;                  p_block_in_shm = p_shm;
168                  *pp_article_block_next = p_article_block_in_shm;                  *pp_block_next = p_block_in_shm;
169    
170                  for (i = 0; i < article_block_count_in_shm; i++)                  for (i = 0; i < block_count_in_shm; i++)
171                  {                  {
172                          if (i < article_block_count_in_shm - 1)                          if (i < block_count_in_shm - 1)
173                          {                          {
174                                  (p_article_block_in_shm + i)->p_next_block = (p_article_block_in_shm + i + 1);                                  (p_block_in_shm + i)->p_next_block = (p_block_in_shm + i + 1);
175                          }                          }
176                          else                          else
177                          {                          {
178                                  (p_article_block_in_shm + i)->p_next_block = NULL;                                  (p_block_in_shm + i)->p_next_block = NULL;
179                                  pp_article_block_next = &((p_article_block_in_shm + i)->p_next_block);                                  pp_block_next = &((p_block_in_shm + i)->p_next_block);
180                          }                          }
181                  }                  }
182          }          }
183    
184            p_article_block_pool->block_count = 0;
185    
186          return 0;          return 0;
187  }  }
188    
189  void section_data_pool_cleanup(void)  void article_block_cleanup(void)
190  {  {
191          int i;          int shmid;
192    
193          if (p_trie_dict_section_data != NULL)          if (p_article_block_pool == NULL)
194          {          {
195                  trie_dict_destroy(p_trie_dict_section_data);                  return;
                 p_trie_dict_section_data = NULL;  
                 section_data_count = 0;  
196          }          }
197    
198          if (p_section_data_pool != NULL)          for (int i = 0; i < p_article_block_pool->shm_count; i++)
199          {          {
200                  free(p_section_data_pool);                  if (shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
201                  p_section_data_pool = NULL;                  {
202                            log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
203                    }
204    
205                    if (shmctl((p_article_block_pool->shm_pool + i)->shmid, IPC_RMID, NULL) == -1)
206                    {
207                            log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
208                    }
209          }          }
210    
211          if (p_article_block_free_list != NULL)          shmid = p_article_block_pool->shmid;
212    
213            if (shmdt(p_article_block_pool) == -1)
214          {          {
215                  p_article_block_free_list = NULL;                  log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
216          }          }
217    
218          if (p_article_block_shm_pool != NULL)          if (shmid != 0 && shmctl(shmid, IPC_RMID, NULL) == -1)
219          {          {
220                  for (i = 0; i < article_block_shm_count; i++)                  log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
221            }
222    
223            p_article_block_pool = NULL;
224    }
225    
226    int set_article_block_shm_readonly(void)
227    {
228            int shmid;
229            void *p_shm;
230            int i;
231    
232            if (p_article_block_pool == NULL)
233            {
234                    log_error("article_block_pool not initialized\n");
235                    return -1;
236            }
237    
238            for (i = 0; i < p_article_block_pool->shm_count; i++)
239            {
240                    shmid = (p_article_block_pool->shm_pool + i)->shmid;
241    
242                    // Remap shared memory in read-only mode
243    #if defined(__MSYS__) || defined(__MINGW32__)
244                    if (shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
245                  {                  {
246                          if (shmdt((p_article_block_shm_pool + i)->p_shm) == -1)                          log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
247                          {                          return -2;
248                                  log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_shm_pool + i)->shmid, errno);                  }
249                          }                  p_shm = shmat(shmid, (p_article_block_pool->shm_pool + i)->p_shm, SHM_RDONLY);
250    #else
251                    p_shm = shmat(shmid, (p_article_block_pool->shm_pool + i)->p_shm, SHM_RDONLY | SHM_REMAP);
252    #endif
253                    if (p_shm == (void *)-1)
254                    {
255                            log_error("shmat(article_block_pool shmid = %d) error (%d)\n", shmid, errno);
256                            return -2;
257                    }
258            }
259    
260                          if (shmctl((p_article_block_shm_pool + i)->shmid, IPC_RMID, NULL) == -1)          return 0;
261                          {  }
262                                  log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", (p_article_block_shm_pool + i)->shmid, errno);  
263                          }  int detach_article_block_shm(void)
264    {
265            int shmid;
266    
267            if (p_article_block_pool == NULL)
268            {
269                    return -1;
270            }
271    
272            for (int i = 0; i < p_article_block_pool->shm_count; i++)
273            {
274                    if ((p_article_block_pool->shm_pool + i)->p_shm != NULL && shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
275                    {
276                            log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
277                            return -2;
278                  }                  }
279            }
280    
281            shmid = p_article_block_pool->shmid;
282    
283                  p_article_block_shm_pool = NULL;          if (shmdt(p_article_block_pool) == -1)
284                  article_block_shm_count = 0;          {
285                    log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
286                    return -3;
287          }          }
288    
289            p_article_block_pool = NULL;
290    
291            return 0;
292  }  }
293    
294  inline static ARTICLE_BLOCK *pop_free_article_block(void)  inline static ARTICLE_BLOCK *pop_free_article_block(void)
295  {  {
296          ARTICLE_BLOCK *p_article_block = NULL;          ARTICLE_BLOCK *p_block = NULL;
297    
298          if (p_article_block_free_list != NULL)          if (p_article_block_pool->p_block_free_list != NULL)
299          {          {
300                  p_article_block = p_article_block_free_list;                  p_block = p_article_block_pool->p_block_free_list;
301                  p_article_block_free_list = p_article_block_free_list->p_next_block;                  p_article_block_pool->p_block_free_list = p_block->p_next_block;
302                    p_block->p_next_block = NULL;
303                    p_block->article_count = 0;
304          }          }
305    
306          return p_article_block;          return p_block;
307  }  }
308    
309  inline static void push_free_article_block(ARTICLE_BLOCK *p_article_block)  inline static void push_free_article_block(ARTICLE_BLOCK *p_block)
310  {  {
311          p_article_block->p_next_block = p_article_block_free_list;          p_block->p_next_block = p_article_block_pool->p_block_free_list;
312          p_article_block_free_list = p_article_block;          p_article_block_pool->p_block_free_list = p_block;
313  }  }
314    
315  SECTION_DATA *section_data_create(const char *sname, const char *stitle, const char *master_name)  int article_block_reset(void)
316  {  {
317          SECTION_DATA *p_section;          ARTICLE_BLOCK *p_block;
         int index;  
318    
319          if (p_section_data_pool == NULL || p_trie_dict_section_data == NULL)          if (p_article_block_pool == NULL)
320          {          {
321                  log_error("section_data not initialized\n");                  log_error("article_block_pool not initialized\n");
322                    return -1;
323            }
324    
325            while (p_article_block_pool->block_count > 0)
326            {
327                    p_article_block_pool->block_count--;
328                    p_block = p_article_block_pool->p_block[p_article_block_pool->block_count];
329                    push_free_article_block(p_block);
330            }
331    
332            return 0;
333    }
334    
335    ARTICLE *article_block_find_by_aid(int32_t aid)
336    {
337            ARTICLE_BLOCK *p_block;
338            int left;
339            int right;
340            int mid;
341    
342            if (p_article_block_pool == NULL)
343            {
344                    log_error("article_block_pool not initialized\n");
345                  return NULL;                  return NULL;
346          }          }
347    
348          if (section_data_count >= BBS_max_section)          if (p_article_block_pool->block_count == 0) // empty
349          {          {
                 log_error("section_data_count exceed limit %d\n", BBS_max_section);  
350                  return NULL;                  return NULL;
351          }          }
352    
353          index = section_data_count;          left = 0;
354          p_section = p_section_data_pool + index;          right = p_article_block_pool->block_count - 1;
355    
356          strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));          // aid in the range [ head aid of blocks[left], tail aid of blocks[right] ]
357          p_section->sname[sizeof(p_section->sname - 1)] = '\0';          while (left < right)
358            {
359                    // get block offset no less than mid value of left and right block offsets
360                    mid = (left + right) / 2 + (left + right) % 2;
361    
362          strncpy(p_section->stitle, stitle, sizeof(p_section->stitle - 1));                  if (aid < p_article_block_pool->p_block[mid]->articles[0].aid)
363          p_section->stitle[sizeof(p_section->stitle - 1)] = '\0';                  {
364                            right = mid - 1;
365                    }
366                    else // if (aid >= p_article_block_pool->p_block[mid]->articles[0].aid)
367                    {
368                            left = mid;
369                    }
370            }
371    
372          strncpy(p_section->master_name, master_name, sizeof(p_section->master_name - 1));          p_block = p_article_block_pool->p_block[left];
         p_section->master_name[sizeof(p_section->master_name - 1)] = '\0';  
373    
374          p_section->p_head_block = NULL;          left = 0;
375          p_section->p_tail_block = NULL;          right = p_block->article_count - 1;
         p_section->block_count = 0;  
         p_section->article_count = 0;  
         p_section->delete_count = 0;  
376    
377          if (trie_dict_set(p_trie_dict_section_data, sname, index) != 1)          // aid in the range [ aid of articles[left], aid of articles[right] ]
378            while (left < right)
379          {          {
380                  log_error("trie_dict_set(section_data, %s, %d) error\n", sname, index);                  mid = (left + right) / 2;
381                  return NULL;  
382                    if (aid <= p_block->articles[mid].aid)
383                    {
384                            right = mid;
385                    }
386                    else
387                    {
388                            left = mid + 1;
389                    }
390          }          }
391    
392          section_data_count++;          if (aid != p_block->articles[left].aid) // not found
393            {
394                    return NULL;
395            }
396    
397          return p_section;          return (p_block->articles + left); // found
398  }  }
399    
400  int section_data_free_block(SECTION_DATA *p_section)  ARTICLE *article_block_find_by_index(int index)
401  {  {
402          ARTICLE_BLOCK *p_block;          ARTICLE_BLOCK *p_block;
403    
404          if (p_section == NULL)          if (p_article_block_pool == NULL)
405            {
406                    log_error("article_block_pool not initialized\n");
407                    return NULL;
408            }
409    
410            if (index < 0 || index / BBS_article_count_per_block >= p_article_block_pool->block_count)
411            {
412                    log_error("article_block_find_by_index(%d) is out of boundary of block [0, %d)\n", index, p_article_block_pool->block_count);
413                    return NULL;
414            }
415    
416            p_block = p_article_block_pool->p_block[index / BBS_article_count_per_block];
417    
418            if (index % BBS_article_count_per_block >= p_block->article_count)
419          {          {
420                  log_error("section_data_free_block() NULL pointer error\n");                  log_error("article_block_find_by_index(%d) is out of boundary of article [0, %d)\n", index, p_block->article_count);
421                    return NULL;
422            }
423    
424            return (p_block->articles + (index % BBS_article_count_per_block));
425    }
426    
427    extern int section_list_init(const char *filename)
428    {
429            int semid;
430            int shmid;
431            int proj_id;
432            key_t key;
433            size_t size;
434            void *p_shm;
435            union semun arg;
436            int i;
437    
438            if (p_section_list_pool != NULL)
439            {
440                    section_list_cleanup();
441            }
442    
443            proj_id = (int)(time(NULL) % getpid());
444            key = ftok(filename, proj_id);
445            if (key == -1)
446            {
447                    log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
448                    return -3;
449            }
450    
451            // Allocate shared memory
452            size = sizeof(SECTION_LIST_POOL);
453            shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
454            if (shmid == -1)
455            {
456                    log_error("shmget(section_list_pool_shm, size = %d) error (%d)\n", size, errno);
457                    return -3;
458            }
459            p_shm = shmat(shmid, NULL, 0);
460            if (p_shm == (void *)-1)
461            {
462                    log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
463                    return -3;
464            }
465    
466            p_section_list_pool = p_shm;
467            p_section_list_pool->shmid = shmid;
468            p_section_list_pool->section_count = 0;
469    
470            // Allocate semaphore as section locks
471            size = 2 * (BBS_max_section + 1); // r_sem and w_sem per section, the last pair for all sections
472            semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
473            if (semid == -1)
474            {
475                    log_error("semget(section_list_pool_sem, size = %d) error (%d)\n", size, errno);
476                    return -3;
477            }
478    
479            // Initialize sem value to 0
480            arg.val = 0;
481            for (i = 0; i < size; i++)
482            {
483                    if (semctl(semid, i, SETVAL, arg) == -1)
484                    {
485                            log_error("semctl(section_list_pool_sem, SETVAL) error (%d)\n", errno);
486                            return -3;
487                    }
488            }
489    
490            p_section_list_pool->semid = semid;
491    
492            p_section_list_pool->p_trie_dict_section_by_name = trie_dict_create();
493            if (p_section_list_pool->p_trie_dict_section_by_name == NULL)
494            {
495                    log_error("trie_dict_create() OOM\n", BBS_max_section);
496                    return -2;
497            }
498    
499            p_section_list_pool->p_trie_dict_section_by_sid = trie_dict_create();
500            if (p_section_list_pool->p_trie_dict_section_by_sid == NULL)
501            {
502                    log_error("trie_dict_create() OOM\n", BBS_max_section);
503                    return -2;
504            }
505    
506            return 0;
507    }
508    
509    void section_list_cleanup(void)
510    {
511            int shmid;
512    
513            if (p_section_list_pool == NULL)
514            {
515                    return;
516            }
517    
518            if (p_section_list_pool->p_trie_dict_section_by_name != NULL)
519            {
520                    trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_name);
521                    p_section_list_pool->p_trie_dict_section_by_name = NULL;
522            }
523    
524            if (p_section_list_pool->p_trie_dict_section_by_sid != NULL)
525            {
526                    trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_sid);
527                    p_section_list_pool->p_trie_dict_section_by_sid = NULL;
528            }
529    
530            shmid = p_section_list_pool->shmid;
531    
532            if (semctl(p_section_list_pool->semid, 0, IPC_RMID) == -1)
533            {
534                    log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_section_list_pool->semid, errno);
535            }
536    
537            if (shmdt(p_section_list_pool) == -1)
538            {
539                    log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
540            }
541    
542            if (shmid != 0 && shmctl(shmid, IPC_RMID, NULL) == -1)
543            {
544                    log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
545            }
546    
547            p_section_list_pool = NULL;
548    }
549    
550    int set_section_list_shm_readonly(void)
551    {
552            int shmid;
553            void *p_shm;
554    
555            if (p_section_list_pool == NULL)
556            {
557                    log_error("p_section_list_pool not initialized\n");
558                  return -1;                  return -1;
559          }          }
560    
561          if (p_section_data_pool == NULL)          shmid = p_section_list_pool->shmid;
562    
563            // Remap shared memory in read-only mode
564    #if defined(__MSYS__) || defined(__MINGW32__)
565            if (shmdt(p_section_list_pool) == -1)
566          {          {
567                  log_error("section_data not initialized\n");                  log_error("shmdt(section_list_pool) error (%d)\n", errno);
568                  return -1;                  return -1;
569          }          }
570            p_shm = shmat(shmid, p_section_list_pool, SHM_RDONLY);
571    #else
572            p_shm = shmat(shmid, p_section_list_pool, SHM_RDONLY | SHM_REMAP);
573    #endif
574            if (p_shm == (void *)-1)
575            {
576                    log_error("shmat(section_list_pool shmid = %d) error (%d)\n", shmid, errno);
577                    return -3;
578            }
579    
580            p_section_list_pool = p_shm;
581    
582            return 0;
583    }
584    
585          while (p_section->p_head_block != NULL)  int detach_section_list_shm(void)
586    {
587            if (p_section_list_pool != NULL && shmdt(p_section_list_pool) == -1)
588          {          {
589                  p_block = p_section->p_head_block;                  log_error("shmdt(section_list_pool) error (%d)\n", errno);
590                  p_section->p_head_block = p_block->p_next_block;                  return -1;
                 push_free_article_block(p_block);  
591          }          }
592    
593          p_section->p_tail_block = NULL;          p_section_list_pool = NULL;
594          p_section->block_count = 0;  
595          p_section->article_count = 0;          return 0;
596          p_section->delete_count = 0;  }
597    
598    inline static void sid_to_str(int32_t sid, char *p_sid_str)
599    {
600            uint32_t u_sid;
601            int i;
602    
603            u_sid = (uint32_t)sid;
604            for (i = 0; i < SID_STR_LEN - 1; i++)
605            {
606                    p_sid_str[i] = (char)(u_sid % 255 + 1);
607                    u_sid /= 255;
608            }
609            p_sid_str[i] = '\0';
610    }
611    
612    SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_list)
613    {
614            SECTION_LIST *p_section;
615            char sid_str[SID_STR_LEN];
616    
617            if (p_section_list_pool == NULL)
618            {
619                    log_error("session_list_pool not initialized\n");
620                    return NULL;
621            }
622    
623            if (p_section_list_pool->section_count >= BBS_max_section)
624            {
625                    log_error("section_count reach limit %d >= %d\n", p_section_list_pool->section_count, BBS_max_section);
626                    return NULL;
627            }
628    
629            sid_to_str(sid, sid_str);
630    
631            p_section = p_section_list_pool->sections + p_section_list_pool->section_count;
632    
633            p_section->sid = sid;
634            p_section->ex_menu_tm = 0;
635    
636            strncpy(p_section->sname, sname, sizeof(p_section->sname) - 1);
637            p_section->sname[sizeof(p_section->sname) - 1] = '\0';
638    
639            strncpy(p_section->stitle, stitle, sizeof(p_section->stitle) - 1);
640            p_section->stitle[sizeof(p_section->stitle) - 1] = '\0';
641    
642            strncpy(p_section->master_list, master_list, sizeof(p_section->master_list) - 1);
643            p_section->master_list[sizeof(p_section->master_list) - 1] = '\0';
644    
645            if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_name, sname, p_section_list_pool->section_count) != 1)
646            {
647                    log_error("trie_dict_set(section, %s, %d) error\n", sname, p_section_list_pool->section_count);
648                    return NULL;
649            }
650    
651            if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, p_section_list_pool->section_count) != 1)
652            {
653                    log_error("trie_dict_set(section, %d, %d) error\n", sid, p_section_list_pool->section_count);
654                    return NULL;
655            }
656    
657            section_list_reset_articles(p_section);
658    
659            p_section_list_pool->section_count++;
660    
661            return p_section;
662    }
663    
664    int section_list_update(SECTION_LIST *p_section, const char *sname, const char *stitle, const char *master_list)
665    {
666            int64_t index;
667    
668            if (p_section == NULL || sname == NULL || stitle == NULL || master_list == NULL)
669            {
670                    log_error("NULL pointer error\n");
671                    return -1;
672            }
673    
674            index = get_section_index(p_section);
675    
676            strncpy(p_section->sname, sname, sizeof(p_section->sname) - 1);
677            p_section->sname[sizeof(p_section->sname) - 1] = '\0';
678    
679            strncpy(p_section->stitle, stitle, sizeof(p_section->stitle) - 1);
680            p_section->stitle[sizeof(p_section->stitle) - 1] = '\0';
681    
682            strncpy(p_section->master_list, master_list, sizeof(p_section->master_list) - 1);
683            p_section->master_list[sizeof(p_section->master_list) - 1] = '\0';
684    
685            if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_name, sname, index) < 0)
686            {
687                    log_error("trie_dict_set(section, %s, %d) error\n", sname, index);
688                    return -2;
689            }
690    
691          return 0;          return 0;
692  }  }
693    
694  SECTION_DATA *section_data_find_by_name(const char *sname)  void section_list_reset_articles(SECTION_LIST *p_section)
695    {
696            p_section->article_count = 0;
697            p_section->topic_count = 0;
698            p_section->visible_article_count = 0;
699            p_section->visible_topic_count = 0;
700            p_section->p_article_head = NULL;
701            p_section->p_article_tail = NULL;
702    
703            p_section->page_count = 0;
704            p_section->last_page_visible_article_count = 0;
705    
706            p_section->ontop_article_count = 0;
707    }
708    
709    SECTION_LIST *section_list_find_by_name(const char *sname)
710  {  {
711          int64_t index;          int64_t index;
712            int ret;
713    
714          if (p_section_data_pool == NULL || p_trie_dict_section_data == NULL)          if (p_section_list_pool == NULL)
715          {          {
716                  log_error("section_data not initialized\n");                  log_error("section_list not initialized\n");
717                  return NULL;                  return NULL;
718          }          }
719    
720          if (trie_dict_get(p_trie_dict_section_data, sname, &index) != 1)          ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_name, sname, &index);
721            if (ret < 0)
722            {
723                    log_error("trie_dict_get(section, %s) error\n", sname);
724                    return NULL;
725            }
726            else if (ret == 0)
727          {          {
                 log_error("trie_dict_get(section_data, %s) error\n", sname);  
728                  return NULL;                  return NULL;
729          }          }
730    
731          return (p_section_data_pool + index);          return (p_section_list_pool->sections + index);
732  }  }
733    
734  int section_data_append_article(SECTION_DATA *p_section, const ARTICLE *p_article)  SECTION_LIST *section_list_find_by_sid(int32_t sid)
735    {
736            int64_t index;
737            int ret;
738            char sid_str[SID_STR_LEN];
739    
740            if (p_section_list_pool == NULL)
741            {
742                    log_error("section_list not initialized\n");
743                    return NULL;
744            }
745    
746            sid_to_str(sid, sid_str);
747    
748            ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, &index);
749            if (ret < 0)
750            {
751                    log_error("trie_dict_get(section, %d) error\n", sid);
752                    return NULL;
753            }
754            else if (ret == 0)
755            {
756                    return NULL;
757            }
758    
759            return (p_section_list_pool->sections + index);
760    }
761    
762    int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
763  {  {
764          ARTICLE_BLOCK *p_block;          ARTICLE_BLOCK *p_block;
765          int32_t last_aid = 0;          int32_t last_aid = 0;
766            ARTICLE *p_article;
767          ARTICLE *p_topic_head;          ARTICLE *p_topic_head;
768          ARTICLE *p_topic_tail;          ARTICLE *p_topic_tail;
769    
770          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article_src == NULL)
771          {          {
772                  log_error("section_data_append_article() NULL pointer error\n");                  log_error("NULL pointer error\n");
773                  return -1;                  return -1;
774          }          }
775    
776          if (p_section_data_pool == NULL)          if (p_article_block_pool == NULL)
777          {          {
778                  log_error("section_data not initialized\n");                  log_error("article_block_pool not initialized\n");
779                  return -1;                  return -1;
780          }          }
781    
782          if (p_section->p_tail_block == NULL || p_section->p_tail_block->article_count >= BBS_article_limit_per_block)          if (p_section->sid != p_article_src->sid)
783          {          {
784                  if (p_section->block_count >= BBS_article_block_limit_per_section)                  log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
785                  {                  return -2;
786                          log_error("section block count %d reach limit\n", p_section->block_count);          }
787                          return -2;  
788                  }          if (p_section->article_count >= BBS_article_limit_per_section)
789            {
790                    log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
791                    return -2;
792            }
793    
794            if (p_article_block_pool->block_count == 0 ||
795                    p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= BBS_article_count_per_block)
796            {
797                  if ((p_block = pop_free_article_block()) == NULL)                  if ((p_block = pop_free_article_block()) == NULL)
798                  {                  {
799                          log_error("pop_free_article_block() error\n");                          log_error("pop_free_article_block() error\n");
800                          return -2;                          return -2;
801                  }                  }
802    
803                  p_block->article_count = 0;                  if (p_article_block_pool->block_count > 0)
                 p_block->p_next_block = NULL;  
   
                 if (p_section->p_tail_block == NULL)  
804                  {                  {
805                          p_section->p_head_block = p_block;                          last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[BBS_article_count_per_block - 1].aid;
                         last_aid = 0;  
806                  }                  }
807                  else  
808                  {                  p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
809                          p_section->p_tail_block->p_next_block = p_block;                  p_article_block_pool->block_count++;
                         last_aid = p_section->p_tail_block->articles[BBS_article_limit_per_block - 1].aid;  
                 }  
                 p_section->p_tail_block = p_block;  
                 p_section->p_block[p_section->block_count] = p_block;  
                 p_section->block_count++;  
810          }          }
811          else          else
812          {          {
813                  p_block = p_section->p_tail_block;                  p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
814                  last_aid = p_block->articles[p_block->article_count - 1].aid;                  last_aid = p_block->articles[p_block->article_count - 1].aid;
815          }          }
816    
817          // AID of articles should be strictly ascending          // AID of articles should be strictly ascending
818          if (p_article->aid <= last_aid)          if (p_article_src->aid <= last_aid)
819          {          {
820                  log_error("section_data_append_article(aid=%d) error: last_aid=%d\n", p_article->aid, last_aid);                  log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
821                  return -3;                  return -3;
822          }          }
823    
824          if (p_block->article_count == 0)          p_article = (p_block->articles + p_block->article_count);
825            p_block->article_count++;
826            p_section->article_count++;
827    
828            // Copy article data
829            *p_article = *p_article_src;
830    
831            if (p_article->visible)
832          {          {
833                  p_section->block_head_aid[p_section->block_count - 1] = p_article->aid;                  p_section->visible_article_count++;
834          }          }
835    
836            // Link appended article as tail node of topic bi-directional list
837          if (p_article->tid != 0)          if (p_article->tid != 0)
838          {          {
839                  p_topic_head = section_data_find_article_by_aid(p_section, p_article->tid);                  p_topic_head = article_block_find_by_aid(p_article->tid);
840                  if (p_topic_head == NULL)                  if (p_topic_head == NULL)
841                  {                  {
842                          log_error("search head of topic (aid=%d) error\n", p_article->tid);                          log_error("search head of topic (aid=%d) error\n", p_article->tid);
843                          return -4;                          return -4;
844                  }                  }
845    
846                  p_topic_tail = section_data_find_article_by_aid(p_section, p_topic_head->prior_aid);                  p_topic_tail = p_topic_head->p_topic_prior;
847                  if (p_topic_tail == NULL)                  if (p_topic_tail == NULL)
848                  {                  {
849                          log_error("search tail of topic (aid=%d) error\n", p_topic_head->prior_aid);                          log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
850                          return -4;                          return -4;
851                  }                  }
852          }          }
853          else          else
854          {          {
855                  p_topic_head = &(p_block->articles[p_block->article_count]);                  p_section->topic_count++;
856                  p_topic_tail = p_topic_head;  
857                    if (p_article->visible)
858                    {
859                            p_section->visible_topic_count++;
860                    }
861    
862                    p_topic_head = p_article;
863                    p_topic_tail = p_article;
864          }          }
865    
866          // Copy article data          p_article->p_topic_prior = p_topic_tail;
867          p_block->articles[p_block->article_count] = *p_article;          p_article->p_topic_next = p_topic_head;
868            p_topic_head->p_topic_prior = p_article;
869            p_topic_tail->p_topic_next = p_article;
870    
871          // Link appended article as tail node of topic bi-directional list;          // Link appended article as tail node of article bi-directional list
872          p_block->articles[p_block->article_count].prior_aid = p_topic_tail->aid;          if (p_section->p_article_head == NULL)
873          p_block->articles[p_block->article_count].next_aid = p_topic_head->aid;          {
874          p_topic_head->prior_aid = p_article->aid;                  p_section->p_article_head = p_article;
875          p_topic_tail->next_aid = p_article->aid;                  p_section->p_article_tail = p_article;
876            }
877            p_article->p_prior = p_section->p_article_tail;
878            p_article->p_next = p_section->p_article_head;
879            p_section->p_article_head->p_prior = p_article;
880            p_section->p_article_tail->p_next = p_article;
881            p_section->p_article_tail = p_article;
882    
883          p_block->article_count++;          // Update page
884          p_section->article_count++;          if ((p_article->visible && p_section->last_page_visible_article_count == BBS_article_limit_per_page) ||
885                    p_section->page_count == 0)
886            {
887                    p_section->p_page_first_article[p_section->page_count] = p_article;
888                    p_section->page_count++;
889                    p_section->last_page_visible_article_count = 0;
890            }
891    
892            if (p_article->visible)
893            {
894                    p_section->last_page_visible_article_count++;
895            }
896    
897            if (p_article->ontop && section_list_update_article_ontop(p_section, p_article) < 0)
898            {
899                    log_error("section_list_update_article_ontop(sid=%d, aid=%d) error\n",
900                                      p_section->sid, p_article->aid);
901                    return -5;
902            }
903    
904          return 0;          return 0;
905  }  }
906    
907  ARTICLE *section_data_find_article_by_aid(SECTION_DATA *p_section, int32_t aid)  int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
908    {
909            ARTICLE *p_article;
910            ARTICLE *p_reply;
911            int affected_count = 0;
912    
913            if (p_section == NULL)
914            {
915                    log_error("NULL pointer error\n");
916                    return -1;
917            }
918    
919            p_article = article_block_find_by_aid(aid);
920            if (p_article == NULL)
921            {
922                    return -1; // Not found
923            }
924    
925            if (p_section->sid != p_article->sid)
926            {
927                    log_error("Inconsistent section sid %d != article sid %d\n", p_section->sid, p_article->sid);
928                    return -2;
929            }
930    
931            if (p_article->visible == visible)
932            {
933                    return 0; // Already set
934            }
935    
936            if (visible == 0) // 1 -> 0
937            {
938                    p_section->visible_article_count--;
939    
940                    if (user_article_cnt_inc(p_article->uid, -1) < 0)
941                    {
942                            log_error("user_article_cnt_inc(uid=%d, -1) error\n", p_article->uid);
943                    }
944    
945                    if (p_article->tid == 0)
946                    {
947                            p_section->visible_topic_count--;
948    
949                            // Set related visible replies to invisible
950                            for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
951                            {
952                                    if (p_reply->tid != aid)
953                                    {
954                                            log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
955                                            continue;
956                                    }
957    
958                                    if (p_reply->visible == 1)
959                                    {
960                                            p_reply->visible = 0;
961                                            p_section->visible_article_count--;
962                                            affected_count++;
963    
964                                            if (user_article_cnt_inc(p_reply->uid, -1) < 0)
965                                            {
966                                                    log_error("user_article_cnt_inc(uid=%d, -1) error\n", p_reply->uid);
967                                            }
968                                    }
969                            }
970                    }
971            }
972            else // 0 -> 1
973            {
974                    p_section->visible_article_count++;
975    
976                    if (p_article->tid == 0)
977                    {
978                            p_section->visible_topic_count++;
979                    }
980    
981                    if (user_article_cnt_inc(p_article->uid, 1) < 0)
982                    {
983                            log_error("user_article_cnt_inc(uid=%d, 1) error\n", p_article->uid);
984                    }
985            }
986    
987            p_article->visible = visible;
988            affected_count++;
989    
990            return affected_count;
991    }
992    
993    int section_list_update_article_ontop(SECTION_LIST *p_section, ARTICLE *p_article)
994    {
995            int i;
996    
997            if (p_section == NULL || p_article == NULL)
998            {
999                    log_error("NULL pointer error\n");
1000                    return -1;
1001            }
1002    
1003            if (p_section->sid != p_article->sid)
1004            {
1005                    log_error("Inconsistent section sid %d != article sid %d\n", p_section->sid, p_article->sid);
1006                    return -2;
1007            }
1008    
1009            if (p_article->ontop)
1010            {
1011                    for (i = 0; i < p_section->ontop_article_count; i++)
1012                    {
1013                            if (p_section->p_ontop_articles[i]->aid == p_article->aid)
1014                            {
1015                                    log_error("Inconsistent state found: article %d already ontop in section %d\n", p_article->aid, p_section->sid);
1016                                    return 0;
1017                            }
1018                            else if (p_section->p_ontop_articles[i]->aid > p_article->aid)
1019                            {
1020                                    break;
1021                            }
1022                    }
1023    
1024                    // Remove the oldest one if the array of ontop articles is full
1025                    if (p_section->ontop_article_count >= BBS_ontop_article_limit_per_section)
1026                    {
1027                            if (i == 0) // p_article is the oldest one
1028                            {
1029                                    return 0;
1030                            }
1031                            memmove((void *)(p_section->p_ontop_articles),
1032                                            (void *)(p_section->p_ontop_articles + 1),
1033                                            sizeof(ARTICLE *) * (size_t)(i - 1));
1034                            p_section->ontop_article_count--;
1035                            i--;
1036                    }
1037                    else
1038                    {
1039                            memmove((void *)(p_section->p_ontop_articles + i + 1),
1040                                            (void *)(p_section->p_ontop_articles + i),
1041                                            sizeof(ARTICLE *) * (size_t)(p_section->ontop_article_count - i));
1042                    }
1043    
1044                    p_section->p_ontop_articles[i] = p_article;
1045                    p_section->ontop_article_count++;
1046    
1047                    // TODO: debug
1048            }
1049            else // ontop == 0
1050            {
1051                    for (i = 0; i < p_section->ontop_article_count; i++)
1052                    {
1053                            if (p_section->p_ontop_articles[i]->aid == p_article->aid)
1054                            {
1055                                    break;
1056                            }
1057                    }
1058                    if (i == p_section->ontop_article_count) // not found
1059                    {
1060                            log_error("Inconsistent state found: article %d not ontop in section %d\n", p_article->aid, p_section->sid);
1061                            return 0;
1062                    }
1063    
1064                    memmove((void *)(p_section->p_ontop_articles + i),
1065                                    (void *)(p_section->p_ontop_articles + i + 1),
1066                                    sizeof(ARTICLE *) * (size_t)(p_section->ontop_article_count - i - 1));
1067                    p_section->ontop_article_count--;
1068            }
1069    
1070            return 0;
1071    }
1072    
1073    int section_list_page_count_with_ontop(SECTION_LIST *p_section)
1074    {
1075            int page_count;
1076    
1077            if (p_section == NULL)
1078            {
1079                    log_error("NULL pointer error\n");
1080                    return -1;
1081            }
1082    
1083            page_count = p_section->page_count - 1 +
1084                                     (p_section->last_page_visible_article_count + p_section->ontop_article_count + BBS_article_limit_per_page - 1) /
1085                                             BBS_article_limit_per_page;
1086    
1087            if (page_count < 0)
1088            {
1089                    page_count = 0;
1090            }
1091    
1092            return page_count;
1093    }
1094    
1095    int section_list_page_article_count_with_ontop(SECTION_LIST *p_section, int32_t page_id)
1096    {
1097            if (p_section == NULL)
1098            {
1099                    log_error("NULL pointer error\n");
1100                    return -1;
1101            }
1102    
1103            if (page_id < p_section->page_count - 1)
1104            {
1105                    return BBS_article_limit_per_page;
1106            }
1107            else // if (page_id >= p_section->page_count - 1)
1108            {
1109                    return MIN(MAX(0,
1110                                               (p_section->last_page_visible_article_count + p_section->ontop_article_count -
1111                                                    BBS_article_limit_per_page * (page_id - p_section->page_count + 1))),
1112                                       BBS_article_limit_per_page);
1113            }
1114    }
1115    
1116    ARTICLE *section_list_find_article_with_offset(SECTION_LIST *p_section, int32_t aid, int32_t *p_page, int32_t *p_offset, ARTICLE **pp_next)
1117  {  {
1118          ARTICLE *p_article;          ARTICLE *p_article;
         ARTICLE_BLOCK *p_block;  
1119          int left;          int left;
1120          int right;          int right;
1121          int mid;          int mid;
1122    
1123            *p_page = -1;
1124            *p_offset = -1;
1125            *pp_next = NULL;
1126    
1127          if (p_section == NULL)          if (p_section == NULL)
1128          {          {
1129                  log_error("section_data_find_article_by_aid() NULL pointer error\n");                  log_error("NULL pointer error\n");
1130                  return NULL;                  return NULL;
1131          }          }
1132    
1133          if (p_section->block_count == 0) // empty section          if (p_section->article_count == 0) // empty
1134          {          {
1135                    *p_page = 0;
1136                    *p_offset = 0;
1137                  return NULL;                  return NULL;
1138          }          }
1139    
1140          left = 0;          left = 0;
1141          right = p_section->block_count;          right = p_section->page_count - 1;
1142    
1143          // aid in the range [ head aid of blocks[left], tail aid of blocks[right - 1] ]          // aid in the range [ head aid of pages[left], tail aid of pages[right] ]
1144          while (left < right - 1)          while (left < right)
1145          {          {
1146                  // get block offset no less than mid value of left and right block offsets                  // get page id no less than mid value of left page id and right page id
1147                  mid = (left + right) / 2 + (right - left) % 2;                  mid = (left + right) / 2 + (left + right) % 2;
                   
                 if (mid >= BBS_article_block_limit_per_section)  
                 {  
                         log_error("block_m(%d) is out of boundary\n", mid);  
                         return NULL;  
                 }  
1148    
1149                  if (aid < p_section->block_head_aid[mid])                  if (aid < p_section->p_page_first_article[mid]->aid)
1150                  {                  {
1151                          right = mid;                          right = mid - 1;
1152                  }                  }
1153                  else                  else // if (aid < p_section->p_page_first_article[mid]->aid)
1154                  {                  {
1155                          left = mid;                          left = mid;
1156                  }                  }
1157          }          }
1158    
1159          p_block = p_section->p_block[left];          *p_page = left;
1160    
1161            p_article = p_section->p_page_first_article[*p_page];
1162    
1163            // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
1164            right = (*p_page == MAX(0, p_section->page_count - 1) ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);
1165    
1166            // left will be the offset of article found or offset to insert
1167          left = 0;          left = 0;
         right = p_block->article_count - 1;  
1168    
1169          // aid in the range [ aid of articles[left], aid of articles[right] ]          while (aid > p_article->aid)
         while (left < right)  
1170          {          {
1171                  mid = (left + right) / 2;                  p_article = p_article->p_next;
1172                    left++;
1173    
1174                  if (aid <= p_block->articles[mid].aid)                  if (aid == p_article->aid)
1175                  {                  {
1176                          right = mid;                          *pp_next = p_article->p_next;
1177                            break;
1178                  }                  }
1179                  else  
1180                    // over last article in the page
1181                    if (p_article == p_section->p_article_head || p_article->aid >= right)
1182                  {                  {
1183                          left = mid + 1;                          *pp_next = (p_article == p_section->p_article_head ? p_section->p_article_head : p_section->p_page_first_article[*p_page + 1]);
1184                            *p_offset = left;
1185                            return NULL; // not found
1186                  }                  }
1187          }          }
1188    
1189          p_article = &(p_block->articles[left]);          if (aid < p_article->aid)
1190            {
1191                    *pp_next = p_article;
1192                    p_article = NULL; // not found
1193            }
1194            else // aid == p_article->aid
1195            {
1196                    *pp_next = p_article->p_next;
1197            }
1198    
1199            *p_offset = left;
1200    
1201          return p_article;          return p_article;
1202  }  }
1203    
1204  ARTICLE *section_data_find_article_by_index(SECTION_DATA *p_section, int index)  int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
1205  {  {
1206          ARTICLE *p_article;          ARTICLE *p_article;
1207          ARTICLE_BLOCK *p_block;          ARTICLE *p_next;
1208            int32_t page;
1209            int32_t offset;
1210            int visible_article_count;
1211            int page_head_set;
1212    
1213          if (p_section == NULL)          if (p_section == NULL)
1214          {          {
1215                  log_error("section_data_find_article_by_index() NULL pointer error\n");                  log_error("NULL pointer error\n");
1216                  return NULL;                  return -1;
1217          }          }
1218    
1219          if (index < 0 || index >= p_section->article_count)          if (p_section->article_count == 0) // empty
1220          {          {
1221                  log_error("section_data_find_article_by_index(%d) is out of boundary [0, %d)\n", index, p_section->article_count);                  p_section->page_count = 0;
1222                  return NULL;                  p_section->last_page_visible_article_count = 0;
1223    
1224                    return 0;
1225          }          }
1226    
1227          p_block = p_section->p_block[index / BBS_article_limit_per_block];          if (start_aid > 0)
1228          p_article = &(p_block->articles[index % BBS_article_limit_per_block]);          {
1229                    p_article = article_block_find_by_aid(start_aid);
1230                    if (p_article == NULL)
1231                    {
1232                            return -1; // Not found
1233                    }
1234    
1235          return p_article;                  if (p_section->sid != p_article->sid)
1236                    {
1237                            log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
1238                            return -2;
1239                    }
1240    
1241                    p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
1242                    if (p_article == NULL)
1243                    {
1244                            if (page < 0)
1245                            {
1246                                    return -1;
1247                            }
1248                            log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
1249                                              start_aid, p_section->sid);
1250                            return -2;
1251                    }
1252    
1253                    if (offset > 0)
1254                    {
1255                            p_article = p_section->p_page_first_article[page];
1256                    }
1257            }
1258            else
1259            {
1260                    p_article = p_section->p_article_head;
1261                    page = 0;
1262                    offset = 0;
1263            }
1264    
1265            visible_article_count = 0;
1266            page_head_set = 0;
1267    
1268            do
1269            {
1270                    if (!page_head_set && visible_article_count == 0)
1271                    {
1272                            p_section->p_page_first_article[page] = p_article;
1273                            page_head_set = 1;
1274                    }
1275    
1276                    if (p_article->visible)
1277                    {
1278                            visible_article_count++;
1279                    }
1280    
1281                    p_article = p_article->p_next;
1282    
1283                    // skip remaining invisible articles
1284                    while (p_article->visible == 0 && p_article != p_section->p_article_head)
1285                    {
1286                            p_article = p_article->p_next;
1287                    }
1288    
1289                    if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
1290                    {
1291                            page++;
1292                            visible_article_count = 0;
1293                            page_head_set = 0;
1294    
1295                            if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
1296                            {
1297                                    log_error("Count of page exceed limit in section %d\n", p_section->sid);
1298                                    break;
1299                            }
1300                    }
1301            } while (p_article != p_section->p_article_head);
1302    
1303            p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1304            p_section->last_page_visible_article_count = (visible_article_count > 0
1305                                                                                                              ? visible_article_count
1306                                                                                                              : (page > 0 ? BBS_article_limit_per_page : 0));
1307    
1308            return 0;
1309  }  }
1310    
1311  int section_data_mark_del_article(SECTION_DATA *p_section, int32_t aid)  int32_t article_block_last_aid(void)
1312    {
1313            ARTICLE_BLOCK *p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
1314            int32_t last_aid = p_block->articles[p_block->article_count - 1].aid;
1315    
1316            return last_aid;
1317    }
1318    
1319    int article_block_article_count(void)
1320    {
1321            int ret;
1322    
1323            if (p_article_block_pool == NULL || p_article_block_pool->block_count <= 0)
1324            {
1325                    return -1;
1326            }
1327    
1328            ret = (p_article_block_pool->block_count - 1) * BBS_article_count_per_block +
1329                      p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count;
1330    
1331            return ret;
1332    }
1333    
1334    int article_count_of_topic(int32_t aid)
1335  {  {
1336          ARTICLE *p_article;          ARTICLE *p_article;
1337            int article_count;
1338    
1339            p_article = article_block_find_by_aid(aid);
1340            if (p_article == NULL)
1341            {
1342                    return 0; // Not found
1343            }
1344    
1345            article_count = 0;
1346    
1347            do
1348            {
1349                    if (p_article->tid != 0 && p_article->tid != aid)
1350                    {
1351                            log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1352                            break;
1353                    }
1354    
1355                    article_count++;
1356                    p_article = p_article->p_topic_next;
1357            } while (p_article->aid != aid);
1358    
1359            return article_count;
1360    }
1361    
1362    int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1363    {
1364            ARTICLE *p_article;
1365            ARTICLE *p_next;
1366            int32_t page;
1367            int32_t offset;
1368            int32_t move_article_count;
1369            int32_t dest_article_count_old;
1370            int32_t last_unaffected_aid_src;
1371            int32_t first_inserted_aid_dest;
1372            int move_counter;
1373    
1374            if (p_section_src == NULL || p_section_dest == NULL)
1375            {
1376                    log_error("NULL pointer error\n");
1377                    return -1;
1378            }
1379    
1380            if (p_section_src->sid == p_section_dest->sid)
1381            {
1382                    log_error("section_list_move_topic() src and dest section are the same\n");
1383                    return -1;
1384            }
1385    
1386            if ((p_article = article_block_find_by_aid(aid)) == NULL)
1387            {
1388                    log_error("article_block_find_by_aid(aid = %d) error: article not found\n", aid);
1389                    return -2;
1390            }
1391    
1392            if (p_section_src->sid != p_article->sid)
1393            {
1394                    log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1395                                      p_section_src->sid, p_article->aid, p_article->sid);
1396                    return -2;
1397            }
1398    
1399            if (p_article->tid != 0)
1400            {
1401                    log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1402                    return -2;
1403            }
1404    
1405            last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1406    
1407            move_article_count = article_count_of_topic(aid);
1408            if (move_article_count <= 0)
1409            {
1410                    log_error("article_count_of_topic(aid = %d) <= 0\n", aid);
1411                    return -2;
1412            }
1413    
1414            if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1415            {
1416                    log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1417                                      p_section_dest->article_count + move_article_count, p_section_dest->sid);
1418                    return -3;
1419            }
1420    
1421            dest_article_count_old = p_section_dest->article_count;
1422            move_counter = 0;
1423            first_inserted_aid_dest = p_article->aid;
1424    
1425            do
1426            {
1427                    if (p_section_src->sid != p_article->sid)
1428                    {
1429                            log_error("section_list_move_topic() warning: src section sid %d != article %d sid %d\n",
1430                                              p_section_src->sid, p_article->aid, p_article->sid);
1431                            p_article = p_article->p_topic_next;
1432                            continue;
1433                    }
1434    
1435                    // Remove from bi-directional article list of src section
1436                    if (p_section_src->p_article_head == p_article)
1437                    {
1438                            p_section_src->p_article_head = p_article->p_next;
1439                    }
1440                    if (p_section_src->p_article_tail == p_article)
1441                    {
1442                            p_section_src->p_article_tail = p_article->p_prior;
1443                    }
1444                    if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1445                    {
1446                            p_section_src->p_article_head = NULL;
1447                            p_section_src->p_article_tail = NULL;
1448                    }
1449    
1450                    p_article->p_prior->p_next = p_article->p_next;
1451                    p_article->p_next->p_prior = p_article->p_prior;
1452    
1453                    // Update sid of article
1454                    p_article->sid = p_section_dest->sid;
1455    
1456                    if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1457                    {
1458                            log_error("section_list_move_topic() warning: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1459                            p_article = p_article->p_topic_next;
1460                            continue;
1461                    }
1462    
1463                    // Insert into bi-directional article list of dest section
1464                    if (p_next == NULL) // empty section
1465                    {
1466                            p_section_dest->p_article_head = p_article;
1467                            p_section_dest->p_article_tail = p_article;
1468                            p_article->p_prior = p_article;
1469                            p_article->p_next = p_article;
1470                    }
1471                    else
1472                    {
1473                            if (p_section_dest->p_article_head == p_next)
1474                            {
1475                                    if (p_article->aid < p_next->aid)
1476                                    {
1477                                            p_section_dest->p_article_head = p_article;
1478                                    }
1479                                    else // p_article->aid > p_next->aid
1480                                    {
1481                                            p_section_dest->p_article_tail = p_article;
1482                                    }
1483                            }
1484    
1485                            p_article->p_prior = p_next->p_prior;
1486                            p_article->p_next = p_next;
1487                            p_next->p_prior->p_next = p_article;
1488                            p_next->p_prior = p_article;
1489                    }
1490    
1491                    // Update article / topic counter of src / desc section
1492                    p_section_src->article_count--;
1493                    p_section_dest->article_count++;
1494                    if (p_article->tid == 0)
1495                    {
1496                            p_section_src->topic_count--;
1497                            p_section_dest->topic_count++;
1498                    }
1499    
1500                    // Update visible article / topic counter of src / desc section
1501                    if (p_article->visible)
1502                    {
1503                            p_section_src->visible_article_count--;
1504                            p_section_dest->visible_article_count++;
1505                            if (p_article->tid == 0)
1506                            {
1507                                    p_section_src->visible_topic_count--;
1508                                    p_section_dest->visible_topic_count++;
1509                            }
1510                    }
1511    
1512                    // Update page for empty dest section
1513                    if (p_section_dest->article_count == 1)
1514                    {
1515                            p_section_dest->p_page_first_article[0] = p_article;
1516                            p_section_dest->page_count = 1;
1517                            p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1518                    }
1519    
1520                    p_article = p_article->p_topic_next;
1521    
1522                    move_counter++;
1523                    if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1524                    {
1525                            // Re-calculate pages of desc section
1526                            if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1527                            {
1528                                    log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1529                                                      p_section_dest->sid, first_inserted_aid_dest);
1530                            }
1531    
1532                            first_inserted_aid_dest = p_article->aid;
1533                    }
1534            } while (p_article->aid != aid);
1535    
1536            if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1537            {
1538                    log_error("section_list_move_topic() warning: count of moved articles %d != %d\n",
1539                                      p_section_dest->article_count - dest_article_count_old, move_article_count);
1540            }
1541    
1542            // Re-calculate pages of src section
1543            if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1544            {
1545                    log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1546                                      p_section_src->sid, last_unaffected_aid_src, aid);
1547            }
1548    
1549            if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1550            {
1551                    // Re-calculate pages of desc section
1552                    if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1553                    {
1554                            log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1555                                              p_section_dest->sid, first_inserted_aid_dest);
1556                    }
1557            }
1558    
1559            return move_article_count;
1560    }
1561    
1562    int get_section_index(SECTION_LIST *p_section)
1563    {
1564            int index;
1565    
1566            if (p_section_list_pool == NULL)
1567            {
1568                    log_error("get_section_index() error: uninitialized\n");
1569                    return -1;
1570            }
1571    
1572            if (p_section == NULL)
1573            {
1574                    index = BBS_max_section;
1575            }
1576            else
1577            {
1578                    index = (int)(p_section - p_section_list_pool->sections);
1579                    if (index < 0 || index >= BBS_max_section)
1580                    {
1581                            log_error("get_section_index(%d) error: index out of range\n", index);
1582                            return -2;
1583                    }
1584            }
1585    
1586            return index;
1587    }
1588    
1589    int get_section_info(SECTION_LIST *p_section, char *sname, char *stitle, char *master_list)
1590    {
1591          if (p_section == NULL)          if (p_section == NULL)
1592          {          {
1593                  log_error("section_data_mark_del_article() NULL pointer error\n");                  log_error("NULL pointer error\n");
1594                    return -1;
1595            }
1596    
1597            if (section_list_rd_lock(p_section) < 0)
1598            {
1599                    log_error("section_list_rd_lock(sid=%d) error\n", p_section->sid);
1600                  return -2;                  return -2;
1601          }          }
1602    
1603          p_article = section_data_find_article_by_aid(p_section, aid);          if (sname != NULL)
         if (p_article == NULL)  
1604          {          {
1605                  return -1; // Not found                  memcpy(sname, p_section->sname, sizeof(p_section->sname));
1606            }
1607            if (stitle != NULL)
1608            {
1609                    memcpy(stitle, p_section->stitle, sizeof(p_section->stitle));
1610            }
1611            if (master_list != NULL)
1612            {
1613                    memcpy(master_list, p_section->master_list, sizeof(p_section->master_list));
1614            }
1615    
1616            // release lock of section
1617            if (section_list_rd_unlock(p_section) < 0)
1618            {
1619                    log_error("section_list_rd_unlock(sid=%d) error\n", p_section->sid);
1620                    return -2;
1621            }
1622    
1623            return 0;
1624    }
1625    
1626    int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1627    {
1628            int index;
1629            struct sembuf sops[4];
1630    #if !defined(__MSYS__) && !defined(__MINGW32__)
1631            struct timespec timeout;
1632    #endif
1633            int ret;
1634    
1635            index = get_section_index(p_section);
1636            if (index < 0)
1637            {
1638                    return -2;
1639            }
1640    
1641            sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1642            sops[0].sem_op = 0;                                                                // wait until unlocked
1643            sops[0].sem_flg = 0;
1644    
1645            sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1646            sops[1].sem_op = 1;                                                        // lock
1647            sops[1].sem_flg = SEM_UNDO;                                        // undo on terminate
1648    
1649            // Read lock on any specific section will also acquire single read lock on "all section"
1650            // so that write lock on all section only need to acquire single write on on "all section"
1651            // rather than to acquire multiple write locks on all the available sections.
1652            if (index != BBS_max_section)
1653            {
1654                    sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1655                    sops[2].sem_op = 0;                                                // wait until unlocked
1656                    sops[2].sem_flg = 0;
1657    
1658                    sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1659                    sops[3].sem_op = 1;                                        // lock
1660                    sops[3].sem_flg = SEM_UNDO;                        // undo on terminate
1661            }
1662    
1663    #if defined(__MSYS__) || defined(__MINGW32__)
1664            ret = semop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 2 : 4));
1665    #else
1666            timeout.tv_sec = wait_sec;
1667            timeout.tv_nsec = 0;
1668    
1669            ret = semtimedop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 2 : 4), &timeout);
1670    #endif
1671            if (ret == -1 && errno != EAGAIN && errno != EINTR)
1672            {
1673                    log_error("semop(index = %d, lock read) error %d\n", index, errno);
1674            }
1675    
1676            return ret;
1677    }
1678    
1679    int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1680    {
1681            int index;
1682            struct sembuf sops[3];
1683    #if !defined(__MSYS__) && !defined(__MINGW32__)
1684            struct timespec timeout;
1685    #endif
1686            int ret;
1687    
1688            index = get_section_index(p_section);
1689            if (index < 0)
1690            {
1691                    return -2;
1692            }
1693    
1694            sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1695            sops[0].sem_op = 0;                                                                // wait until unlocked
1696            sops[0].sem_flg = 0;
1697    
1698            sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1699            sops[1].sem_op = 1;                                                                // lock
1700            sops[1].sem_flg = SEM_UNDO;                                                // undo on terminate
1701    
1702            sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1703            sops[2].sem_op = 0;                                                        // wait until unlocked
1704            sops[2].sem_flg = 0;
1705    
1706    #if defined(__MSYS__) || defined(__MINGW32__)
1707            ret = semop(p_section_list_pool->semid, sops, 3);
1708    #else
1709            timeout.tv_sec = wait_sec;
1710            timeout.tv_nsec = 0;
1711    
1712            ret = semtimedop(p_section_list_pool->semid, sops, 3, &timeout);
1713    #endif
1714            if (ret == -1 && errno != EAGAIN && errno != EINTR)
1715            {
1716                    log_error("semop(index = %d, lock write) error %d\n", index, errno);
1717            }
1718    
1719            return ret;
1720    }
1721    
1722    int section_list_rd_unlock(SECTION_LIST *p_section)
1723    {
1724            int index;
1725            struct sembuf sops[2];
1726            int ret;
1727    
1728            index = get_section_index(p_section);
1729            if (index < 0)
1730            {
1731                    return -2;
1732            }
1733    
1734            sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1735            sops[0].sem_op = -1;                                               // unlock
1736            sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO;           // no wait
1737    
1738            if (index != BBS_max_section)
1739            {
1740                    sops[1].sem_num = BBS_max_section * 2;   // r_sem of all section
1741                    sops[1].sem_op = -1;                                     // unlock
1742                    sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1743          }          }
1744    
1745          if (p_article->visible == 0)          ret = semop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 1 : 2));
1746            if (ret == -1 && errno != EAGAIN && errno != EINTR)
1747          {          {
1748                  return 0; // Already deleted                  log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1749          }          }
1750    
1751          p_article->visible = 0;          return ret;
1752          p_section->delete_count++;  }
1753    
1754    int section_list_rw_unlock(SECTION_LIST *p_section)
1755    {
1756            int index;
1757            struct sembuf sops[1];
1758            int ret;
1759    
1760            index = get_section_index(p_section);
1761            if (index < 0)
1762            {
1763                    return -2;
1764            }
1765    
1766            sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1767            sops[0].sem_op = -1;                                                       // unlock
1768            sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO;                   // no wait
1769    
1770            ret = semop(p_section_list_pool->semid, sops, 1);
1771            if (ret == -1 && errno != EAGAIN && errno != EINTR)
1772            {
1773                    log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1774            }
1775    
1776            return ret;
1777    }
1778    
1779    int section_list_rd_lock(SECTION_LIST *p_section)
1780    {
1781            int timer = 0;
1782            int sid = (p_section == NULL ? 0 : p_section->sid);
1783            int ret = -1;
1784    
1785            while (!SYS_server_exit)
1786            {
1787                    ret = section_list_try_rd_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1788                    if (ret == 0) // success
1789                    {
1790                            break;
1791                    }
1792                    else if (errno == EAGAIN || errno == EINTR) // retry
1793                    {
1794                            timer++;
1795                            if (timer % SECTION_TRY_LOCK_TIMES == 0)
1796                            {
1797                                    log_error("section_list_try_rd_lock() tried %d times on section %d\n", timer, sid);
1798                            }
1799                    }
1800                    else // failed
1801                    {
1802                            log_error("section_list_try_rd_lock() failed on section %d\n", sid);
1803                            break;
1804                    }
1805            }
1806    
1807            return ret;
1808    }
1809    
1810    int section_list_rw_lock(SECTION_LIST *p_section)
1811    {
1812            int timer = 0;
1813            int sid = (p_section == NULL ? 0 : p_section->sid);
1814            int ret = -1;
1815    
1816            while (!SYS_server_exit)
1817            {
1818                    ret = section_list_try_rw_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1819                    if (ret == 0) // success
1820                    {
1821                            break;
1822                    }
1823                    else if (errno == EAGAIN || errno == EINTR) // retry
1824                    {
1825                            timer++;
1826                            if (timer % SECTION_TRY_LOCK_TIMES == 0)
1827                            {
1828                                    log_error("section_list_try_rw_lock() tried %d times on section %d\n", timer, sid);
1829                            }
1830                    }
1831                    else // failed
1832                    {
1833                            log_error("section_list_try_rw_lock() failed on section %d\n", sid);
1834                            break;
1835                    }
1836            }
1837    
1838          return 1;          return ret;
1839  }  }


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

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