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

Annotation of /lbbs/src/section_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.63 - (hide annotations)
Thu Nov 20 10:20:51 2025 UTC (3 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.62: +221 -23 lines
Content type: text/x-csrc
Add alternative POSIX semaphore based rd/rw (un)lock in section_list

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

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