/[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.28 - (show annotations)
Tue May 27 07:21:43 2025 UTC (9 months, 2 weeks ago) by sysadm
Branch: MAIN
Changes since 1.27: +21 -8 lines
Content type: text/x-csrc
Add set_last_article_op_log_from_db() and set_last_article_op_log_from_db()

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 if (aid != p_block->articles[left].aid) // not found
403 {
404 return NULL;
405 }
406
407 return (p_block->articles + left); // found
408 }
409
410 ARTICLE *article_block_find_by_index(int index)
411 {
412 ARTICLE_BLOCK *p_block;
413
414 if (p_article_block_pool == NULL)
415 {
416 log_error("article_block_pool not initialized\n");
417 return NULL;
418 }
419
420 if (index < 0 || index / ARTICLE_PER_BLOCK >= p_article_block_pool->block_count)
421 {
422 log_error("article_block_find_by_index(%d) is out of boundary of block [0, %d)\n", index, p_article_block_pool->block_count);
423 return NULL;
424 }
425
426 p_block = p_article_block_pool->p_block[index / ARTICLE_PER_BLOCK];
427
428 if (index % ARTICLE_PER_BLOCK >= p_block->article_count)
429 {
430 log_error("article_block_find_by_index(%d) is out of boundary of article [0, %d)\n", index, p_block->article_count);
431 return NULL;
432 }
433
434 return (p_block->articles + (index % ARTICLE_PER_BLOCK));
435 }
436
437 extern int section_list_init(const char *filename)
438 {
439 int semid;
440 int shmid;
441 int proj_id;
442 key_t key;
443 size_t size;
444 void *p_shm;
445 union semun arg;
446 int i;
447
448 if (p_section_list_pool != NULL)
449 {
450 section_list_cleanup();
451 }
452
453 proj_id = (int)(time(NULL) % getpid());
454 key = ftok(filename, proj_id);
455 if (key == -1)
456 {
457 log_error("ftok(%s, %d) error (%d)\n", filename, proj_id, errno);
458 return -3;
459 }
460
461 // Allocate shared memory
462 size = sizeof(SECTION_LIST_POOL);
463 shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
464 if (shmid == -1)
465 {
466 log_error("shmget(section_list_pool_shm, size = %d) error (%d)\n", size, errno);
467 return -3;
468 }
469 p_shm = shmat(shmid, NULL, 0);
470 if (p_shm == (void *)-1)
471 {
472 log_error("shmat(shmid = %d) error (%d)\n", shmid, errno);
473 return -3;
474 }
475
476 p_section_list_pool = p_shm;
477 p_section_list_pool->shmid = shmid;
478 p_section_list_pool->section_count = 0;
479
480 // Allocate semaphore as section locks
481 size = 2 * (BBS_max_section + 1); // r_sem and w_sem per section, the last pair for all sections
482 semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
483 if (semid == -1)
484 {
485 log_error("semget(section_list_pool_sem, size = %d) error (%d)\n", size, errno);
486 return -3;
487 }
488
489 // Initialize sem value to 0
490 arg.val = 0;
491 for (i = 0; i < size; i++)
492 {
493 if (semctl(semid, i, SETVAL, arg) == -1)
494 {
495 log_error("semctl(section_list_pool_sem, SETVAL) error (%d)\n", errno);
496 return -3;
497 }
498 }
499
500 p_section_list_pool->semid = semid;
501
502 p_section_list_pool->p_trie_dict_section_by_name = trie_dict_create();
503 if (p_section_list_pool->p_trie_dict_section_by_name == NULL)
504 {
505 log_error("trie_dict_create() OOM\n", BBS_max_section);
506 return -2;
507 }
508
509 p_section_list_pool->p_trie_dict_section_by_sid = trie_dict_create();
510 if (p_section_list_pool->p_trie_dict_section_by_sid == NULL)
511 {
512 log_error("trie_dict_create() OOM\n", BBS_max_section);
513 return -2;
514 }
515
516 return 0;
517 }
518
519 void section_list_cleanup(void)
520 {
521 int shmid;
522
523 if (p_section_list_pool == NULL)
524 {
525 return;
526 }
527
528 if (p_section_list_pool->p_trie_dict_section_by_name != NULL)
529 {
530 trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_name);
531 p_section_list_pool->p_trie_dict_section_by_name = NULL;
532 }
533
534 if (p_section_list_pool->p_trie_dict_section_by_sid != NULL)
535 {
536 trie_dict_destroy(p_section_list_pool->p_trie_dict_section_by_sid);
537 p_section_list_pool->p_trie_dict_section_by_sid = NULL;
538 }
539
540 shmid = p_section_list_pool->shmid;
541
542 if (semctl(p_section_list_pool->semid, 0, IPC_RMID) == -1)
543 {
544 log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_section_list_pool->semid, errno);
545 }
546
547 if (shmdt(p_section_list_pool) == -1)
548 {
549 log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
550 }
551
552 if (shmctl(shmid, IPC_RMID, NULL) == -1)
553 {
554 log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
555 }
556
557 p_section_list_pool = NULL;
558 }
559
560 int set_section_list_shm_readonly(void)
561 {
562 int shmid;
563 void *p_shm;
564
565 if (p_section_list_pool == NULL)
566 {
567 log_error("p_section_list_pool not initialized\n");
568 return -1;
569 }
570
571 shmid = p_section_list_pool->shmid;
572
573 // Remap shared memory in read-only mode
574 p_shm = shmat(shmid, p_section_list_pool, SHM_RDONLY | SHM_REMAP);
575 if (p_shm == (void *)-1)
576 {
577 log_error("shmat(section_list_pool shmid = %d) error (%d)\n", shmid, errno);
578 return -3;
579 }
580
581 p_section_list_pool = p_shm;
582
583 return 0;
584 }
585
586 int detach_section_list_shm(void)
587 {
588 if (p_section_list_pool != NULL && shmdt(p_section_list_pool) == -1)
589 {
590 log_error("shmdt(section_list_pool) error (%d)\n", errno);
591 return -1;
592 }
593
594 p_section_list_pool = NULL;
595
596 return 0;
597 }
598
599 inline static void sid_to_str(int32_t sid, char *p_sid_str)
600 {
601 uint32_t u_sid;
602 int i;
603
604 u_sid = (uint32_t)sid;
605 for (i = 0; i < SID_STR_LEN - 1; i++)
606 {
607 p_sid_str[i] = (char)(u_sid % 255 + 1);
608 u_sid /= 255;
609 }
610 p_sid_str[i] = '\0';
611 }
612
613 SECTION_LIST *section_list_create(int32_t sid, const char *sname, const char *stitle, const char *master_name)
614 {
615 SECTION_LIST *p_section;
616 char sid_str[SID_STR_LEN];
617
618 if (p_section_list_pool == NULL)
619 {
620 log_error("session_list_pool not initialized\n");
621 return NULL;
622 }
623
624 if (p_section_list_pool->section_count >= BBS_max_section)
625 {
626 log_error("section_count reach limit %d >= %d\n", p_section_list_pool->section_count, BBS_max_section);
627 return NULL;
628 }
629
630 sid_to_str(sid, sid_str);
631
632 p_section = p_section_list_pool->sections + p_section_list_pool->section_count;
633
634 p_section->sid = sid;
635
636 strncpy(p_section->sname, sname, sizeof(p_section->sname - 1));
637 p_section->sname[sizeof(p_section->sname - 1)] = '\0';
638
639 strncpy(p_section->stitle, stitle, sizeof(p_section->stitle - 1));
640 p_section->stitle[sizeof(p_section->stitle - 1)] = '\0';
641
642 strncpy(p_section->master_name, master_name, sizeof(p_section->master_name - 1));
643 p_section->master_name[sizeof(p_section->master_name - 1)] = '\0';
644
645 if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_name, sname, p_section_list_pool->section_count) != 1)
646 {
647 log_error("trie_dict_set(section, %s, %d) error\n", sname, p_section_list_pool->section_count);
648 return NULL;
649 }
650
651 if (trie_dict_set(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, p_section_list_pool->section_count) != 1)
652 {
653 log_error("trie_dict_set(section, %d, %d) error\n", sid, p_section_list_pool->section_count);
654 return NULL;
655 }
656
657 section_list_reset_articles(p_section);
658
659 p_section_list_pool->section_count++;
660
661 return p_section;
662 }
663
664 void section_list_reset_articles(SECTION_LIST *p_section)
665 {
666 p_section->article_count = 0;
667 p_section->topic_count = 0;
668 p_section->visible_article_count = 0;
669 p_section->visible_topic_count = 0;
670 p_section->p_article_head = NULL;
671 p_section->p_article_tail = NULL;
672
673 p_section->page_count = 0;
674 p_section->last_page_visible_article_count = 0;
675 }
676
677 SECTION_LIST *section_list_find_by_name(const char *sname)
678 {
679 int64_t index;
680 int ret;
681
682 if (p_section_list_pool == NULL)
683 {
684 log_error("section_list not initialized\n");
685 return NULL;
686 }
687
688 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_name, sname, &index);
689 if (ret < 0)
690 {
691 log_error("trie_dict_get(section, %s) error\n", sname);
692 return NULL;
693 }
694 else if (ret == 0)
695 {
696 return NULL;
697 }
698
699 return (p_section_list_pool->sections + index);
700 }
701
702 SECTION_LIST *section_list_find_by_sid(int32_t sid)
703 {
704 int64_t index;
705 int ret;
706 char sid_str[SID_STR_LEN];
707
708 if (p_section_list_pool == NULL)
709 {
710 log_error("section_list not initialized\n");
711 return NULL;
712 }
713
714 sid_to_str(sid, sid_str);
715
716 ret = trie_dict_get(p_section_list_pool->p_trie_dict_section_by_sid, sid_str, &index);
717 if (ret < 0)
718 {
719 log_error("trie_dict_get(section, %d) error\n", sid);
720 return NULL;
721 }
722 else if (ret == 0)
723 {
724 return NULL;
725 }
726
727 return (p_section_list_pool->sections + index);
728 }
729
730 int section_list_append_article(SECTION_LIST *p_section, const ARTICLE *p_article_src)
731 {
732 ARTICLE_BLOCK *p_block;
733 int32_t last_aid = 0;
734 ARTICLE *p_article;
735 ARTICLE *p_topic_head;
736 ARTICLE *p_topic_tail;
737
738 if (p_section == NULL || p_article_src == NULL)
739 {
740 log_error("section_list_append_article() NULL pointer error\n");
741 return -1;
742 }
743
744 if (p_article_block_pool == NULL)
745 {
746 log_error("article_block_pool not initialized\n");
747 return -1;
748 }
749
750 if (p_section->sid != p_article_src->sid)
751 {
752 log_error("section_list_append_article() error: section sid %d != article sid %d\n", p_section->sid, p_article_src->sid);
753 return -2;
754 }
755
756 if (p_section->article_count >= BBS_article_limit_per_section)
757 {
758 log_error("section_list_append_article() error: article_count reach limit in section %d\n", p_section->sid);
759 return -2;
760 }
761
762 if (p_article_block_pool->block_count == 0 ||
763 p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count >= ARTICLE_PER_BLOCK)
764 {
765 if ((p_block = pop_free_article_block()) == NULL)
766 {
767 log_error("pop_free_article_block() error\n");
768 return -2;
769 }
770
771 if (p_article_block_pool->block_count > 0)
772 {
773 last_aid = p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->articles[ARTICLE_PER_BLOCK - 1].aid;
774 }
775
776 p_article_block_pool->p_block[p_article_block_pool->block_count] = p_block;
777 p_article_block_pool->block_count++;
778 }
779 else
780 {
781 p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
782 last_aid = p_block->articles[p_block->article_count - 1].aid;
783 }
784
785 // AID of articles should be strictly ascending
786 if (p_article_src->aid <= last_aid)
787 {
788 log_error("section_list_append_article(aid=%d) error: last_aid=%d\n", p_article_src->aid, last_aid);
789 return -3;
790 }
791
792 p_article = (p_block->articles + p_block->article_count);
793 p_block->article_count++;
794 p_section->article_count++;
795
796 // Copy article data
797 *p_article = *p_article_src;
798
799 if (p_article->visible)
800 {
801 p_section->visible_article_count++;
802 }
803
804 // Link appended article as tail node of topic bi-directional list
805 if (p_article->tid != 0)
806 {
807 p_topic_head = article_block_find_by_aid(p_article->tid);
808 if (p_topic_head == NULL)
809 {
810 log_error("search head of topic (aid=%d) error\n", p_article->tid);
811 return -4;
812 }
813
814 p_topic_tail = p_topic_head->p_topic_prior;
815 if (p_topic_tail == NULL)
816 {
817 log_error("tail of topic (aid=%d) is NULL\n", p_article->tid);
818 return -4;
819 }
820 }
821 else
822 {
823 p_section->topic_count++;
824
825 if (p_article->visible)
826 {
827 p_section->visible_topic_count++;
828 }
829
830 p_topic_head = p_article;
831 p_topic_tail = p_article;
832 }
833
834 p_article->p_topic_prior = p_topic_tail;
835 p_article->p_topic_next = p_topic_head;
836 p_topic_head->p_topic_prior = p_article;
837 p_topic_tail->p_topic_next = p_article;
838
839 // Link appended article as tail node of article bi-directional list
840 if (p_section->p_article_head == NULL)
841 {
842 p_section->p_article_head = p_article;
843 p_section->p_article_tail = p_article;
844 }
845 p_article->p_prior = p_section->p_article_tail;
846 p_article->p_next = p_section->p_article_head;
847 p_section->p_article_head->p_prior = p_article;
848 p_section->p_article_tail->p_next = p_article;
849 p_section->p_article_tail = p_article;
850
851 // Update page
852 if ((p_article->visible && p_section->last_page_visible_article_count % BBS_article_limit_per_page == 0) ||
853 p_section->article_count == 1)
854 {
855 p_section->p_page_first_article[p_section->page_count] = p_article;
856 p_section->page_count++;
857 p_section->last_page_visible_article_count = 0;
858 }
859
860 if (p_article->visible)
861 {
862 p_section->last_page_visible_article_count++;
863 }
864
865 return 0;
866 }
867
868 int section_list_set_article_visible(SECTION_LIST *p_section, int32_t aid, int8_t visible)
869 {
870 ARTICLE *p_article;
871 ARTICLE *p_reply;
872 int affected_count = 0;
873
874 if (p_section == NULL)
875 {
876 log_error("section_list_set_article_visible() NULL pointer error\n");
877 return -2;
878 }
879
880 p_article = article_block_find_by_aid(aid);
881 if (p_article == NULL)
882 {
883 return -1; // Not found
884 }
885
886 if (p_section->sid != p_article->sid)
887 {
888 log_error("section_list_set_article_visible() error: section sid %d != article sid %d\n", p_section->sid, p_article->sid);
889 return -2;
890 }
891
892 if (p_article->visible == visible)
893 {
894 return 0; // Already set
895 }
896
897 if (visible == 0) // 1 -> 0
898 {
899 p_section->visible_article_count--;
900
901 if (p_article->tid == 0)
902 {
903 p_section->visible_topic_count--;
904
905 // Set related visible replies to invisible
906 for (p_reply = p_article->p_topic_next; p_reply->tid != 0; p_reply = p_reply->p_topic_next)
907 {
908 if (p_reply->tid != aid)
909 {
910 log_error("Inconsistent tid = %d found in reply %d of topic %d\n", p_reply->tid, p_reply->aid, aid);
911 continue;
912 }
913
914 if (p_reply->visible == 1)
915 {
916 p_reply->visible = 0;
917 p_section->visible_article_count--;
918 affected_count++;
919 }
920 }
921 }
922 }
923 else // 0 -> 1
924 {
925 p_section->visible_article_count++;
926
927 if (p_article->tid == 0)
928 {
929 p_section->visible_topic_count++;
930 }
931 }
932
933 p_article->visible = visible;
934 affected_count++;
935
936 return affected_count;
937 }
938
939 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)
940 {
941 ARTICLE *p_article;
942 int left;
943 int right;
944 int mid;
945
946 *p_page = -1;
947 *p_offset = -1;
948 *pp_next = NULL;
949
950 if (p_section == NULL)
951 {
952 log_error("section_list_find_article_with_offset() NULL pointer error\n");
953 return NULL;
954 }
955
956 if (p_section->article_count == 0) // empty
957 {
958 *p_page = 0;
959 *p_offset = 0;
960 return NULL;
961 }
962
963 left = 0;
964 right = p_section->page_count;
965
966 // aid in the range [ head aid of pages[left], tail aid of pages[right - 1] ]
967 while (left < right - 1)
968 {
969 // get page id no less than mid value of left page id and right page id
970 mid = (left + right) / 2 + (right - left) % 2;
971
972 if (mid >= p_section->page_count)
973 {
974 log_error("page id (mid = %d) is out of boundary\n", mid);
975 return NULL;
976 }
977
978 if (aid < p_section->p_page_first_article[mid]->aid)
979 {
980 right = mid;
981 }
982 else
983 {
984 left = mid;
985 }
986 }
987
988 *p_page = left;
989
990 p_article = p_section->p_page_first_article[*p_page];
991
992 // p_section->p_page_first_article[*p_page]->aid <= aid < p_section->p_page_first_article[*p_page + 1]->aid
993 right = (*p_page == MAX(0, p_section->page_count - 1) ? INT32_MAX : p_section->p_page_first_article[*p_page + 1]->aid);
994
995 // left will be the offset of article found or offset to insert
996 left = 0;
997
998 while (aid > p_article->aid)
999 {
1000 p_article = p_article->p_next;
1001 left++;
1002
1003 if (aid == p_article->aid)
1004 {
1005 *pp_next = p_article->p_next;
1006 break;
1007 }
1008
1009 // over last article in the page
1010 if (p_article == p_section->p_article_head || p_article->aid >= right)
1011 {
1012 *pp_next = (p_article == p_section->p_article_head ? p_section->p_article_head : p_section->p_page_first_article[*p_page + 1]);
1013 *p_offset = left;
1014 return NULL; // not found
1015 }
1016 }
1017
1018 if (aid < p_article->aid)
1019 {
1020 *pp_next = p_article;
1021 p_article = NULL; // not found
1022 }
1023 else // aid == p_article->aid
1024 {
1025 *pp_next = p_article->p_next;
1026 }
1027
1028 *p_offset = left;
1029
1030 return p_article;
1031 }
1032
1033 int section_list_calculate_page(SECTION_LIST *p_section, int32_t start_aid)
1034 {
1035 ARTICLE *p_article;
1036 ARTICLE *p_next;
1037 int32_t page;
1038 int32_t offset;
1039 int visible_article_count;
1040 int page_head_set;
1041
1042 if (p_section == NULL)
1043 {
1044 log_error("section_list_calculate_page() NULL pointer error\n");
1045 return -1;
1046 }
1047
1048 if (p_section->article_count == 0) // empty
1049 {
1050 p_section->page_count = 0;
1051 p_section->last_page_visible_article_count = 0;
1052
1053 return 0;
1054 }
1055
1056 if (start_aid > 0)
1057 {
1058 p_article = article_block_find_by_aid(start_aid);
1059 if (p_article == NULL)
1060 {
1061 return -1; // Not found
1062 }
1063
1064 if (p_section->sid != p_article->sid)
1065 {
1066 log_error("section_list_calculate_page() error: section sid %d != start article sid %d\n", p_section->sid, p_article->sid);
1067 return -2;
1068 }
1069
1070 p_article = section_list_find_article_with_offset(p_section, start_aid, &page, &offset, &p_next);
1071 if (p_article == NULL)
1072 {
1073 if (page < 0)
1074 {
1075 return -1;
1076 }
1077 log_error("section_list_calculate_page() aid = %d not found in section sid = %d\n",
1078 start_aid, p_section->sid);
1079 return -2;
1080 }
1081
1082 if (offset > 0)
1083 {
1084 p_article = p_section->p_page_first_article[page];
1085 }
1086 }
1087 else
1088 {
1089 p_article = p_section->p_article_head;
1090 page = 0;
1091 offset = 0;
1092 }
1093
1094 visible_article_count = 0;
1095 page_head_set = 0;
1096
1097 do
1098 {
1099 if (!page_head_set && visible_article_count == 0)
1100 {
1101 p_section->p_page_first_article[page] = p_article;
1102 page_head_set = 1;
1103 }
1104
1105 if (p_article->visible)
1106 {
1107 visible_article_count++;
1108 }
1109
1110 p_article = p_article->p_next;
1111
1112 // skip remaining invisible articles
1113 while (p_article->visible == 0 && p_article != p_section->p_article_head)
1114 {
1115 p_article = p_article->p_next;
1116 }
1117
1118 if (visible_article_count >= BBS_article_limit_per_page && p_article != p_section->p_article_head)
1119 {
1120 page++;
1121 visible_article_count = 0;
1122 page_head_set = 0;
1123
1124 if (page >= BBS_article_limit_per_section / BBS_article_limit_per_page && p_article != p_section->p_article_head)
1125 {
1126 log_error("Count of page exceed limit in section %d\n", p_section->sid);
1127 break;
1128 }
1129 }
1130 } while (p_article != p_section->p_article_head);
1131
1132 p_section->page_count = page + (visible_article_count > 0 ? 1 : 0);
1133 p_section->last_page_visible_article_count = visible_article_count;
1134
1135 return 0;
1136 }
1137
1138 int32_t article_block_last_aid(void)
1139 {
1140 ARTICLE_BLOCK *p_block = p_article_block_pool->p_block[p_article_block_pool->block_count - 1];
1141 int32_t last_aid = p_block->articles[p_block->article_count - 1].aid;
1142
1143 return last_aid;
1144 }
1145
1146 int article_block_article_count(void)
1147 {
1148 int ret;
1149
1150 if (p_article_block_pool == NULL || p_article_block_pool->block_count <= 0)
1151 {
1152 return -1;
1153 }
1154
1155 ret = (p_article_block_pool->block_count - 1) * ARTICLE_PER_BLOCK +
1156 p_article_block_pool->p_block[p_article_block_pool->block_count - 1]->article_count;
1157
1158 return ret;
1159 }
1160
1161 int article_count_of_topic(int32_t aid)
1162 {
1163 ARTICLE *p_article;
1164 int article_count;
1165
1166 p_article = article_block_find_by_aid(aid);
1167 if (p_article == NULL)
1168 {
1169 return 0; // Not found
1170 }
1171
1172 article_count = 0;
1173
1174 do
1175 {
1176 if (p_article->tid != 0 && p_article->tid != aid)
1177 {
1178 log_error("article_count_of_topic(%d) error: article %d not linked to the topic\n", aid, p_article->aid);
1179 break;
1180 }
1181
1182 article_count++;
1183 p_article = p_article->p_topic_next;
1184 } while (p_article->aid != aid);
1185
1186 return article_count;
1187 }
1188
1189 int section_list_move_topic(SECTION_LIST *p_section_src, SECTION_LIST *p_section_dest, int32_t aid)
1190 {
1191 ARTICLE *p_article;
1192 ARTICLE *p_next;
1193 int32_t page;
1194 int32_t offset;
1195 int32_t move_article_count;
1196 int32_t dest_article_count_old;
1197 int32_t last_unaffected_aid_src;
1198 int32_t first_inserted_aid_dest;
1199 int move_counter;
1200
1201 if (p_section_src == NULL || p_section_dest == NULL)
1202 {
1203 log_error("section_list_move_topic() NULL pointer error\n");
1204 return -1;
1205 }
1206
1207 if (p_section_src->sid == p_section_dest->sid)
1208 {
1209 log_error("section_list_move_topic() src and dest section are the same\n");
1210 return -1;
1211 }
1212
1213 if ((p_article = article_block_find_by_aid(aid)) == NULL)
1214 {
1215 log_error("article_block_find_by_aid(aid = %d) error: article not found\n", aid);
1216 return -2;
1217 }
1218
1219 if (p_section_src->sid != p_article->sid)
1220 {
1221 log_error("section_list_move_topic() error: src section sid %d != article %d sid %d\n",
1222 p_section_src->sid, p_article->aid, p_article->sid);
1223 return -2;
1224 }
1225
1226 if (p_article->tid != 0)
1227 {
1228 log_error("section_list_move_topic(aid = %d) error: article is not head of topic, tid = %d\n", aid, p_article->tid);
1229 return -2;
1230 }
1231
1232 last_unaffected_aid_src = (p_article == p_section_src->p_article_head ? 0 : p_article->p_prior->aid);
1233
1234 move_article_count = article_count_of_topic(aid);
1235 if (move_article_count <= 0)
1236 {
1237 log_error("article_count_of_topic(aid = %d) <= 0\n", aid);
1238 return -2;
1239 }
1240
1241 if (p_section_dest->article_count + move_article_count > BBS_article_limit_per_section)
1242 {
1243 log_error("section_list_move_topic() error: article_count %d reach limit in section %d\n",
1244 p_section_dest->article_count + move_article_count, p_section_dest->sid);
1245 return -3;
1246 }
1247
1248 dest_article_count_old = p_section_dest->article_count;
1249 move_counter = 0;
1250 first_inserted_aid_dest = p_article->aid;
1251
1252 do
1253 {
1254 if (p_section_src->sid != p_article->sid)
1255 {
1256 log_error("section_list_move_topic() warning: src section sid %d != article %d sid %d\n",
1257 p_section_src->sid, p_article->aid, p_article->sid);
1258 p_article = p_article->p_topic_next;
1259 continue;
1260 }
1261
1262 // Remove from bi-directional article list of src section
1263 if (p_section_src->p_article_head == p_article)
1264 {
1265 p_section_src->p_article_head = p_article->p_next;
1266 }
1267 if (p_section_src->p_article_tail == p_article)
1268 {
1269 p_section_src->p_article_tail = p_article->p_prior;
1270 }
1271 if (p_section_src->p_article_head == p_article) // || p_section_src->p_article_tail == p_article
1272 {
1273 p_section_src->p_article_head = NULL;
1274 p_section_src->p_article_tail = NULL;
1275 }
1276
1277 p_article->p_prior->p_next = p_article->p_next;
1278 p_article->p_next->p_prior = p_article->p_prior;
1279
1280 // Update sid of article
1281 p_article->sid = p_section_dest->sid;
1282
1283 if (section_list_find_article_with_offset(p_section_dest, p_article->aid, &page, &offset, &p_next) != NULL)
1284 {
1285 log_error("section_list_move_topic() warning: article %d already in section %d\n", p_article->aid, p_section_dest->sid);
1286 p_article = p_article->p_topic_next;
1287 continue;
1288 }
1289
1290 // Insert into bi-directional article list of dest section
1291 if (p_next == NULL) // empty section
1292 {
1293 p_section_dest->p_article_head = p_article;
1294 p_section_dest->p_article_tail = p_article;
1295 p_article->p_prior = p_article;
1296 p_article->p_next = p_article;
1297 }
1298 else
1299 {
1300 if (p_section_dest->p_article_head == p_next)
1301 {
1302 if (p_article->aid < p_next->aid)
1303 {
1304 p_section_dest->p_article_head = p_article;
1305 }
1306 else // p_article->aid > p_next->aid
1307 {
1308 p_section_dest->p_article_tail = p_article;
1309 }
1310 }
1311
1312 p_article->p_prior = p_next->p_prior;
1313 p_article->p_next = p_next;
1314 p_next->p_prior->p_next = p_article;
1315 p_next->p_prior = p_article;
1316 }
1317
1318 // Update article / topic counter of src / desc section
1319 p_section_src->article_count--;
1320 p_section_dest->article_count++;
1321 if (p_article->tid == 0)
1322 {
1323 p_section_src->topic_count--;
1324 p_section_dest->topic_count++;
1325 }
1326
1327 // Update visible article / topic counter of src / desc section
1328 if (p_article->visible)
1329 {
1330 p_section_src->visible_article_count--;
1331 p_section_dest->visible_article_count++;
1332 if (p_article->tid == 0)
1333 {
1334 p_section_src->visible_topic_count--;
1335 p_section_dest->visible_topic_count++;
1336 }
1337 }
1338
1339 // Update page for empty dest section
1340 if (p_section_dest->article_count == 1)
1341 {
1342 p_section_dest->p_page_first_article[0] = p_article;
1343 p_section_dest->page_count = 1;
1344 p_section_dest->last_page_visible_article_count = (p_article->visible ? 1 : 0);
1345 }
1346
1347 p_article = p_article->p_topic_next;
1348
1349 move_counter++;
1350 if (move_counter % CALCULATE_PAGE_THRESHOLD == 0)
1351 {
1352 // Re-calculate pages of desc section
1353 if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1354 {
1355 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1356 p_section_dest->sid, first_inserted_aid_dest);
1357 }
1358
1359 first_inserted_aid_dest = p_article->aid;
1360 }
1361 } while (p_article->aid != aid);
1362
1363 if (p_section_dest->article_count - dest_article_count_old != move_article_count)
1364 {
1365 log_error("section_list_move_topic() warning: count of moved articles %d != %d\n",
1366 p_section_dest->article_count - dest_article_count_old, move_article_count);
1367 }
1368
1369 // Re-calculate pages of src section
1370 if (section_list_calculate_page(p_section_src, last_unaffected_aid_src) < 0)
1371 {
1372 log_error("section_list_calculate_page(src section = %d, aid = %d) error at aid = %d\n",
1373 p_section_src->sid, last_unaffected_aid_src, aid);
1374 }
1375
1376 if (move_counter % CALCULATE_PAGE_THRESHOLD != 0)
1377 {
1378 // Re-calculate pages of desc section
1379 if (section_list_calculate_page(p_section_dest, first_inserted_aid_dest) < 0)
1380 {
1381 log_error("section_list_calculate_page(dest section = %d, aid = %d) error\n",
1382 p_section_dest->sid, first_inserted_aid_dest);
1383 }
1384 }
1385
1386 return move_article_count;
1387 }
1388
1389 int get_section_index(SECTION_LIST *p_section)
1390 {
1391 int index;
1392
1393 if (p_section_list_pool == NULL)
1394 {
1395 log_error("get_section_index() error: uninitialized\n");
1396 return -1;
1397 }
1398
1399 if (p_section == NULL)
1400 {
1401 index = BBS_max_section;
1402 }
1403 else
1404 {
1405 index = (int)(p_section - p_section_list_pool->sections);
1406 if (index < 0 || index >= BBS_max_section)
1407 {
1408 log_error("get_section_index(%d) error: index out of range\n", index);
1409 return -2;
1410 }
1411 }
1412
1413 return index;
1414 }
1415
1416 int section_list_try_rd_lock(SECTION_LIST *p_section, int wait_sec)
1417 {
1418 int index;
1419 struct sembuf sops[4];
1420 struct timespec timeout;
1421 int ret;
1422
1423 index = get_section_index(p_section);
1424 if (index < 0)
1425 {
1426 return -2;
1427 }
1428
1429 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1430 sops[0].sem_op = 0; // wait until unlocked
1431 sops[0].sem_flg = 0;
1432
1433 sops[1].sem_num = (unsigned short)(index * 2); // r_sem of section index
1434 sops[1].sem_op = 1; // lock
1435 sops[1].sem_flg = SEM_UNDO; // undo on terminate
1436
1437 // Read lock on any specific section will also acquire single read lock on "all section"
1438 // so that write lock on all section only need to acquire single write on on "all section"
1439 // rather than to acquire multiple write locks on all the available sections.
1440 if (index != BBS_max_section)
1441 {
1442 sops[2].sem_num = BBS_max_section * 2 + 1; // w_sem of all section
1443 sops[2].sem_op = 0; // wait until unlocked
1444 sops[2].sem_flg = 0;
1445
1446 sops[3].sem_num = BBS_max_section * 2; // r_sem of all section
1447 sops[3].sem_op = 1; // lock
1448 sops[3].sem_flg = SEM_UNDO; // undo on terminate
1449 }
1450
1451 timeout.tv_sec = wait_sec;
1452 timeout.tv_nsec = 0;
1453
1454 ret = semtimedop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 2 : 4), &timeout);
1455 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1456 {
1457 log_error("semtimedop(index = %d, lock read) error %d\n", index, errno);
1458 }
1459
1460 return ret;
1461 }
1462
1463 int section_list_try_rw_lock(SECTION_LIST *p_section, int wait_sec)
1464 {
1465 int index;
1466 struct sembuf sops[3];
1467 struct timespec timeout;
1468 int ret;
1469
1470 index = get_section_index(p_section);
1471 if (index < 0)
1472 {
1473 return -2;
1474 }
1475
1476 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1477 sops[0].sem_op = 0; // wait until unlocked
1478 sops[0].sem_flg = 0;
1479
1480 sops[1].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1481 sops[1].sem_op = 1; // lock
1482 sops[1].sem_flg = SEM_UNDO; // undo on terminate
1483
1484 sops[2].sem_num = (unsigned short)(index * 2); // r_sem of section index
1485 sops[2].sem_op = 0; // wait until unlocked
1486 sops[2].sem_flg = 0;
1487
1488 timeout.tv_sec = wait_sec;
1489 timeout.tv_nsec = 0;
1490
1491 ret = semtimedop(p_section_list_pool->semid, sops, 3, &timeout);
1492 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1493 {
1494 log_error("semtimedop(index = %d, lock write) error %d\n", index, errno);
1495 }
1496
1497 return ret;
1498 }
1499
1500 int section_list_rd_unlock(SECTION_LIST *p_section)
1501 {
1502 int index;
1503 struct sembuf sops[2];
1504 int ret;
1505
1506 index = get_section_index(p_section);
1507 if (index < 0)
1508 {
1509 return -2;
1510 }
1511
1512 sops[0].sem_num = (unsigned short)(index * 2); // r_sem of section index
1513 sops[0].sem_op = -1; // unlock
1514 sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1515
1516 if (index != BBS_max_section)
1517 {
1518 sops[1].sem_num = BBS_max_section * 2; // r_sem of all section
1519 sops[1].sem_op = -1; // unlock
1520 sops[1].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1521 }
1522
1523 ret = semop(p_section_list_pool->semid, sops, (index == BBS_max_section ? 1 : 2));
1524 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1525 {
1526 log_error("semop(index = %d, unlock read) error %d\n", index, errno);
1527 }
1528
1529 return ret;
1530 }
1531
1532 int section_list_rw_unlock(SECTION_LIST *p_section)
1533 {
1534 int index;
1535 struct sembuf sops[1];
1536 int ret;
1537
1538 index = get_section_index(p_section);
1539 if (index < 0)
1540 {
1541 return -2;
1542 }
1543
1544 sops[0].sem_num = (unsigned short)(index * 2 + 1); // w_sem of section index
1545 sops[0].sem_op = -1; // unlock
1546 sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
1547
1548 ret = semop(p_section_list_pool->semid, sops, 1);
1549 if (ret == -1 && errno != EAGAIN && errno != EINTR)
1550 {
1551 log_error("semop(index = %d, unlock write) error %d\n", index, errno);
1552 }
1553
1554 return ret;
1555 }
1556
1557 int section_list_rd_lock(SECTION_LIST *p_section)
1558 {
1559 int timer = 0;
1560 int sid = (p_section == NULL ? 0 : p_section->sid);
1561 int ret = -1;
1562
1563 while (!SYS_server_exit)
1564 {
1565 ret = section_list_try_rd_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1566 if (ret == 0) // success
1567 {
1568 break;
1569 }
1570 else if (errno == EAGAIN || errno == EINTR) // retry
1571 {
1572 timer++;
1573 if (timer % SECTION_TRY_LOCK_TIMES == 0)
1574 {
1575 log_error("section_list_rd_lock() tried %d times on section %d\n", sid, timer);
1576 }
1577 }
1578 else // failed
1579 {
1580 log_error("section_list_rd_lock() failed on section %d\n", sid);
1581 break;
1582 }
1583 }
1584
1585 return ret;
1586 }
1587
1588 int section_list_rw_lock(SECTION_LIST *p_section)
1589 {
1590 int timer = 0;
1591 int sid = (p_section == NULL ? 0 : p_section->sid);
1592 int ret = -1;
1593
1594 while (!SYS_server_exit)
1595 {
1596 ret = section_list_try_rw_lock(p_section, SECTION_TRY_LOCK_WAIT_TIME);
1597 if (ret == 0) // success
1598 {
1599 break;
1600 }
1601 else if (errno == EAGAIN || errno == EINTR) // retry
1602 {
1603 timer++;
1604 if (timer % SECTION_TRY_LOCK_TIMES == 0)
1605 {
1606 log_error("acquire_section_rw_lock() tried %d times on section %d\n", sid, timer);
1607 }
1608 }
1609 else // failed
1610 {
1611 log_error("acquire_section_rw_lock() failed on section %d\n", sid);
1612 break;
1613 }
1614 }
1615
1616 return ret;
1617 }

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