/[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.17 - (hide annotations)
Sat May 24 13:52:44 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.16: +88 -26 lines
Content type: text/x-csrc
Update lock/unlock and test

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

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