/[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.20 - (hide annotations)
Sun May 25 08:15:03 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.19: +0 -1 lines
Content type: text/x-csrc
Remove debug message

1 sysadm 1.1 /***************************************************************************
2     section_list.c - description
3     -------------------
4     Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6     ***************************************************************************/
7    
8     /***************************************************************************
9     * *
10     * This program is free software; you can redistribute it and/or modify *
11     * it under the terms of the GNU General Public License as published by *
12     * the Free Software Foundation; either version 3 of the License, or *
13     * (at your option) any later version. *
14     * *
15     ***************************************************************************/
16    
17 sysadm 1.16 #define _GNU_SOURCE
18    
19 sysadm 1.1 #include "section_list.h"
20     #include "log.h"
21     #include "trie_dict.h"
22     #include <stdio.h>
23     #include <string.h>
24     #include <signal.h>
25     #include <unistd.h>
26     #include <stdlib.h>
27     #include <errno.h>
28 sysadm 1.7 #include <sys/param.h>
29 sysadm 1.16 #include <sys/sem.h>
30 sysadm 1.1 #include <sys/shm.h>
31     #include <sys/ipc.h>
32    
33 sysadm 1.17 #ifdef _SEM_SEMUN_UNDEFINED
34     union semun
35     {
36     int val; /* Value for SETVAL */
37     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
38     unsigned short *array; /* Array for GETALL, SETALL */
39     struct seminfo *__buf; /* Buffer for IPC_INFO
40     (Linux-specific) */
41     };
42     #endif // #ifdef _SEM_SEMUN_UNDEFINED
43    
44 sysadm 1.7 #define ARTICLE_BLOCK_PER_SHM 400 // sizeof(ARTICLE_BLOCK) * ARTICLE_BLOCK_PER_SHM is the size of each shm segment to allocate
45 sysadm 1.18 #define ARTICLE_BLOCK_SHM_COUNT_LIMIT 200 // limited by length (8-bit) of proj_id in ftok(path, proj_id)
46 sysadm 1.7 #define ARTICLE_BLOCK_PER_POOL (ARTICLE_BLOCK_PER_SHM * ARTICLE_BLOCK_SHM_COUNT_LIMIT)
47    
48 sysadm 1.12 #define CALCULATE_PAGE_THRESHOLD 100 // Adjust to tune performance of move topic
49    
50 sysadm 1.14 #define SID_STR_LEN 5 // 32-bit + NULL
51    
52 sysadm 1.7 struct article_block_t
53     {
54     ARTICLE articles[ARTICLE_PER_BLOCK];
55     int32_t article_count;
56     struct article_block_t *p_next_block;
57     };
58     typedef struct article_block_t ARTICLE_BLOCK;
59 sysadm 1.1
60     struct article_block_shm_t
61     {
62     int shmid;
63     void *p_shm;
64     };
65     typedef struct article_block_shm_t ARTICLE_BLOCK_SHM;
66    
67 sysadm 1.7 struct article_block_pool_t
68     {
69     ARTICLE_BLOCK_SHM shm_pool[ARTICLE_BLOCK_SHM_COUNT_LIMIT];
70     int shm_count;
71     ARTICLE_BLOCK *p_block_free_list;
72     ARTICLE_BLOCK *p_block[ARTICLE_BLOCK_PER_POOL];
73     int32_t block_count;
74     };
75     typedef struct article_block_pool_t ARTICLE_BLOCK_POOL;
76    
77 sysadm 1.18 static int article_block_pool_shmid;
78 sysadm 1.7 static ARTICLE_BLOCK_POOL *p_article_block_pool = NULL;
79 sysadm 1.1
80 sysadm 1.18 static int section_list_pool_semid;
81 sysadm 1.13 static int section_list_pool_shmid;
82 sysadm 1.7 static SECTION_LIST *p_section_list_pool = NULL;
83 sysadm 1.18
84 sysadm 1.7 static int section_list_count = 0;
85 sysadm 1.14 static TRIE_NODE *p_trie_dict_section_by_name = NULL;
86     static TRIE_NODE *p_trie_dict_section_by_sid = NULL;
87 sysadm 1.7
88     int article_block_init(const char *filename, int block_count)
89 sysadm 1.1 {
90     int shmid;
91     int proj_id;
92     key_t key;
93     size_t size;
94     void *p_shm;
95     int i;
96 sysadm 1.7 int block_count_in_shm;
97     ARTICLE_BLOCK *p_block_in_shm;
98     ARTICLE_BLOCK **pp_block_next;
99    
100     if (p_article_block_pool != NULL)
101 sysadm 1.1 {
102 sysadm 1.7 log_error("article_block_pool already initialized\n");
103 sysadm 1.1 return -1;
104     }
105    
106 sysadm 1.7 if (block_count > ARTICLE_BLOCK_PER_POOL)
107 sysadm 1.1 {
108 sysadm 1.7 log_error("article_block_count exceed limit %d\n", ARTICLE_BLOCK_PER_POOL);
109 sysadm 1.1 return -2;
110     }
111    
112 sysadm 1.18 // Allocate shared memory
113     proj_id = ARTICLE_BLOCK_SHM_COUNT_LIMIT; // keep different from proj_id used to create block shm
114     key = ftok(filename, proj_id);
115     if (key == -1)
116     {
117     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
118     return -3;
119     }
120    
121     size = sizeof(ARTICLE_BLOCK_POOL);
122     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
123     if (shmid == -1)
124     {
125     log_error("shmget(article_block_pool_shm, size = %d) error (%d)\n", size, errno);
126     return -3;
127     }
128     p_shm = shmat(shmid, NULL, 0);
129     if (p_shm == (void *)-1)
130 sysadm 1.1 {
131 sysadm 1.18 log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
132     return -3;
133 sysadm 1.1 }
134    
135 sysadm 1.18 article_block_pool_shmid = shmid;
136     p_article_block_pool = p_shm;
137    
138 sysadm 1.7 p_article_block_pool->shm_count = 0;
139     pp_block_next = &(p_article_block_pool->p_block_free_list);
140 sysadm 1.1
141 sysadm 1.7 while (block_count > 0)
142 sysadm 1.1 {
143 sysadm 1.7 block_count_in_shm = MIN(block_count, ARTICLE_BLOCK_PER_SHM);
144     block_count -= block_count_in_shm;
145 sysadm 1.1
146 sysadm 1.18 proj_id = p_article_block_pool->shm_count;
147 sysadm 1.1 key = ftok(filename, proj_id);
148     if (key == -1)
149     {
150     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
151 sysadm 1.7 article_block_cleanup();
152 sysadm 1.1 return -3;
153     }
154    
155 sysadm 1.19 size = sizeof(ARTICLE_BLOCK) * (size_t)block_count_in_shm;
156 sysadm 1.1 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
157     if (shmid == -1)
158     {
159 sysadm 1.7 log_error("shmget(shm_index = %d, size = %d) error (%d)\n", p_article_block_pool->shm_count, size, errno);
160     article_block_cleanup();
161 sysadm 1.1 return -3;
162     }
163     p_shm = shmat(shmid, NULL, 0);
164     if (p_shm == (void *)-1)
165     {
166     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
167 sysadm 1.7 article_block_cleanup();
168 sysadm 1.1 return -3;
169     }
170    
171 sysadm 1.7 (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->shmid = shmid;
172     (p_article_block_pool->shm_pool + p_article_block_pool->shm_count)->p_shm = p_shm;
173     p_article_block_pool->shm_count++;
174 sysadm 1.1
175 sysadm 1.7 p_block_in_shm = p_shm;
176     *pp_block_next = p_block_in_shm;
177 sysadm 1.1
178 sysadm 1.7 for (i = 0; i < block_count_in_shm; i++)
179 sysadm 1.1 {
180 sysadm 1.7 if (i < block_count_in_shm - 1)
181 sysadm 1.1 {
182 sysadm 1.7 (p_block_in_shm + i)->p_next_block = (p_block_in_shm + i + 1);
183 sysadm 1.1 }
184     else
185     {
186 sysadm 1.7 (p_block_in_shm + i)->p_next_block = NULL;
187     pp_block_next = &((p_block_in_shm + i)->p_next_block);
188 sysadm 1.1 }
189     }
190     }
191    
192 sysadm 1.7 p_article_block_pool->block_count = 0;
193    
194 sysadm 1.1 return 0;
195     }
196    
197 sysadm 1.7 void article_block_cleanup(void)
198     {
199 sysadm 1.18 if (p_article_block_pool == NULL)
200     {
201     return;
202     }
203    
204     for (int i = 0; i < p_article_block_pool->shm_count; i++)
205 sysadm 1.7 {
206 sysadm 1.18 if (shmdt((p_article_block_pool->shm_pool + i)->p_shm) == -1)
207 sysadm 1.7 {
208 sysadm 1.18 log_error("shmdt(shmid = %d) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
209     }
210 sysadm 1.7
211 sysadm 1.18 if (shmctl((p_article_block_pool->shm_pool + i)->shmid, IPC_RMID, NULL) == -1)
212     {
213     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", (p_article_block_pool->shm_pool + i)->shmid, errno);
214 sysadm 1.7 }
215 sysadm 1.18 }
216    
217     if (shmdt(p_article_block_pool) == -1)
218     {
219     log_error("shmdt(shmid = %d) error (%d)\n", article_block_pool_shmid, errno);
220     }
221 sysadm 1.7
222 sysadm 1.18 if (shmctl(article_block_pool_shmid, IPC_RMID, NULL) == -1)
223     {
224     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", article_block_pool_shmid, errno);
225 sysadm 1.7 }
226 sysadm 1.18
227     p_article_block_pool = NULL;
228 sysadm 1.7 }
229    
230     inline static ARTICLE_BLOCK *pop_free_article_block(void)
231     {
232     ARTICLE_BLOCK *p_block = NULL;
233    
234     if (p_article_block_pool->p_block_free_list != NULL)
235     {
236     p_block = p_article_block_pool->p_block_free_list;
237     p_article_block_pool->p_block_free_list = p_block->p_next_block;
238     p_block->p_next_block = NULL;
239     p_block->article_count = 0;
240     }
241    
242     return p_block;
243     }
244    
245     inline static void push_free_article_block(ARTICLE_BLOCK *p_block)
246 sysadm 1.1 {
247 sysadm 1.7 p_block->p_next_block = p_article_block_pool->p_block_free_list;
248     p_article_block_pool->p_block_free_list = p_block;
249     }
250    
251     int article_block_reset(void)
252     {
253     ARTICLE_BLOCK *p_block;
254    
255     if (p_article_block_pool == NULL)
256     {
257     log_error("article_block_pool not initialized\n");
258     return -1;
259     }
260 sysadm 1.1
261 sysadm 1.7 while (p_article_block_pool->block_count > 0)
262 sysadm 1.1 {
263 sysadm 1.7 p_article_block_pool->block_count--;
264     p_block = p_article_block_pool->p_block[p_article_block_pool->block_count];
265     push_free_article_block(p_block);
266 sysadm 1.1 }
267    
268 sysadm 1.7 return 0;
269     }
270    
271     ARTICLE *article_block_find_by_aid(int32_t aid)
272     {
273     ARTICLE_BLOCK *p_block;
274     int left;
275     int right;
276     int mid;
277    
278     if (p_article_block_pool == NULL)
279 sysadm 1.1 {
280 sysadm 1.7 log_error("article_block_pool not initialized\n");
281     return NULL;
282 sysadm 1.1 }
283    
284 sysadm 1.7 if (p_article_block_pool->block_count == 0) // empty
285 sysadm 1.1 {
286 sysadm 1.7 return NULL;
287 sysadm 1.1 }
288    
289 sysadm 1.7 left = 0;
290     right = p_article_block_pool->block_count;
291    
292     // aid in the range [ head aid of blocks[left], tail aid of blocks[right - 1] ]
293     while (left < right - 1)
294 sysadm 1.1 {
295 sysadm 1.7 // get block offset no less than mid value of left and right block offsets
296     mid = (left + right) / 2 + (right - left) % 2;
297    
298     if (mid >= p_article_block_pool->block_count)
299 sysadm 1.1 {
300 sysadm 1.7 log_error("block(mid = %d) is out of boundary\n", mid);
301     return NULL;
302     }
303 sysadm 1.1
304 sysadm 1.7 if (aid < p_article_block_pool->p_block[mid]->articles[0].aid)
305     {
306     right = mid;
307     }
308     else
309     {
310     left = mid;
311 sysadm 1.1 }
312 sysadm 1.7 }
313    
314     p_block = p_article_block_pool->p_block[left];
315    
316     left = 0;
317     right = p_block->article_count - 1;
318    
319     // aid in the range [ aid of articles[left], aid of articles[right] ]
320     while (left < right)
321     {
322     mid = (left + right) / 2;
323 sysadm 1.1
324 sysadm 1.7 if (aid <= p_block->articles[mid].aid)
325     {
326     right = mid;
327     }
328     else
329     {
330     left = mid + 1;
331     }
332 sysadm 1.1 }
333 sysadm 1.7
334     return (p_block->articles + left);
335 sysadm 1.1 }
336    
337 sysadm 1.7 ARTICLE *article_block_find_by_index(int index)
338 sysadm 1.1 {
339 sysadm 1.7 ARTICLE_BLOCK *p_block;
340    
341     if (p_article_block_pool == NULL)
342     {
343     log_error("article_block_pool not initialized\n");
344     return NULL;
345     }
346    
347     if (index < 0 || index / ARTICLE_PER_BLOCK >= p_article_block_pool->block_count)
348     {
349 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);
350 sysadm 1.7 return NULL;
351     }
352    
353     p_block = p_article_block_pool->p_block[index / ARTICLE_PER_BLOCK];
354 sysadm 1.1
355 sysadm 1.7 if (index % ARTICLE_PER_BLOCK >= p_block->article_count)
356 sysadm 1.1 {
357 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);
358 sysadm 1.7 return NULL;
359 sysadm 1.1 }
360    
361 sysadm 1.7 return (p_block->articles + (index % ARTICLE_PER_BLOCK));
362 sysadm 1.1 }
363    
364 sysadm 1.19 extern int section_list_init(const char *filename)
365 sysadm 1.1 {
366 sysadm 1.16 int semid;
367 sysadm 1.13 int shmid;
368     int proj_id;
369     key_t key;
370     size_t size;
371     void *p_shm;
372 sysadm 1.17 union semun arg;
373     int i;
374 sysadm 1.13
375 sysadm 1.14 if (p_section_list_pool == NULL || p_trie_dict_section_by_name == NULL || p_trie_dict_section_by_sid == NULL)
376 sysadm 1.13 {
377 sysadm 1.19 section_list_cleanup();
378 sysadm 1.13 }
379 sysadm 1.7
380 sysadm 1.13 proj_id = (int)(time(NULL) % getpid());
381     key = ftok(filename, proj_id);
382     if (key == -1)
383     {
384     log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
385     return -3;
386     }
387 sysadm 1.1
388 sysadm 1.16 size = 2 * (BBS_max_section + 1); // r_sem and w_sem per section, the last pair for all sections
389     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
390     if (semid == -1)
391     {
392 sysadm 1.17 log_error("semget(section_list_pool_sem, size = %d) error (%d)\n", size, errno);
393 sysadm 1.16 return -3;
394     }
395    
396 sysadm 1.17 // Initialize sem value to 0
397     arg.val = 0;
398     for (i = 0; i < size; i++)
399     {
400     if (semctl(semid, i, SETVAL, arg) == -1)
401     {
402     log_error("semctl(section_list_pool_sem, SETVAL) error (%d)\n", errno);
403     return -3;
404     }
405     }
406    
407 sysadm 1.16 section_list_pool_semid = semid;
408    
409 sysadm 1.18 size = sizeof(SECTION_LIST) * BBS_max_section;
410 sysadm 1.13 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
411     if (shmid == -1)
412     {
413 sysadm 1.17 log_error("shmget(section_list_pool_shm, size = %d) error (%d)\n", size, errno);
414 sysadm 1.13 return -3;
415     }
416     p_shm = shmat(shmid, NULL, 0);
417     if (p_shm == (void *)-1)
418     {
419     log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
420     return -3;
421 sysadm 1.7 }
422 sysadm 1.1
423 sysadm 1.13 section_list_pool_shmid = shmid;
424     p_section_list_pool = p_shm;
425     section_list_count = 0;
426    
427 sysadm 1.14 p_trie_dict_section_by_name = trie_dict_create();
428     if (p_trie_dict_section_by_name == NULL)
429     {
430     log_error("trie_dict_create() OOM\n", BBS_max_section);
431     return -2;
432     }
433    
434     p_trie_dict_section_by_sid = trie_dict_create();
435     if (p_trie_dict_section_by_sid == NULL)
436 sysadm 1.1 {
437 sysadm 1.13 log_error("trie_dict_create() OOM\n", BBS_max_section);
438     return -2;
439     }
440    
441     return 0;
442     }
443    
444 sysadm 1.14 inline static void sid_to_str(int32_t sid, char *p_sid_str)
445     {
446     uint32_t u_sid;
447     int i;
448    
449     u_sid = (uint32_t)sid;
450     for (i = 0; i < SID_STR_LEN - 1; i++)
451     {
452     p_sid_str[i] = (char)(u_sid % 255 + 1);
453     u_sid /= 255;
454     }
455     p_sid_str[i] = '\0';
456     }
457    
458 sysadm 1.13 SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_name)
459     {
460     SECTION_LIST *p_section;
461 sysadm 1.14 char sid_str[SID_STR_LEN];
462 sysadm 1.13
463 sysadm 1.14 if (p_section_list_pool == NULL || p_trie_dict_section_by_name == NULL || p_trie_dict_section_by_sid == NULL)
464 sysadm 1.13 {
465     log_error("session_list_pool not initialized\n");
466     return NULL;
467 sysadm 1.1 }
468    
469 sysadm 1.7 if (section_list_count >= BBS_max_section)
470 sysadm 1.1 {
471 sysadm 1.13 log_error("section_list_count exceed limit %d >= %d\n", section_list_count, BBS_max_section);
472 sysadm 1.1 return NULL;
473     }
474    
475 sysadm 1.14 sid_to_str(sid, sid_str);
476    
477 sysadm 1.7 p_section = p_section_list_pool + section_list_count;
478 sysadm 1.1
479 sysadm 1.11 p_section->sid = sid;
480    
481 sysadm 1.1 strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
482     p_section->sname[sizeof(p_section->sname - 1)] = '\0';
483    
484     strncpy(p_section->stitle, stitle, sizeof(p_section->stitle - 1));
485     p_section->stitle[sizeof(p_section->stitle - 1)] = '\0';
486    
487     strncpy(p_section->master_name, master_name, sizeof(p_section->master_name - 1));
488     p_section->master_name[sizeof(p_section->master_name - 1)] = '\0';
489    
490 sysadm 1.14 if (trie_dict_set(p_trie_dict_section_by_name, sname, section_list_count) != 1)
491     {
492     log_error("trie_dict_set(section, %s, %d) error\n", sname, section_list_count);
493     return NULL;
494     }
495    
496     if (trie_dict_set(p_trie_dict_section_by_sid, sid_str, section_list_count) != 1)
497 sysadm 1.1 {
498 sysadm 1.14 log_error("trie_dict_set(section, %d, %d) error\n", sid, section_list_count);
499 sysadm 1.1 return NULL;
500     }
501    
502 sysadm 1.7 section_list_reset_articles(p_section);
503    
504     section_list_count++;
505 sysadm 1.1
506     return p_section;
507     }
508    
509 sysadm 1.7 void section_list_reset_articles(SECTION_LIST *p_section)
510 sysadm 1.1 {
511 sysadm 1.7 p_section->article_count = 0;
512 sysadm 1.8 p_section->topic_count = 0;
513     p_section->visible_article_count = 0;
514     p_section->visible_topic_count = 0;
515 sysadm 1.7 p_section->p_article_head = NULL;
516     p_section->p_article_tail = NULL;
517 sysadm 1.1
518 sysadm 1.7 p_section->page_count = 0;
519 sysadm 1.8 p_section->last_page_visible_article_count = 0;
520 sysadm 1.7 }
521 sysadm 1.1
522 sysadm 1.19 void section_list_cleanup(void)
523 sysadm 1.7 {
524 sysadm 1.14 if (p_trie_dict_section_by_name != NULL)
525 sysadm 1.1 {
526 sysadm 1.14 trie_dict_destroy(p_trie_dict_section_by_name);
527     p_trie_dict_section_by_name = NULL;
528     }
529    
530     if (p_trie_dict_section_by_sid != NULL)
531     {
532     trie_dict_destroy(p_trie_dict_section_by_sid);
533     p_trie_dict_section_by_sid = NULL;
534 sysadm 1.1 }
535    
536 sysadm 1.7 if (p_section_list_pool != NULL)
537 sysadm 1.1 {
538 sysadm 1.13 if (shmdt(p_section_list_pool) == -1)
539     {
540     log_error("shmdt(shmid = %d) error (%d)\n", section_list_pool_shmid, errno);
541     }
542 sysadm 1.7 p_section_list_pool = NULL;
543 sysadm 1.13
544     if (shmctl(section_list_pool_shmid, IPC_RMID, NULL) == -1)
545     {
546     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", section_list_pool_shmid, errno);
547     }
548 sysadm 1.16
549     if (semctl(section_list_pool_semid, 0, IPC_RMID) == -1)
550     {
551     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", section_list_pool_semid, errno);
552     }
553 sysadm 1.1 }
554    
555 sysadm 1.7 section_list_count = 0;
556 sysadm 1.1 }
557    
558 sysadm 1.7 SECTION_LIST *section_list_find_by_name(const char *sname)
559 sysadm 1.1 {
560     int64_t index;
561    
562 sysadm 1.14 if (p_section_list_pool == NULL || p_trie_dict_section_by_name == NULL)
563     {
564     log_error("section_list not initialized\n");
565     return NULL;
566     }
567    
568     if (trie_dict_get(p_trie_dict_section_by_name, sname, &index) != 1)
569     {
570     log_error("trie_dict_get(section, %s) error\n", sname);
571     return NULL;
572     }
573    
574     return (p_section_list_pool + index);
575     }
576    
577     SECTION_LIST *section_list_find_by_sid(int32_t sid)
578     {
579     int64_t index;
580     char sid_str[SID_STR_LEN];
581    
582     if (p_section_list_pool == NULL || p_trie_dict_section_by_sid == NULL)
583 sysadm 1.1 {
584 sysadm 1.7 log_error("section_list not initialized\n");
585 sysadm 1.1 return NULL;
586     }
587    
588 sysadm 1.14 sid_to_str(sid, sid_str);
589    
590     if (trie_dict_get(p_trie_dict_section_by_sid, sid_str, &index) != 1)
591 sysadm 1.1 {
592 sysadm 1.14 log_error("trie_dict_get(section, %d) error\n", sid);
593 sysadm 1.1 return NULL;
594     }
595    
596 sysadm 1.7 return (p_section_list_pool + index);
597 sysadm 1.1 }
598    
599 sysadm 1.7 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
600 sysadm 1.1 {
601     ARTICLE_BLOCK *p_block;
602     int32_t last_aid = 0;
603 sysadm 1.6 ARTICLE *p_article;
604 sysadm 1.1 ARTICLE *p_topic_head;
605     ARTICLE *p_topic_tail;
606    
607 sysadm 1.6 if (p_section == NULL || p_article_src == NULL)
608 sysadm 1.1 {
609 sysadm 1.7 log_error("section_list_append_article() NULL pointer error\n");
610 sysadm 1.1 return -1;
611     }
612    
613 sysadm 1.7 if (p_article_block_pool == NULL)
614 sysadm 1.1 {
615 sysadm 1.7 log_error("article_block_pool not initialized\n");
616 sysadm 1.1 return -1;
617     }
618    
619 sysadm 1.14 if (p_section->sid != p_article_src->sid)
620     {
621     log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
622     return -2;
623     }
624    
625 sysadm 1.9 if (p_section->article_count >= BBS_article_limit_per_section)
626     {
627     log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
628     return -2;
629     }
630    
631 sysadm 1.7 if (p_article_block_pool->block_count == 0 ||
632     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
633 sysadm 1.1 {
634     if ((p_block = pop_free_article_block()) == NULL)
635     {
636     log_error("pop_free_article_block() error\n");
637     return -2;
638     }
639    
640 sysadm 1.7 if (p_article_block_pool->block_count > 0)
641 sysadm 1.1 {
642 sysadm 1.7 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
643 sysadm 1.1 }
644 sysadm 1.7
645     p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
646     p_article_block_pool->block_count++;
647 sysadm 1.1 }
648     else
649     {
650 sysadm 1.7 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
651     last_aid = p_block->articles[p_block->article_count - 1].aid;
652 sysadm 1.1 }
653    
654     // AID of articles should be strictly ascending
655 sysadm 1.6 if (p_article_src->aid <= last_aid)
656 sysadm 1.1 {
657 sysadm 1.14 log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
658 sysadm 1.1 return -3;
659     }
660    
661 sysadm 1.7 p_article = (p_block->articles + p_block->article_count);
662     p_block->article_count++;
663     p_section->article_count++;
664    
665     // Copy article data
666     *p_article = *p_article_src;
667 sysadm 1.1
668 sysadm 1.8 if (p_article->visible)
669     {
670     p_section->visible_article_count++;
671     }
672    
673 sysadm 1.7 // Link appended article as tail node of topic bi-directional list
674     if (p_article->tid != 0)
675 sysadm 1.1 {
676 sysadm 1.7 p_topic_head = article_block_find_by_aid(p_article->tid);
677 sysadm 1.1 if (p_topic_head == NULL)
678     {
679 sysadm 1.7 log_error("search head of topic (aid=%d) error\n", p_article->tid);
680 sysadm 1.1 return -4;
681     }
682    
683 sysadm 1.6 p_topic_tail = p_topic_head->p_topic_prior;
684 sysadm 1.1 if (p_topic_tail == NULL)
685     {
686 sysadm 1.7 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
687 sysadm 1.1 return -4;
688     }
689     }
690     else
691     {
692 sysadm 1.8 p_section->topic_count++;
693    
694     if (p_article->visible)
695     {
696     p_section->visible_topic_count++;
697     }
698    
699 sysadm 1.7 p_topic_head = p_article;
700     p_topic_tail = p_article;
701 sysadm 1.1 }
702    
703 sysadm 1.7 p_article->p_topic_prior = p_topic_tail;
704     p_article->p_topic_next = p_topic_head;
705     p_topic_head->p_topic_prior = p_article;
706     p_topic_tail->p_topic_next = p_article;
707 sysadm 1.1
708 sysadm 1.6 // Link appended article as tail node of article bi-directional list
709     if (p_section->p_article_head == NULL)
710     {
711     p_section->p_article_head = p_article;
712     p_section->p_article_tail = p_article;
713     }
714     p_article->p_prior = p_section->p_article_tail;
715     p_article->p_next = p_section->p_article_head;
716     p_section->p_article_head->p_prior = p_article;
717     p_section->p_article_tail->p_next = p_article;
718     p_section->p_article_tail = p_article;
719    
720 sysadm 1.7 // Update page
721 sysadm 1.11 if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
722     p_section->article_count == 1)
723 sysadm 1.1 {
724 sysadm 1.7 p_section->p_page_first_article[p_section->page_count] = p_article;
725     p_section->page_count++;
726 sysadm 1.8 p_section->last_page_visible_article_count = 0;
727 sysadm 1.1 }
728 sysadm 1.9
729     if (p_article->visible)
730     {
731     p_section->last_page_visible_article_count++;
732     }
733 sysadm 1.1
734 sysadm 1.7 return 0;
735 sysadm 1.2 }
736    
737 sysadm 1.7 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
738 sysadm 1.1 {
739     ARTICLE *p_article;
740 sysadm 1.8 ARTICLE *p_reply;
741     int affected_count = 0;
742 sysadm 1.1
743 sysadm 1.2 if (p_section == NULL)
744     {
745 sysadm 1.7 log_error("section_list_set_article_visible() NULL pointer error\n");
746 sysadm 1.2 return -2;
747     }
748    
749 sysadm 1.7 p_article = article_block_find_by_aid(aid);
750 sysadm 1.1 if (p_article == NULL)
751     {
752     return -1; // Not found
753     }
754    
755 sysadm 1.14 if (p_section->sid != p_article->sid)
756     {
757     log_error("section_list_set_article_visible() error: section sid %d != article sid %d\n", p_section->sid, p_article->sid);
758     return -2;
759     }
760    
761 sysadm 1.7 if (p_article->visible == visible)
762 sysadm 1.1 {
763 sysadm 1.7 return 0; // Already set
764 sysadm 1.1 }
765    
766 sysadm 1.8 if (visible == 0) // 1 -> 0
767     {
768     p_section->visible_article_count--;
769    
770     if (p_article->tid == 0)
771     {
772     p_section->visible_topic_count--;
773    
774     // Set related visible replies to invisible
775     for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
776     {
777     if (p_reply->tid != aid)
778     {
779     log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
780     continue;
781     }
782    
783     if (p_reply->visible == 1)
784     {
785     p_reply->visible = 0;
786     p_section->visible_article_count--;
787     affected_count++;
788     }
789     }
790     }
791     }
792     else // 0 -> 1
793     {
794     p_section->visible_article_count++;
795    
796     if (p_article->tid == 0)
797     {
798     p_section->visible_topic_count++;
799     }
800     }
801    
802 sysadm 1.7 p_article->visible = visible;
803 sysadm 1.8 affected_count++;
804    
805     return affected_count;
806     }
807    
808 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)
809 sysadm 1.8 {
810     ARTICLE *p_article;
811     int left;
812     int right;
813     int mid;
814    
815     *p_page = -1;
816     *p_offset = -1;
817 sysadm 1.11 *pp_next = NULL;
818 sysadm 1.8
819     if (p_section == NULL)
820     {
821     log_error("section_list_find_article_with_offset() NULL pointer error\n");
822     return NULL;
823     }
824 sysadm 1.7
825 sysadm 1.8 if (p_section->article_count == 0) // empty
826     {
827     *p_page = 0;
828     *p_offset = 0;
829     return NULL;
830     }
831    
832     left = 0;
833     right = p_section->page_count;
834    
835     // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
836     while (left < right - 1)
837     {
838     // get page id no less than mid value of left page id and right page id
839     mid = (left + right) / 2 + (right - left) % 2;
840 sysadm 1.1
841 sysadm 1.8 if (mid >= p_section->page_count)
842     {
843     log_error("page id (mid = %d) is out of boundary\n", mid);
844     return NULL;
845     }
846    
847     if (aid < p_section->p_page_first_article[mid]->aid)
848     {
849     right = mid;
850     }
851     else
852     {
853     left = mid;
854     }
855     }
856    
857     *p_page = left;
858    
859     p_article = p_section->p_page_first_article[*p_page];
860    
861     // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
862 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);
863 sysadm 1.8
864     // left will be the offset of article found or offset to insert
865     left = 0;
866    
867 sysadm 1.10 while (aid > p_article->aid)
868 sysadm 1.8 {
869     p_article = p_article->p_next;
870     left++;
871    
872 sysadm 1.11 if (aid == p_article->aid)
873     {
874     *pp_next = p_article->p_next;
875     break;
876     }
877    
878 sysadm 1.8 // over last article in the page
879     if (p_article == p_section->p_article_head || p_article->aid >= right)
880     {
881 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]);
882     *p_offset = left;
883     return NULL; // not found
884 sysadm 1.8 }
885     }
886    
887 sysadm 1.11 if (aid < p_article->aid)
888     {
889     *pp_next = p_article;
890     p_article = NULL; // not found
891     }
892     else // aid == p_article->aid
893 sysadm 1.10 {
894 sysadm 1.11 *pp_next = p_article->p_next;
895 sysadm 1.10 }
896    
897 sysadm 1.8 *p_offset = left;
898    
899     return p_article;
900     }
901    
902     int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
903     {
904 sysadm 1.9 ARTICLE *p_article;
905 sysadm 1.11 ARTICLE *p_next;
906 sysadm 1.9 int32_t page;
907     int32_t offset;
908     int visible_article_count;
909     int page_head_set;
910 sysadm 1.8
911     if (p_section == NULL)
912     {
913     log_error("section_list_calculate_page() NULL pointer error\n");
914     return -1;
915     }
916    
917 sysadm 1.11 if (p_section->article_count == 0) // empty
918     {
919     p_section->page_count = 0;
920     p_section->last_page_visible_article_count = 0;
921    
922     return 0;
923     }
924    
925     if (start_aid > 0)
926 sysadm 1.9 {
927 sysadm 1.14 p_article = article_block_find_by_aid(start_aid);
928     if (p_article == NULL)
929     {
930     return -1; // Not found
931     }
932    
933     if (p_section->sid != p_article->sid)
934     {
935     log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
936     return -2;
937     }
938    
939 sysadm 1.11 p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
940     if (p_article == NULL)
941 sysadm 1.9 {
942 sysadm 1.11 if (page < 0)
943     {
944     return -1;
945     }
946     log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
947     start_aid, p_section->sid);
948     return -2;
949 sysadm 1.9 }
950    
951 sysadm 1.11 if (offset > 0)
952     {
953     p_article = p_section->p_page_first_article[page];
954     }
955 sysadm 1.9 }
956 sysadm 1.11 else
957 sysadm 1.9 {
958 sysadm 1.11 p_article = p_section->p_article_head;
959     page = 0;
960     offset = 0;
961 sysadm 1.9 }
962    
963     visible_article_count = 0;
964     page_head_set = 0;
965    
966     do
967     {
968     if (!page_head_set && visible_article_count == 0)
969     {
970     p_section->p_page_first_article[page] = p_article;
971     page_head_set = 1;
972     }
973    
974     if (p_article->visible)
975     {
976     visible_article_count++;
977     }
978    
979     p_article = p_article->p_next;
980    
981     // skip remaining invisible articles
982     while (p_article->visible == 0 && p_article != p_section->p_article_head)
983     {
984     p_article = p_article->p_next;
985     }
986    
987     if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
988     {
989     page++;
990     visible_article_count = 0;
991     page_head_set = 0;
992    
993     if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
994     {
995     log_error("Count of page exceed limit in section %d\n", p_section->sid);
996     break;
997     }
998     }
999     } while (p_article != p_section->p_article_head);
1000    
1001     p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1002     p_section->last_page_visible_article_count = visible_article_count;
1003    
1004 sysadm 1.8 return 0;
1005 sysadm 1.1 }
1006 sysadm 1.11
1007 sysadm 1.14 int article_count_of_topic(int32_t aid)
1008 sysadm 1.11 {
1009     ARTICLE *p_article;
1010     int article_count;
1011    
1012     p_article = article_block_find_by_aid(aid);
1013     if (p_article == NULL)
1014     {
1015     return 0; // Not found
1016     }
1017    
1018     article_count = 0;
1019    
1020     do
1021     {
1022 sysadm 1.15 if (p_article->tid != 0 && p_article->tid != aid)
1023     {
1024     log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1025     break;
1026     }
1027    
1028 sysadm 1.11 article_count++;
1029     p_article = p_article->p_topic_next;
1030     } while (p_article->aid != aid);
1031    
1032     return article_count;
1033     }
1034    
1035     int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1036     {
1037     ARTICLE *p_article;
1038     ARTICLE *p_next;
1039     int32_t page;
1040     int32_t offset;
1041     int32_t move_article_count;
1042     int32_t dest_article_count_old;
1043     int32_t last_unaffected_aid_src;
1044 sysadm 1.12 int32_t first_inserted_aid_dest;
1045     int move_counter;
1046 sysadm 1.11
1047     if (p_section_dest == NULL)
1048     {
1049     log_error("section_list_move_topic() NULL pointer error\n");
1050     return -1;
1051     }
1052    
1053 sysadm 1.14 if ((p_article = article_block_find_by_aid(aid)) == NULL)
1054 sysadm 1.11 {
1055 sysadm 1.14 log_error("section_list_move_topic() error: article %d not found in block\n", aid);
1056     return -2;
1057     }
1058    
1059     if (p_section_src->sid != p_article->sid)
1060     {
1061     log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1062     p_section_src->sid, p_article->aid, p_article->sid);
1063 sysadm 1.11 return -2;
1064     }
1065    
1066     if (p_article->tid != 0)
1067     {
1068     log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1069     return -2;
1070     }
1071    
1072     last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1073    
1074 sysadm 1.14 move_article_count = article_count_of_topic(aid);
1075 sysadm 1.11 if (move_article_count <= 0)
1076     {
1077     log_error("section_list_count_of_topic_articles(aid = %d) <= 0\n", aid);
1078     return -2;
1079     }
1080    
1081     if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1082     {
1083     log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1084     p_section_dest->article_count + move_article_count, p_section_dest->sid);
1085     return -3;
1086     }
1087    
1088     dest_article_count_old = p_section_dest->article_count;
1089 sysadm 1.12 move_counter = 0;
1090     first_inserted_aid_dest = p_article->aid;
1091 sysadm 1.11
1092     do
1093     {
1094 sysadm 1.14 if (p_section_src->sid != p_article->sid)
1095 sysadm 1.11 {
1096 sysadm 1.14 log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1097     p_section_src->sid, p_article->aid, p_article->sid);
1098     return -2;
1099 sysadm 1.11 }
1100    
1101     // Remove from bi-directional article list of src section
1102     if (p_section_src->p_article_head == p_article)
1103     {
1104     p_section_src->p_article_head = p_article->p_next;
1105     }
1106     if (p_section_src->p_article_tail == p_article)
1107     {
1108     p_section_src->p_article_tail = p_article->p_prior;
1109     }
1110     if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1111     {
1112     p_section_src->p_article_head = NULL;
1113     p_section_src->p_article_tail = NULL;
1114     }
1115    
1116     p_article->p_prior->p_next = p_article->p_next;
1117     p_article->p_next->p_prior = p_article->p_prior;
1118    
1119 sysadm 1.14 // Update sid of article
1120     p_article->sid = p_section_dest->sid;
1121    
1122     if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1123     {
1124     log_error("section_list_move_topic() error: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1125     return -4;
1126     }
1127    
1128 sysadm 1.11 // Insert into bi-directional article list of dest section
1129     if (p_next == NULL) // empty section
1130     {
1131     p_section_dest->p_article_head = p_article;
1132     p_section_dest->p_article_tail = p_article;
1133     p_article->p_prior = p_article;
1134     p_article->p_next = p_article;
1135     }
1136     else
1137     {
1138     if (p_section_dest->p_article_head == p_next)
1139     {
1140     if (p_article->aid < p_next->aid)
1141     {
1142     p_section_dest->p_article_head = p_article;
1143     }
1144     else // p_article->aid > p_next->aid
1145     {
1146     p_section_dest->p_article_tail = p_article;
1147     }
1148     }
1149    
1150     p_article->p_prior = p_next->p_prior;
1151     p_article->p_next = p_next;
1152     p_next->p_prior->p_next = p_article;
1153     p_next->p_prior = p_article;
1154     }
1155    
1156     // Update article / topic counter of src / desc section
1157     p_section_src->article_count--;
1158     p_section_dest->article_count++;
1159     if (p_article->tid == 0)
1160     {
1161     p_section_src->topic_count--;
1162     p_section_dest->topic_count++;
1163     }
1164    
1165     // Update visible article / topic counter of src / desc section
1166     if (p_article->visible)
1167     {
1168     p_section_src->visible_article_count--;
1169     p_section_dest->visible_article_count++;
1170     if (p_article->tid == 0)
1171     {
1172     p_section_src->visible_topic_count--;
1173     p_section_dest->visible_topic_count++;
1174     }
1175     }
1176    
1177     // Update page for empty dest section
1178     if (p_section_dest->article_count == 1)
1179     {
1180     p_section_dest->p_page_first_article[0] = p_article;
1181     p_section_dest->page_count = 1;
1182     p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1183     }
1184    
1185     p_article = p_article->p_topic_next;
1186 sysadm 1.12
1187     move_counter++;
1188     if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1189     {
1190     // Re-calculate pages of desc section
1191     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1192     {
1193 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1194 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1195     }
1196    
1197     first_inserted_aid_dest = p_article->aid;
1198     }
1199 sysadm 1.11 } while (p_article->aid != aid);
1200    
1201     if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1202     {
1203     log_error("section_list_move_topic() error: count of moved articles %d != %d\n",
1204     p_section_dest->article_count - dest_article_count_old, move_article_count);
1205     }
1206    
1207 sysadm 1.12 // Re-calculate pages of src section
1208 sysadm 1.11 if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1209     {
1210 sysadm 1.14 log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1211 sysadm 1.12 p_section_src->sid, last_unaffected_aid_src, aid);
1212 sysadm 1.11 }
1213 sysadm 1.12
1214     if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1215 sysadm 1.11 {
1216 sysadm 1.12 // Re-calculate pages of desc section
1217     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1218     {
1219 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1220 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1221     }
1222 sysadm 1.11 }
1223    
1224     return move_article_count;
1225     }
1226 sysadm 1.16
1227     int get_section_index(SECTION_LIST *p_section)
1228     {
1229     int index;
1230    
1231     if (p_section_list_pool == NULL)
1232     {
1233     log_error("get_section_index() error: uninitialized\n");
1234     return -1;
1235     }
1236    
1237     if (p_section == NULL)
1238     {
1239     index = BBS_max_section;
1240     }
1241     else
1242     {
1243     index = (int)(p_section - p_section_list_pool);
1244     if (index < 0 || index >= BBS_max_section)
1245     {
1246     log_error("get_section_index(%d) error: index out of range\n", index);
1247     return -2;
1248     }
1249     }
1250    
1251     return index;
1252     }
1253    
1254     int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1255     {
1256     int index;
1257 sysadm 1.17 struct sembuf sops[4];
1258 sysadm 1.16 struct timespec timeout;
1259     int ret;
1260    
1261     index = get_section_index(p_section);
1262     if (index < 0)
1263     {
1264     return -2;
1265     }
1266    
1267 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1268     sops[0].sem_op = 0; // wait until unlocked
1269 sysadm 1.16 sops[0].sem_flg = 0;
1270    
1271 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1272     sops[1].sem_op = 1; // lock
1273     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1274    
1275     // Read lock on any specific section will also acquire single read lock on "all section"
1276     // so that write lock on all section only need to acquire single write on on "all section"
1277     // rather than to acquire multiple write locks on all the available sections.
1278     if (index == BBS_max_section)
1279     {
1280     sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1281     sops[2].sem_op = 0; // wait until unlocked
1282     sops[2].sem_flg = 0;
1283    
1284     sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1285     sops[3].sem_op = 1; // lock
1286     sops[3].sem_flg = SEM_UNDO; // undo on terminate
1287     }
1288 sysadm 1.16
1289     timeout.tv_sec = wait_sec;
1290     timeout.tv_nsec = 0;
1291    
1292 sysadm 1.17 ret = semtimedop(section_list_pool_semid, sops, (index == BBS_max_section ? 4 : 2), &timeout);
1293     if (ret == -1 && errno != EAGAIN && errno != EINTR)
1294     {
1295     log_error("semtimedop(index = %d, lock read) error %d\n", index, errno);
1296     }
1297 sysadm 1.16
1298     return ret;
1299     }
1300    
1301     int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1302     {
1303     int index;
1304     struct sembuf sops[3];
1305     struct timespec timeout;
1306     int ret;
1307    
1308     index = get_section_index(p_section);
1309     if (index < 0)
1310     {
1311     return -2;
1312     }
1313    
1314 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1315     sops[0].sem_op = 0; // wait until unlocked
1316 sysadm 1.16 sops[0].sem_flg = 0;
1317    
1318 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1319     sops[1].sem_op = 1; // lock
1320     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1321    
1322     sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1323     sops[2].sem_op = 0; // wait until unlocked
1324     sops[2].sem_flg = 0;
1325 sysadm 1.16
1326     timeout.tv_sec = wait_sec;
1327     timeout.tv_nsec = 0;
1328    
1329     ret = semtimedop(section_list_pool_semid, sops, 3, &timeout);
1330 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1331     {
1332     log_error("semtimedop(index = %d, lock write) error %d\n", index, errno);
1333     }
1334 sysadm 1.16
1335     return ret;
1336     }
1337    
1338     int section_list_rd_unlock(SECTION_LIST *p_section)
1339     {
1340     int index;
1341 sysadm 1.17 struct sembuf sops[2];
1342 sysadm 1.16 int ret;
1343    
1344     index = get_section_index(p_section);
1345     if (index < 0)
1346     {
1347     return -2;
1348     }
1349    
1350 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1351     sops[0].sem_op = -1; // unlock
1352     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1353 sysadm 1.16
1354 sysadm 1.17 // The same reason as section_list_try_rd_lock()
1355     if (index == BBS_max_section)
1356     {
1357     sops[1].sem_num = BBS_max_section * 2; // r_sem of all section
1358     sops[1].sem_op = -1; // unlock
1359     sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1360     }
1361    
1362     ret = semop(section_list_pool_semid, sops, (index == BBS_max_section ? 2 : 1));
1363     if (ret == -1 && errno != EAGAIN && errno != EINTR)
1364     {
1365     log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1366     }
1367 sysadm 1.16
1368     return ret;
1369     }
1370    
1371     int section_list_rw_unlock(SECTION_LIST *p_section)
1372     {
1373     int index;
1374     struct sembuf sops[1];
1375     int ret;
1376    
1377     index = get_section_index(p_section);
1378     if (index < 0)
1379     {
1380     return -2;
1381     }
1382    
1383 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1384     sops[0].sem_op = -1; // unlock
1385     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1386 sysadm 1.16
1387     ret = semop(section_list_pool_semid, sops, 1);
1388 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1389     {
1390     log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1391     }
1392 sysadm 1.16
1393     return ret;
1394     }

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