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

Contents of /lbbs/src/section_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (show annotations)
Tue May 27 01:53:42 2025 UTC (9 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.26: +16 -1 lines
Content type: text/x-csrc
Add article_block_article_count()

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

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