/[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.18 - (hide annotations)
Sat May 24 15:18:11 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.17: +52 -28 lines
Content type: text/x-csrc
Move p_article_block_pool to SHM

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.7 size = sizeof(shmid) + 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.13 extern int section_list_pool_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     section_list_pool_cleanup();
378     }
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     log_std("Debug %x %x %x %x\n", sid_str[0], sid_str[1], sid_str[2], sid_str[3]);
500 sysadm 1.1 return NULL;
501     }
502    
503 sysadm 1.7 section_list_reset_articles(p_section);
504    
505     section_list_count++;
506 sysadm 1.1
507     return p_section;
508     }
509    
510 sysadm 1.7 void section_list_reset_articles(SECTION_LIST *p_section)
511 sysadm 1.1 {
512 sysadm 1.7 p_section->article_count = 0;
513 sysadm 1.8 p_section->topic_count = 0;
514     p_section->visible_article_count = 0;
515     p_section->visible_topic_count = 0;
516 sysadm 1.7 p_section->p_article_head = NULL;
517     p_section->p_article_tail = NULL;
518 sysadm 1.1
519 sysadm 1.7 p_section->page_count = 0;
520 sysadm 1.8 p_section->last_page_visible_article_count = 0;
521 sysadm 1.7 }
522 sysadm 1.1
523 sysadm 1.13 void section_list_pool_cleanup(void)
524 sysadm 1.7 {
525 sysadm 1.14 if (p_trie_dict_section_by_name != NULL)
526 sysadm 1.1 {
527 sysadm 1.14 trie_dict_destroy(p_trie_dict_section_by_name);
528     p_trie_dict_section_by_name = NULL;
529     }
530    
531     if (p_trie_dict_section_by_sid != NULL)
532     {
533     trie_dict_destroy(p_trie_dict_section_by_sid);
534     p_trie_dict_section_by_sid = NULL;
535 sysadm 1.1 }
536    
537 sysadm 1.7 if (p_section_list_pool != NULL)
538 sysadm 1.1 {
539 sysadm 1.13 if (shmdt(p_section_list_pool) == -1)
540     {
541     log_error("shmdt(shmid = %d) error (%d)\n", section_list_pool_shmid, errno);
542     }
543 sysadm 1.7 p_section_list_pool = NULL;
544 sysadm 1.13
545     if (shmctl(section_list_pool_shmid, IPC_RMID, NULL) == -1)
546     {
547     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", section_list_pool_shmid, errno);
548     }
549 sysadm 1.16
550     if (semctl(section_list_pool_semid, 0, IPC_RMID) == -1)
551     {
552     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", section_list_pool_semid, errno);
553     }
554 sysadm 1.1 }
555    
556 sysadm 1.7 section_list_count = 0;
557 sysadm 1.1 }
558    
559 sysadm 1.7 SECTION_LIST *section_list_find_by_name(const char *sname)
560 sysadm 1.1 {
561     int64_t index;
562    
563 sysadm 1.14 if (p_section_list_pool == NULL || p_trie_dict_section_by_name == NULL)
564     {
565     log_error("section_list not initialized\n");
566     return NULL;
567     }
568    
569     if (trie_dict_get(p_trie_dict_section_by_name, sname, &index) != 1)
570     {
571     log_error("trie_dict_get(section, %s) error\n", sname);
572     return NULL;
573     }
574    
575     return (p_section_list_pool + index);
576     }
577    
578     SECTION_LIST *section_list_find_by_sid(int32_t sid)
579     {
580     int64_t index;
581     char sid_str[SID_STR_LEN];
582    
583     if (p_section_list_pool == NULL || p_trie_dict_section_by_sid == NULL)
584 sysadm 1.1 {
585 sysadm 1.7 log_error("section_list not initialized\n");
586 sysadm 1.1 return NULL;
587     }
588    
589 sysadm 1.14 sid_to_str(sid, sid_str);
590    
591     if (trie_dict_get(p_trie_dict_section_by_sid, sid_str, &index) != 1)
592 sysadm 1.1 {
593 sysadm 1.14 log_error("trie_dict_get(section, %d) error\n", sid);
594 sysadm 1.1 return NULL;
595     }
596    
597 sysadm 1.7 return (p_section_list_pool + index);
598 sysadm 1.1 }
599    
600 sysadm 1.7 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
601 sysadm 1.1 {
602     ARTICLE_BLOCK *p_block;
603     int32_t last_aid = 0;
604 sysadm 1.6 ARTICLE *p_article;
605 sysadm 1.1 ARTICLE *p_topic_head;
606     ARTICLE *p_topic_tail;
607    
608 sysadm 1.6 if (p_section == NULL || p_article_src == NULL)
609 sysadm 1.1 {
610 sysadm 1.7 log_error("section_list_append_article() NULL pointer error\n");
611 sysadm 1.1 return -1;
612     }
613    
614 sysadm 1.7 if (p_article_block_pool == NULL)
615 sysadm 1.1 {
616 sysadm 1.7 log_error("article_block_pool not initialized\n");
617 sysadm 1.1 return -1;
618     }
619    
620 sysadm 1.14 if (p_section->sid != p_article_src->sid)
621     {
622     log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
623     return -2;
624     }
625    
626 sysadm 1.9 if (p_section->article_count >= BBS_article_limit_per_section)
627     {
628     log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
629     return -2;
630     }
631    
632 sysadm 1.7 if (p_article_block_pool->block_count == 0 ||
633     p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
634 sysadm 1.1 {
635     if ((p_block = pop_free_article_block()) == NULL)
636     {
637     log_error("pop_free_article_block() error\n");
638     return -2;
639     }
640    
641 sysadm 1.7 if (p_article_block_pool->block_count > 0)
642 sysadm 1.1 {
643 sysadm 1.7 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
644 sysadm 1.1 }
645 sysadm 1.7
646     p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
647     p_article_block_pool->block_count++;
648 sysadm 1.1 }
649     else
650     {
651 sysadm 1.7 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
652     last_aid = p_block->articles[p_block->article_count - 1].aid;
653 sysadm 1.1 }
654    
655     // AID of articles should be strictly ascending
656 sysadm 1.6 if (p_article_src->aid <= last_aid)
657 sysadm 1.1 {
658 sysadm 1.14 log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
659 sysadm 1.1 return -3;
660     }
661    
662 sysadm 1.7 p_article = (p_block->articles + p_block->article_count);
663     p_block->article_count++;
664     p_section->article_count++;
665    
666     // Copy article data
667     *p_article = *p_article_src;
668 sysadm 1.1
669 sysadm 1.8 if (p_article->visible)
670     {
671     p_section->visible_article_count++;
672     }
673    
674 sysadm 1.7 // Link appended article as tail node of topic bi-directional list
675     if (p_article->tid != 0)
676 sysadm 1.1 {
677 sysadm 1.7 p_topic_head = article_block_find_by_aid(p_article->tid);
678 sysadm 1.1 if (p_topic_head == NULL)
679     {
680 sysadm 1.7 log_error("search head of topic (aid=%d) error\n", p_article->tid);
681 sysadm 1.1 return -4;
682     }
683    
684 sysadm 1.6 p_topic_tail = p_topic_head->p_topic_prior;
685 sysadm 1.1 if (p_topic_tail == NULL)
686     {
687 sysadm 1.7 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
688 sysadm 1.1 return -4;
689     }
690     }
691     else
692     {
693 sysadm 1.8 p_section->topic_count++;
694    
695     if (p_article->visible)
696     {
697     p_section->visible_topic_count++;
698     }
699    
700 sysadm 1.7 p_topic_head = p_article;
701     p_topic_tail = p_article;
702 sysadm 1.1 }
703    
704 sysadm 1.7 p_article->p_topic_prior = p_topic_tail;
705     p_article->p_topic_next = p_topic_head;
706     p_topic_head->p_topic_prior = p_article;
707     p_topic_tail->p_topic_next = p_article;
708 sysadm 1.1
709 sysadm 1.6 // Link appended article as tail node of article bi-directional list
710     if (p_section->p_article_head == NULL)
711     {
712     p_section->p_article_head = p_article;
713     p_section->p_article_tail = p_article;
714     }
715     p_article->p_prior = p_section->p_article_tail;
716     p_article->p_next = p_section->p_article_head;
717     p_section->p_article_head->p_prior = p_article;
718     p_section->p_article_tail->p_next = p_article;
719     p_section->p_article_tail = p_article;
720    
721 sysadm 1.7 // Update page
722 sysadm 1.11 if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
723     p_section->article_count == 1)
724 sysadm 1.1 {
725 sysadm 1.7 p_section->p_page_first_article[p_section->page_count] = p_article;
726     p_section->page_count++;
727 sysadm 1.8 p_section->last_page_visible_article_count = 0;
728 sysadm 1.1 }
729 sysadm 1.9
730     if (p_article->visible)
731     {
732     p_section->last_page_visible_article_count++;
733     }
734 sysadm 1.1
735 sysadm 1.7 return 0;
736 sysadm 1.2 }
737    
738 sysadm 1.7 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
739 sysadm 1.1 {
740     ARTICLE *p_article;
741 sysadm 1.8 ARTICLE *p_reply;
742     int affected_count = 0;
743 sysadm 1.1
744 sysadm 1.2 if (p_section == NULL)
745     {
746 sysadm 1.7 log_error("section_list_set_article_visible() NULL pointer error\n");
747 sysadm 1.2 return -2;
748     }
749    
750 sysadm 1.7 p_article = article_block_find_by_aid(aid);
751 sysadm 1.1 if (p_article == NULL)
752     {
753     return -1; // Not found
754     }
755    
756 sysadm 1.14 if (p_section->sid != p_article->sid)
757     {
758     log_error("section_list_set_article_visible() error: section sid %d != article sid %d\n", p_section->sid, p_article->sid);
759     return -2;
760     }
761    
762 sysadm 1.7 if (p_article->visible == visible)
763 sysadm 1.1 {
764 sysadm 1.7 return 0; // Already set
765 sysadm 1.1 }
766    
767 sysadm 1.8 if (visible == 0) // 1 -> 0
768     {
769     p_section->visible_article_count--;
770    
771     if (p_article->tid == 0)
772     {
773     p_section->visible_topic_count--;
774    
775     // Set related visible replies to invisible
776     for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
777     {
778     if (p_reply->tid != aid)
779     {
780     log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
781     continue;
782     }
783    
784     if (p_reply->visible == 1)
785     {
786     p_reply->visible = 0;
787     p_section->visible_article_count--;
788     affected_count++;
789     }
790     }
791     }
792     }
793     else // 0 -> 1
794     {
795     p_section->visible_article_count++;
796    
797     if (p_article->tid == 0)
798     {
799     p_section->visible_topic_count++;
800     }
801     }
802    
803 sysadm 1.7 p_article->visible = visible;
804 sysadm 1.8 affected_count++;
805    
806     return affected_count;
807     }
808    
809 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)
810 sysadm 1.8 {
811     ARTICLE *p_article;
812     int left;
813     int right;
814     int mid;
815    
816     *p_page = -1;
817     *p_offset = -1;
818 sysadm 1.11 *pp_next = NULL;
819 sysadm 1.8
820     if (p_section == NULL)
821     {
822     log_error("section_list_find_article_with_offset() NULL pointer error\n");
823     return NULL;
824     }
825 sysadm 1.7
826 sysadm 1.8 if (p_section->article_count == 0) // empty
827     {
828     *p_page = 0;
829     *p_offset = 0;
830     return NULL;
831     }
832    
833     left = 0;
834     right = p_section->page_count;
835    
836     // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
837     while (left < right - 1)
838     {
839     // get page id no less than mid value of left page id and right page id
840     mid = (left + right) / 2 + (right - left) % 2;
841 sysadm 1.1
842 sysadm 1.8 if (mid >= p_section->page_count)
843     {
844     log_error("page id (mid = %d) is out of boundary\n", mid);
845     return NULL;
846     }
847    
848     if (aid < p_section->p_page_first_article[mid]->aid)
849     {
850     right = mid;
851     }
852     else
853     {
854     left = mid;
855     }
856     }
857    
858     *p_page = left;
859    
860     p_article = p_section->p_page_first_article[*p_page];
861    
862     // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
863 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);
864 sysadm 1.8
865     // left will be the offset of article found or offset to insert
866     left = 0;
867    
868 sysadm 1.10 while (aid > p_article->aid)
869 sysadm 1.8 {
870     p_article = p_article->p_next;
871     left++;
872    
873 sysadm 1.11 if (aid == p_article->aid)
874     {
875     *pp_next = p_article->p_next;
876     break;
877     }
878    
879 sysadm 1.8 // over last article in the page
880     if (p_article == p_section->p_article_head || p_article->aid >= right)
881     {
882 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]);
883     *p_offset = left;
884     return NULL; // not found
885 sysadm 1.8 }
886     }
887    
888 sysadm 1.11 if (aid < p_article->aid)
889     {
890     *pp_next = p_article;
891     p_article = NULL; // not found
892     }
893     else // aid == p_article->aid
894 sysadm 1.10 {
895 sysadm 1.11 *pp_next = p_article->p_next;
896 sysadm 1.10 }
897    
898 sysadm 1.8 *p_offset = left;
899    
900     return p_article;
901     }
902    
903     int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
904     {
905 sysadm 1.9 ARTICLE *p_article;
906 sysadm 1.11 ARTICLE *p_next;
907 sysadm 1.9 int32_t page;
908     int32_t offset;
909     int visible_article_count;
910     int page_head_set;
911 sysadm 1.8
912     if (p_section == NULL)
913     {
914     log_error("section_list_calculate_page() NULL pointer error\n");
915     return -1;
916     }
917    
918 sysadm 1.11 if (p_section->article_count == 0) // empty
919     {
920     p_section->page_count = 0;
921     p_section->last_page_visible_article_count = 0;
922    
923     return 0;
924     }
925    
926     if (start_aid > 0)
927 sysadm 1.9 {
928 sysadm 1.14 p_article = article_block_find_by_aid(start_aid);
929     if (p_article == NULL)
930     {
931     return -1; // Not found
932     }
933    
934     if (p_section->sid != p_article->sid)
935     {
936     log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
937     return -2;
938     }
939    
940 sysadm 1.11 p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
941     if (p_article == NULL)
942 sysadm 1.9 {
943 sysadm 1.11 if (page < 0)
944     {
945     return -1;
946     }
947     log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
948     start_aid, p_section->sid);
949     return -2;
950 sysadm 1.9 }
951    
952 sysadm 1.11 if (offset > 0)
953     {
954     p_article = p_section->p_page_first_article[page];
955     }
956 sysadm 1.9 }
957 sysadm 1.11 else
958 sysadm 1.9 {
959 sysadm 1.11 p_article = p_section->p_article_head;
960     page = 0;
961     offset = 0;
962 sysadm 1.9 }
963    
964     visible_article_count = 0;
965     page_head_set = 0;
966    
967     do
968     {
969     if (!page_head_set && visible_article_count == 0)
970     {
971     p_section->p_page_first_article[page] = p_article;
972     page_head_set = 1;
973     }
974    
975     if (p_article->visible)
976     {
977     visible_article_count++;
978     }
979    
980     p_article = p_article->p_next;
981    
982     // skip remaining invisible articles
983     while (p_article->visible == 0 && p_article != p_section->p_article_head)
984     {
985     p_article = p_article->p_next;
986     }
987    
988     if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
989     {
990     page++;
991     visible_article_count = 0;
992     page_head_set = 0;
993    
994     if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
995     {
996     log_error("Count of page exceed limit in section %d\n", p_section->sid);
997     break;
998     }
999     }
1000     } while (p_article != p_section->p_article_head);
1001    
1002     p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1003     p_section->last_page_visible_article_count = visible_article_count;
1004    
1005 sysadm 1.8 return 0;
1006 sysadm 1.1 }
1007 sysadm 1.11
1008 sysadm 1.14 int article_count_of_topic(int32_t aid)
1009 sysadm 1.11 {
1010     ARTICLE *p_article;
1011     int article_count;
1012    
1013     p_article = article_block_find_by_aid(aid);
1014     if (p_article == NULL)
1015     {
1016     return 0; // Not found
1017     }
1018    
1019     article_count = 0;
1020    
1021     do
1022     {
1023 sysadm 1.15 if (p_article->tid != 0 && p_article->tid != aid)
1024     {
1025     log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1026     break;
1027     }
1028    
1029 sysadm 1.11 article_count++;
1030     p_article = p_article->p_topic_next;
1031     } while (p_article->aid != aid);
1032    
1033     return article_count;
1034     }
1035    
1036     int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1037     {
1038     ARTICLE *p_article;
1039     ARTICLE *p_next;
1040     int32_t page;
1041     int32_t offset;
1042     int32_t move_article_count;
1043     int32_t dest_article_count_old;
1044     int32_t last_unaffected_aid_src;
1045 sysadm 1.12 int32_t first_inserted_aid_dest;
1046     int move_counter;
1047 sysadm 1.11
1048     if (p_section_dest == NULL)
1049     {
1050     log_error("section_list_move_topic() NULL pointer error\n");
1051     return -1;
1052     }
1053    
1054 sysadm 1.14 if ((p_article = article_block_find_by_aid(aid)) == NULL)
1055 sysadm 1.11 {
1056 sysadm 1.14 log_error("section_list_move_topic() error: article %d not found in block\n", aid);
1057     return -2;
1058     }
1059    
1060     if (p_section_src->sid != p_article->sid)
1061     {
1062     log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1063     p_section_src->sid, p_article->aid, p_article->sid);
1064 sysadm 1.11 return -2;
1065     }
1066    
1067     if (p_article->tid != 0)
1068     {
1069     log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1070     return -2;
1071     }
1072    
1073     last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1074    
1075 sysadm 1.14 move_article_count = article_count_of_topic(aid);
1076 sysadm 1.11 if (move_article_count <= 0)
1077     {
1078     log_error("section_list_count_of_topic_articles(aid = %d) <= 0\n", aid);
1079     return -2;
1080     }
1081    
1082     if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1083     {
1084     log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1085     p_section_dest->article_count + move_article_count, p_section_dest->sid);
1086     return -3;
1087     }
1088    
1089     dest_article_count_old = p_section_dest->article_count;
1090 sysadm 1.12 move_counter = 0;
1091     first_inserted_aid_dest = p_article->aid;
1092 sysadm 1.11
1093     do
1094     {
1095 sysadm 1.14 if (p_section_src->sid != p_article->sid)
1096 sysadm 1.11 {
1097 sysadm 1.14 log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1098     p_section_src->sid, p_article->aid, p_article->sid);
1099     return -2;
1100 sysadm 1.11 }
1101    
1102     // Remove from bi-directional article list of src section
1103     if (p_section_src->p_article_head == p_article)
1104     {
1105     p_section_src->p_article_head = p_article->p_next;
1106     }
1107     if (p_section_src->p_article_tail == p_article)
1108     {
1109     p_section_src->p_article_tail = p_article->p_prior;
1110     }
1111     if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1112     {
1113     p_section_src->p_article_head = NULL;
1114     p_section_src->p_article_tail = NULL;
1115     }
1116    
1117     p_article->p_prior->p_next = p_article->p_next;
1118     p_article->p_next->p_prior = p_article->p_prior;
1119    
1120 sysadm 1.14 // Update sid of article
1121     p_article->sid = p_section_dest->sid;
1122    
1123     if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1124     {
1125     log_error("section_list_move_topic() error: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1126     return -4;
1127     }
1128    
1129 sysadm 1.11 // Insert into bi-directional article list of dest section
1130     if (p_next == NULL) // empty section
1131     {
1132     p_section_dest->p_article_head = p_article;
1133     p_section_dest->p_article_tail = p_article;
1134     p_article->p_prior = p_article;
1135     p_article->p_next = p_article;
1136     }
1137     else
1138     {
1139     if (p_section_dest->p_article_head == p_next)
1140     {
1141     if (p_article->aid < p_next->aid)
1142     {
1143     p_section_dest->p_article_head = p_article;
1144     }
1145     else // p_article->aid > p_next->aid
1146     {
1147     p_section_dest->p_article_tail = p_article;
1148     }
1149     }
1150    
1151     p_article->p_prior = p_next->p_prior;
1152     p_article->p_next = p_next;
1153     p_next->p_prior->p_next = p_article;
1154     p_next->p_prior = p_article;
1155     }
1156    
1157     // Update article / topic counter of src / desc section
1158     p_section_src->article_count--;
1159     p_section_dest->article_count++;
1160     if (p_article->tid == 0)
1161     {
1162     p_section_src->topic_count--;
1163     p_section_dest->topic_count++;
1164     }
1165    
1166     // Update visible article / topic counter of src / desc section
1167     if (p_article->visible)
1168     {
1169     p_section_src->visible_article_count--;
1170     p_section_dest->visible_article_count++;
1171     if (p_article->tid == 0)
1172     {
1173     p_section_src->visible_topic_count--;
1174     p_section_dest->visible_topic_count++;
1175     }
1176     }
1177    
1178     // Update page for empty dest section
1179     if (p_section_dest->article_count == 1)
1180     {
1181     p_section_dest->p_page_first_article[0] = p_article;
1182     p_section_dest->page_count = 1;
1183     p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1184     }
1185    
1186     p_article = p_article->p_topic_next;
1187 sysadm 1.12
1188     move_counter++;
1189     if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1190     {
1191     // Re-calculate pages of desc section
1192     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1193     {
1194 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1195 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1196     }
1197    
1198     first_inserted_aid_dest = p_article->aid;
1199     }
1200 sysadm 1.11 } while (p_article->aid != aid);
1201    
1202     if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1203     {
1204     log_error("section_list_move_topic() error: count of moved articles %d != %d\n",
1205     p_section_dest->article_count - dest_article_count_old, move_article_count);
1206     }
1207    
1208 sysadm 1.12 // Re-calculate pages of src section
1209 sysadm 1.11 if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1210     {
1211 sysadm 1.14 log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1212 sysadm 1.12 p_section_src->sid, last_unaffected_aid_src, aid);
1213 sysadm 1.11 }
1214 sysadm 1.12
1215     if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1216 sysadm 1.11 {
1217 sysadm 1.12 // Re-calculate pages of desc section
1218     if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1219     {
1220 sysadm 1.14 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1221 sysadm 1.12 p_section_dest->sid, first_inserted_aid_dest);
1222     }
1223 sysadm 1.11 }
1224    
1225     return move_article_count;
1226     }
1227 sysadm 1.16
1228     int get_section_index(SECTION_LIST *p_section)
1229     {
1230     int index;
1231    
1232     if (p_section_list_pool == NULL)
1233     {
1234     log_error("get_section_index() error: uninitialized\n");
1235     return -1;
1236     }
1237    
1238     if (p_section == NULL)
1239     {
1240     index = BBS_max_section;
1241     }
1242     else
1243     {
1244     index = (int)(p_section - p_section_list_pool);
1245     if (index < 0 || index >= BBS_max_section)
1246     {
1247     log_error("get_section_index(%d) error: index out of range\n", index);
1248     return -2;
1249     }
1250     }
1251    
1252     return index;
1253     }
1254    
1255     int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1256     {
1257     int index;
1258 sysadm 1.17 struct sembuf sops[4];
1259 sysadm 1.16 struct timespec timeout;
1260     int ret;
1261    
1262     index = get_section_index(p_section);
1263     if (index < 0)
1264     {
1265     return -2;
1266     }
1267    
1268 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1269     sops[0].sem_op = 0; // wait until unlocked
1270 sysadm 1.16 sops[0].sem_flg = 0;
1271    
1272 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1273     sops[1].sem_op = 1; // lock
1274     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1275    
1276     // Read lock on any specific section will also acquire single read lock on "all section"
1277     // so that write lock on all section only need to acquire single write on on "all section"
1278     // rather than to acquire multiple write locks on all the available sections.
1279     if (index == BBS_max_section)
1280     {
1281     sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1282     sops[2].sem_op = 0; // wait until unlocked
1283     sops[2].sem_flg = 0;
1284    
1285     sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1286     sops[3].sem_op = 1; // lock
1287     sops[3].sem_flg = SEM_UNDO; // undo on terminate
1288     }
1289 sysadm 1.16
1290     timeout.tv_sec = wait_sec;
1291     timeout.tv_nsec = 0;
1292    
1293 sysadm 1.17 ret = semtimedop(section_list_pool_semid, sops, (index == BBS_max_section ? 4 : 2), &timeout);
1294     if (ret == -1 && errno != EAGAIN && errno != EINTR)
1295     {
1296     log_error("semtimedop(index = %d, lock read) error %d\n", index, errno);
1297     }
1298 sysadm 1.16
1299     return ret;
1300     }
1301    
1302     int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1303     {
1304     int index;
1305     struct sembuf sops[3];
1306     struct timespec timeout;
1307     int ret;
1308    
1309     index = get_section_index(p_section);
1310     if (index < 0)
1311     {
1312     return -2;
1313     }
1314    
1315 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1316     sops[0].sem_op = 0; // wait until unlocked
1317 sysadm 1.16 sops[0].sem_flg = 0;
1318    
1319 sysadm 1.17 sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1320     sops[1].sem_op = 1; // lock
1321     sops[1].sem_flg = SEM_UNDO; // undo on terminate
1322    
1323     sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1324     sops[2].sem_op = 0; // wait until unlocked
1325     sops[2].sem_flg = 0;
1326 sysadm 1.16
1327     timeout.tv_sec = wait_sec;
1328     timeout.tv_nsec = 0;
1329    
1330     ret = semtimedop(section_list_pool_semid, sops, 3, &timeout);
1331 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1332     {
1333     log_error("semtimedop(index = %d, lock write) error %d\n", index, errno);
1334     }
1335 sysadm 1.16
1336     return ret;
1337     }
1338    
1339     int section_list_rd_unlock(SECTION_LIST *p_section)
1340     {
1341     int index;
1342 sysadm 1.17 struct sembuf sops[2];
1343 sysadm 1.16 int ret;
1344    
1345     index = get_section_index(p_section);
1346     if (index < 0)
1347     {
1348     return -2;
1349     }
1350    
1351 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1352     sops[0].sem_op = -1; // unlock
1353     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1354 sysadm 1.16
1355 sysadm 1.17 // The same reason as section_list_try_rd_lock()
1356     if (index == BBS_max_section)
1357     {
1358     sops[1].sem_num = BBS_max_section * 2; // r_sem of all section
1359     sops[1].sem_op = -1; // unlock
1360     sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1361     }
1362    
1363     ret = semop(section_list_pool_semid, sops, (index == BBS_max_section ? 2 : 1));
1364     if (ret == -1 && errno != EAGAIN && errno != EINTR)
1365     {
1366     log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1367     }
1368 sysadm 1.16
1369     return ret;
1370     }
1371    
1372     int section_list_rw_unlock(SECTION_LIST *p_section)
1373     {
1374     int index;
1375     struct sembuf sops[1];
1376     int ret;
1377    
1378     index = get_section_index(p_section);
1379     if (index < 0)
1380     {
1381     return -2;
1382     }
1383    
1384 sysadm 1.17 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1385     sops[0].sem_op = -1; // unlock
1386     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1387 sysadm 1.16
1388     ret = semop(section_list_pool_semid, sops, 1);
1389 sysadm 1.17 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1390     {
1391     log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1392     }
1393 sysadm 1.16
1394     return ret;
1395     }

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