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

Annotation of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations)
Thu Oct 23 01:58:05 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.16: +7 -0 lines
Content type: text/x-csrc
Revert "Set user_list_[rd|rw]_(un)lock as public functions"

This reverts commit ea1c349d0feaaf9db4458aca239daf29894245de.

1 sysadm 1.1 /***************************************************************************
2 sysadm 1.6 user_list.c - description
3     -------------------
4     Copyright : (C) 2004-2025 by Leaflet
5     Email : leaflet@leafok.com
6 sysadm 1.1 ***************************************************************************/
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     #include "common.h"
18     #include "database.h"
19     #include "log.h"
20 sysadm 1.6 #include "trie_dict.h"
21 sysadm 1.1 #include "user_list.h"
22     #include <errno.h>
23     #include <stdlib.h>
24     #include <string.h>
25     #include <time.h>
26     #include <sys/ipc.h>
27     #include <sys/mman.h>
28 sysadm 1.2 #include <sys/param.h>
29 sysadm 1.1 #include <sys/sem.h>
30     #include <sys/shm.h>
31    
32     #ifdef _SEM_SEMUN_UNDEFINED
33     union semun
34     {
35 sysadm 1.6 int val; /* Value for SETVAL */
36     struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
37     unsigned short *array; /* Array for GETALL, SETALL */
38     struct seminfo *__buf; /* Buffer for IPC_INFO
39     (Linux-specific) */
40 sysadm 1.1 };
41     #endif // #ifdef _SEM_SEMUN_UNDEFINED
42    
43     #define USER_LIST_TRY_LOCK_WAIT_TIME 1 // second
44     #define USER_LIST_TRY_LOCK_TIMES 10
45    
46     struct user_list_pool_t
47     {
48 sysadm 1.6 int shmid;
49     int semid;
50     USER_LIST user_list[2];
51     USER_LIST *p_current;
52     USER_LIST *p_new;
53     USER_ONLINE_LIST user_online_list[2];
54     USER_ONLINE_LIST *p_online_current;
55     USER_ONLINE_LIST *p_online_new;
56 sysadm 1.1 };
57     typedef struct user_list_pool_t USER_LIST_POOL;
58    
59     static USER_LIST_POOL *p_user_list_pool = NULL;
60 sysadm 1.6 static TRIE_NODE *p_trie_action_dict = NULL;
61    
62     typedef struct user_action_map_t
63     {
64     char name[BBS_current_action_max_len + 1];
65     char title[BBS_current_action_max_len + 1];
66     } USER_ACTION_MAP;
67    
68     const USER_ACTION_MAP user_action_map[] =
69     {
70     {"ARTICLE_FAVOR", "浏览收藏"},
71     {"BBS_NET", "站点穿梭"},
72     {"CHICKEN", "电子小鸡"},
73     {"EDIT_ARTICLE", "修改文章"},
74 sysadm 1.7 {"LOGIN", "进入大厅"},
75 sysadm 1.6 {"MENU", "菜单选择"},
76     {"POST_ARTICLE", "撰写文章"},
77     {"REPLY_ARTICLE", "回复文章"},
78     {"USER_LIST", "查花名册"},
79     {"USER_ONLINE", "环顾四周"},
80     {"VIEW_ARTICLE", "阅读文章"},
81 sysadm 1.7 {"VIEW_FILE", "查看文档"},
82     {"WWW", "Web浏览"}};
83 sysadm 1.6
84 sysadm 1.7 const int user_action_map_size = sizeof(user_action_map) / sizeof(USER_ACTION_MAP);
85 sysadm 1.1
86 sysadm 1.17 static int user_list_try_rd_lock(int semid, int wait_sec);
87     static int user_list_try_rw_lock(int semid, int wait_sec);
88     static int user_list_rd_unlock(int semid);
89     static int user_list_rw_unlock(int semid);
90     static int user_list_rd_lock(int semid);
91     static int user_list_rw_lock(int semid);
92    
93 sysadm 1.6 static int user_list_load(MYSQL *db, USER_LIST *p_list);
94     static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);
95    
96 sysadm 1.8 static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
97     {
98     const USER_INFO_INDEX_UID *p1 = ptr1;
99     const USER_INFO_INDEX_UID *p2 = ptr2;
100    
101     if (p1->uid < p2->uid)
102     {
103     return -1;
104     }
105     else if (p1->uid > p2->uid)
106     {
107     return 1;
108     }
109 sysadm 1.10 else if (p1->id < p2->id)
110     {
111     return -1;
112     }
113     else if (p1->id > p2->id)
114     {
115     return 1;
116     }
117 sysadm 1.8 return 0;
118     }
119    
120 sysadm 1.1 int user_list_load(MYSQL *db, USER_LIST *p_list)
121     {
122 sysadm 1.6 MYSQL_RES *rs = NULL;
123     MYSQL_ROW row;
124     char sql[SQL_BUFFER_LEN];
125     int ret = 0;
126 sysadm 1.15 int i;
127     int j;
128     int32_t last_uid;
129     size_t intro_buf_offset;
130 sysadm 1.14 size_t intro_len;
131 sysadm 1.6
132     if (db == NULL || p_list == NULL)
133     {
134     log_error("NULL pointer error\n");
135     return -1;
136     }
137    
138 sysadm 1.10 if (p_list->user_count > 0)
139     {
140     last_uid = p_list->users[p_list->user_count - 1].uid;
141     }
142 sysadm 1.15 else
143     {
144     last_uid = -1;
145     }
146 sysadm 1.10
147 sysadm 1.6 snprintf(sql, sizeof(sql),
148 sysadm 1.14 "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, visit_count, "
149     "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(birthday), `introduction` "
150 sysadm 1.6 "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
151     "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
152 sysadm 1.8 "WHERE enable ORDER BY username");
153 sysadm 1.6
154     if (mysql_query(db, sql) != 0)
155     {
156     log_error("Query user info error: %s\n", mysql_error(db));
157     ret = -1;
158     goto cleanup;
159     }
160    
161     if ((rs = mysql_use_result(db)) == NULL)
162     {
163     log_error("Get user info data failed\n");
164     ret = -1;
165     goto cleanup;
166     }
167    
168 sysadm 1.14 intro_buf_offset = 0;
169 sysadm 1.6 i = 0;
170     while ((row = mysql_fetch_row(rs)))
171     {
172 sysadm 1.8 // record
173     p_list->users[i].id = i;
174 sysadm 1.6 p_list->users[i].uid = atoi(row[0]);
175     strncpy(p_list->users[i].username, row[1], sizeof(p_list->users[i].username) - 1);
176     p_list->users[i].username[sizeof(p_list->users[i].username) - 1] = '\0';
177     strncpy(p_list->users[i].nickname, row[2], sizeof(p_list->users[i].nickname) - 1);
178     p_list->users[i].nickname[sizeof(p_list->users[i].nickname) - 1] = '\0';
179     p_list->users[i].gender = row[3][0];
180     p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
181     p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
182     p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
183 sysadm 1.14 p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
184     p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
185     p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
186     p_list->users[i].birthday = (row[10] == NULL ? 0 : atol(row[10]));
187     intro_len = strlen((row[11] == NULL ? "" : row[11]));
188     if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
189     {
190     log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
191     break;
192     }
193     memcpy(p_list->user_intro_buf + intro_buf_offset,
194     (row[11] == NULL ? "" : row[11]),
195     intro_len + 1);
196     p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
197     intro_buf_offset += (intro_len + 1);
198 sysadm 1.6
199     i++;
200     if (i >= BBS_max_user_count)
201     {
202     log_error("Too many users, exceed limit %d\n", BBS_max_user_count);
203     break;
204     }
205     }
206     mysql_free_result(rs);
207     rs = NULL;
208 sysadm 1.1
209 sysadm 1.10 if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
210     {
211 sysadm 1.15 // Rebuild index
212     for (j = 0; j < i; j++)
213     {
214     p_list->index_uid[j].uid = p_list->users[j].uid;
215     p_list->index_uid[j].id = j;
216     }
217    
218     qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
219 sysadm 1.12
220 sysadm 1.10 #ifdef _DEBUG
221     log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
222     #endif
223     }
224    
225 sysadm 1.6 p_list->user_count = i;
226 sysadm 1.1
227     #ifdef _DEBUG
228 sysadm 1.6 log_error("Loaded %d users\n", p_list->user_count);
229 sysadm 1.1 #endif
230    
231     cleanup:
232 sysadm 1.6 mysql_free_result(rs);
233 sysadm 1.1
234 sysadm 1.6 return ret;
235     }
236    
237     int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list)
238     {
239     MYSQL_RES *rs = NULL;
240     MYSQL_ROW row;
241     char sql[SQL_BUFFER_LEN];
242     int ret = 0;
243     int i;
244 sysadm 1.15 int j;
245 sysadm 1.6
246     if (db == NULL || p_list == NULL)
247     {
248     log_error("NULL pointer error\n");
249     return -1;
250     }
251    
252     snprintf(sql, sizeof(sql),
253     "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
254     "UNIX_TIMESTAMP(last_tm) FROM user_online "
255 sysadm 1.9 "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) AND UID <> 0 "
256 sysadm 1.6 "ORDER BY last_tm DESC",
257     BBS_user_off_line);
258    
259     if (mysql_query(db, sql) != 0)
260     {
261     log_error("Query user online error: %s\n", mysql_error(db));
262     ret = -1;
263     goto cleanup;
264     }
265    
266     if ((rs = mysql_use_result(db)) == NULL)
267     {
268     log_error("Get user online data failed\n");
269     ret = -1;
270     goto cleanup;
271     }
272    
273     i = 0;
274     while ((row = mysql_fetch_row(rs)))
275     {
276 sysadm 1.8 p_list->users[i].id = i;
277 sysadm 1.6 strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);
278 sysadm 1.8 p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';
279 sysadm 1.6
280 sysadm 1.12 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) <= 0)
281 sysadm 1.7 {
282 sysadm 1.12 log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
283 sysadm 1.9 continue;
284 sysadm 1.7 }
285 sysadm 1.6
286     strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);
287     p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';
288    
289     strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);
290     p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';
291     p_list->users[i].current_action_title = NULL;
292     if (p_list->users[i].current_action[0] == '\0')
293     {
294 sysadm 1.7 p_list->users[i].current_action_title = "";
295 sysadm 1.6 }
296     else if (trie_dict_get(p_trie_action_dict, p_list->users[i].current_action, (int64_t *)(&(p_list->users[i].current_action_title))) < 0)
297     {
298     log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
299     p_list->users[i].current_action, p_list->users[i].session_id);
300     continue;
301     }
302    
303     p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
304     p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
305    
306     i++;
307     if (i >= BBS_max_user_online_count)
308     {
309     log_error("Too many online users, exceed limit %d\n", BBS_max_user_online_count);
310     break;
311     }
312     }
313     mysql_free_result(rs);
314     rs = NULL;
315    
316 sysadm 1.10 if (i > 0)
317     {
318 sysadm 1.15 // Rebuild index
319     for (j = 0; j < i; j++)
320     {
321     p_list->index_uid[j].uid = p_list->users[j].user_info.uid;
322     p_list->index_uid[j].id = j;
323     }
324    
325 sysadm 1.10 qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
326 sysadm 1.15
327 sysadm 1.10 #ifdef _DEBUG
328     log_error("Rebuild index of %d online users\n", i);
329     #endif
330     }
331    
332 sysadm 1.6 p_list->user_count = i;
333    
334     #ifdef _DEBUG
335 sysadm 1.10 log_error("Loaded %d online users\n", p_list->user_count);
336 sysadm 1.6 #endif
337    
338     cleanup:
339     mysql_free_result(rs);
340    
341     return ret;
342 sysadm 1.1 }
343    
344     int user_list_pool_init(void)
345     {
346 sysadm 1.6 int shmid;
347     int semid;
348     int proj_id;
349     key_t key;
350     size_t size;
351     void *p_shm;
352     union semun arg;
353     int i;
354    
355     if (p_user_list_pool != NULL || p_trie_action_dict != NULL)
356     {
357     log_error("p_user_list_pool already initialized\n");
358     return -1;
359     }
360    
361     p_trie_action_dict = trie_dict_create();
362     if (p_trie_action_dict == NULL)
363     {
364     log_error("trie_dict_create() error\n");
365     return -1;
366     }
367    
368     for (i = 0; i < user_action_map_size; i++)
369     {
370     if (trie_dict_set(p_trie_action_dict, user_action_map[i].name, (int64_t)(user_action_map[i].title)) < 0)
371     {
372     log_error("trie_dict_set(p_trie_action_dict, %s) error\n", user_action_map[i].name);
373     }
374     }
375    
376     // Allocate shared memory
377     proj_id = (int)(time(NULL) % getpid());
378     key = ftok(VAR_USER_LIST_SHM, proj_id);
379     if (key == -1)
380     {
381     log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);
382     return -2;
383     }
384    
385     size = sizeof(USER_LIST_POOL);
386     shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
387     if (shmid == -1)
388     {
389     log_error("shmget(size = %d) error (%d)\n", size, errno);
390     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     }
398    
399     p_user_list_pool = p_shm;
400     p_user_list_pool->shmid = shmid;
401    
402     // Allocate semaphore as user list pool lock
403     size = 2; // r_sem and w_sem
404     semid = semget(key, (int)size, IPC_CREAT | IPC_EXCL | 0600);
405     if (semid == -1)
406     {
407     log_error("semget(user_list_pool_sem, size = %d) error (%d)\n", size, errno);
408     return -3;
409     }
410    
411     // Initialize sem value to 0
412     arg.val = 0;
413     for (i = 0; i < size; i++)
414     {
415     if (semctl(semid, i, SETVAL, arg) == -1)
416     {
417     log_error("semctl(user_list_pool_sem, SETVAL) error (%d)\n", errno);
418     return -3;
419     }
420     }
421    
422     p_user_list_pool->semid = semid;
423    
424     // Set user counts to 0
425     p_user_list_pool->user_list[0].user_count = 0;
426     p_user_list_pool->user_list[1].user_count = 0;
427    
428     p_user_list_pool->p_current = &(p_user_list_pool->user_list[0]);
429     p_user_list_pool->p_new = &(p_user_list_pool->user_list[1]);
430 sysadm 1.1
431 sysadm 1.6 p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
432     p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
433 sysadm 1.1
434 sysadm 1.6 return 0;
435 sysadm 1.1 }
436    
437     void user_list_pool_cleanup(void)
438     {
439 sysadm 1.6 int shmid;
440 sysadm 1.1
441 sysadm 1.6 if (p_user_list_pool == NULL)
442     {
443     return;
444     }
445    
446     shmid = p_user_list_pool->shmid;
447    
448     if (semctl(p_user_list_pool->semid, 0, IPC_RMID) == -1)
449     {
450     log_error("semctl(semid = %d, IPC_RMID) error (%d)\n", p_user_list_pool->semid, errno);
451     }
452    
453     if (shmdt(p_user_list_pool) == -1)
454     {
455     log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
456     }
457    
458     if (shmctl(shmid, IPC_RMID, NULL) == -1)
459     {
460     log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
461     }
462    
463     p_user_list_pool = NULL;
464    
465     if (p_trie_action_dict != NULL)
466     {
467     trie_dict_destroy(p_trie_action_dict);
468 sysadm 1.1
469 sysadm 1.6 p_trie_action_dict = NULL;
470     }
471 sysadm 1.1 }
472    
473     int set_user_list_pool_shm_readonly(void)
474     {
475 sysadm 1.6 int shmid;
476     void *p_shm;
477 sysadm 1.1
478 sysadm 1.6 if (p_user_list_pool == NULL)
479     {
480     log_error("p_user_list_pool not initialized\n");
481     return -1;
482     }
483    
484     shmid = p_user_list_pool->shmid;
485    
486     // Remap shared memory in read-only mode
487     p_shm = shmat(shmid, p_user_list_pool, SHM_RDONLY | SHM_REMAP);
488     if (p_shm == (void *)-1)
489     {
490     log_error("shmat(user_list_pool shmid = %d) error (%d)\n", shmid, errno);
491     return -3;
492     }
493 sysadm 1.1
494 sysadm 1.6 p_user_list_pool = p_shm;
495 sysadm 1.1
496 sysadm 1.6 return 0;
497 sysadm 1.1 }
498    
499     int detach_user_list_pool_shm(void)
500     {
501 sysadm 1.6 if (p_user_list_pool != NULL && shmdt(p_user_list_pool) == -1)
502     {
503     log_error("shmdt(user_list_pool) error (%d)\n", errno);
504     return -1;
505     }
506    
507     p_user_list_pool = NULL;
508    
509     return 0;
510     }
511    
512     int user_list_pool_reload(int online_user)
513     {
514     MYSQL *db = NULL;
515     USER_LIST *p_tmp;
516     USER_ONLINE_LIST *p_online_tmp;
517 sysadm 1.11 int ret = 0;
518 sysadm 1.6
519     if (p_user_list_pool == NULL)
520     {
521     log_error("p_user_list_pool not initialized\n");
522     return -1;
523     }
524    
525     db = db_open();
526     if (db == NULL)
527     {
528     log_error("db_open() error: %s\n", mysql_error(db));
529     return -1;
530     }
531    
532     if (online_user)
533     {
534     if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
535     {
536     log_error("user_online_list_load() error\n");
537 sysadm 1.11 ret = -2;
538     goto cleanup;
539 sysadm 1.6 }
540     }
541     else
542     {
543     if (user_list_load(db, p_user_list_pool->p_new) < 0)
544     {
545     log_error("user_list_load() error\n");
546 sysadm 1.11 ret = -2;
547     goto cleanup;
548 sysadm 1.6 }
549     }
550    
551     mysql_close(db);
552 sysadm 1.11 db = NULL;
553 sysadm 1.6
554     if (user_list_rw_lock(p_user_list_pool->semid) < 0)
555     {
556     log_error("user_list_rw_lock() error\n");
557 sysadm 1.11 ret = -3;
558     goto cleanup;
559 sysadm 1.6 }
560    
561     if (online_user)
562     {
563     // Swap p_online_current and p_online_new
564     p_online_tmp = p_user_list_pool->p_online_current;
565     p_user_list_pool->p_online_current = p_user_list_pool->p_online_new;
566     p_user_list_pool->p_online_new = p_online_tmp;
567     }
568     else
569     {
570     // Swap p_current and p_new
571     p_tmp = p_user_list_pool->p_current;
572     p_user_list_pool->p_current = p_user_list_pool->p_new;
573     p_user_list_pool->p_new = p_tmp;
574     }
575    
576     if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
577     {
578     log_error("user_list_rw_unlock() error\n");
579 sysadm 1.11 ret = -3;
580     goto cleanup;
581 sysadm 1.6 }
582 sysadm 1.1
583 sysadm 1.11 cleanup:
584     mysql_close(db);
585    
586     return ret;
587 sysadm 1.1 }
588    
589 sysadm 1.5 int user_list_try_rd_lock(int semid, int wait_sec)
590 sysadm 1.1 {
591 sysadm 1.6 struct sembuf sops[2];
592     struct timespec timeout;
593     int ret;
594    
595     sops[0].sem_num = 1; // w_sem
596     sops[0].sem_op = 0; // wait until unlocked
597     sops[0].sem_flg = 0;
598    
599     sops[1].sem_num = 0; // r_sem
600     sops[1].sem_op = 1; // lock
601     sops[1].sem_flg = SEM_UNDO; // undo on terminate
602    
603     timeout.tv_sec = wait_sec;
604     timeout.tv_nsec = 0;
605    
606     ret = semtimedop(semid, sops, 2, &timeout);
607     if (ret == -1 && errno != EAGAIN && errno != EINTR)
608     {
609     log_error("semtimedop(lock read) error %d\n", errno);
610     }
611 sysadm 1.1
612 sysadm 1.6 return ret;
613 sysadm 1.1 }
614    
615 sysadm 1.5 int user_list_try_rw_lock(int semid, int wait_sec)
616 sysadm 1.1 {
617 sysadm 1.6 struct sembuf sops[3];
618     struct timespec timeout;
619     int ret;
620    
621     sops[0].sem_num = 1; // w_sem
622     sops[0].sem_op = 0; // wait until unlocked
623     sops[0].sem_flg = 0;
624    
625     sops[1].sem_num = 1; // w_sem
626     sops[1].sem_op = 1; // lock
627     sops[1].sem_flg = SEM_UNDO; // undo on terminate
628    
629     sops[2].sem_num = 0; // r_sem
630     sops[2].sem_op = 0; // wait until unlocked
631     sops[2].sem_flg = 0;
632    
633     timeout.tv_sec = wait_sec;
634     timeout.tv_nsec = 0;
635    
636     ret = semtimedop(semid, sops, 3, &timeout);
637     if (ret == -1 && errno != EAGAIN && errno != EINTR)
638     {
639     log_error("semtimedop(lock write) error %d\n", errno);
640     }
641 sysadm 1.1
642 sysadm 1.6 return ret;
643 sysadm 1.1 }
644    
645 sysadm 1.5 int user_list_rd_unlock(int semid)
646 sysadm 1.1 {
647 sysadm 1.6 struct sembuf sops[2];
648     int ret;
649 sysadm 1.1
650 sysadm 1.6 sops[0].sem_num = 0; // r_sem
651     sops[0].sem_op = -1; // unlock
652     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
653    
654     ret = semop(semid, sops, 1);
655     if (ret == -1 && errno != EAGAIN && errno != EINTR)
656     {
657     log_error("semop(unlock read) error %d\n", errno);
658     }
659 sysadm 1.1
660 sysadm 1.6 return ret;
661 sysadm 1.1 }
662    
663 sysadm 1.5 int user_list_rw_unlock(int semid)
664 sysadm 1.1 {
665 sysadm 1.6 struct sembuf sops[1];
666     int ret;
667 sysadm 1.1
668 sysadm 1.6 sops[0].sem_num = 1; // w_sem
669     sops[0].sem_op = -1; // unlock
670     sops[0].sem_flg = IPC_NOWAIT | SEM_UNDO; // no wait
671    
672     ret = semop(semid, sops, 1);
673     if (ret == -1 && errno != EAGAIN && errno != EINTR)
674     {
675     log_error("semop(unlock write) error %d\n", errno);
676     }
677 sysadm 1.1
678 sysadm 1.6 return ret;
679 sysadm 1.1 }
680    
681 sysadm 1.5 int user_list_rd_lock(int semid)
682 sysadm 1.1 {
683 sysadm 1.6 int timer = 0;
684     int ret = -1;
685 sysadm 1.1
686 sysadm 1.6 while (!SYS_server_exit)
687     {
688     ret = user_list_try_rd_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
689     if (ret == 0) // success
690     {
691     break;
692     }
693     else if (errno == EAGAIN || errno == EINTR) // retry
694     {
695     timer++;
696     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
697     {
698     log_error("user_list_try_rd_lock() tried %d times\n", timer);
699     }
700     }
701     else // failed
702     {
703     log_error("user_list_try_rd_lock() failed\n");
704     break;
705     }
706     }
707 sysadm 1.1
708 sysadm 1.6 return ret;
709 sysadm 1.1 }
710    
711 sysadm 1.5 int user_list_rw_lock(int semid)
712 sysadm 1.1 {
713 sysadm 1.6 int timer = 0;
714     int ret = -1;
715 sysadm 1.1
716 sysadm 1.6 while (!SYS_server_exit)
717     {
718     ret = user_list_try_rw_lock(semid, USER_LIST_TRY_LOCK_WAIT_TIME);
719     if (ret == 0) // success
720     {
721     break;
722     }
723     else if (errno == EAGAIN || errno == EINTR) // retry
724     {
725     timer++;
726     if (timer % USER_LIST_TRY_LOCK_TIMES == 0)
727     {
728     log_error("user_list_try_rw_lock() tried %d times\n", timer);
729     }
730     }
731     else // failed
732     {
733     log_error("user_list_try_rw_lock() failed\n");
734     break;
735     }
736     }
737 sysadm 1.1
738 sysadm 1.6 return ret;
739 sysadm 1.1 }
740 sysadm 1.2
741     int query_user_list(int page_id, USER_INFO *p_users, int *p_user_count, int *p_page_count)
742     {
743 sysadm 1.6 int ret = 0;
744 sysadm 1.2
745 sysadm 1.6 if (p_users == NULL || p_user_count == NULL || p_page_count == NULL)
746     {
747     log_error("NULL pointer error\n");
748     return -1;
749     }
750    
751 sysadm 1.12 *p_user_count = 0;
752     *p_page_count = 0;
753    
754 sysadm 1.6 // acquire lock of user list
755     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
756     {
757     log_error("user_list_rd_lock() error\n");
758     return -2;
759     }
760    
761     if (p_user_list_pool->p_current->user_count == 0)
762     {
763     // empty list
764     ret = 0;
765     goto cleanup;
766     }
767    
768     *p_page_count = p_user_list_pool->p_current->user_count / BBS_user_limit_per_page +
769     (p_user_list_pool->p_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
770    
771     if (page_id < 0 || page_id >= *p_page_count)
772     {
773     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
774     ret = -3;
775     goto cleanup;
776     }
777    
778     *p_user_count = MIN(BBS_user_limit_per_page,
779     p_user_list_pool->p_current->user_count -
780     page_id * BBS_user_limit_per_page);
781    
782     memcpy(p_users,
783     p_user_list_pool->p_current->users + page_id * BBS_user_limit_per_page,
784     sizeof(USER_INFO) * (size_t)(*p_user_count));
785    
786     cleanup:
787     // release lock of user list
788     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
789     {
790     log_error("user_list_rd_unlock() error\n");
791     ret = -1;
792     }
793    
794     return ret;
795     }
796    
797     int query_user_online_list(int page_id, USER_ONLINE_INFO *p_online_users, int *p_user_count, int *p_page_count)
798     {
799     int ret = 0;
800    
801     if (p_online_users == NULL || p_user_count == NULL || p_page_count == NULL)
802     {
803     log_error("NULL pointer error\n");
804     return -1;
805     }
806    
807 sysadm 1.12 *p_user_count = 0;
808     *p_page_count = 0;
809    
810 sysadm 1.6 // acquire lock of user list
811     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
812     {
813     log_error("user_list_rd_lock() error\n");
814     return -2;
815     }
816    
817     if (p_user_list_pool->p_online_current->user_count == 0)
818     {
819     // empty list
820     ret = 0;
821     goto cleanup;
822     }
823    
824     *p_page_count = p_user_list_pool->p_online_current->user_count / BBS_user_limit_per_page +
825     (p_user_list_pool->p_online_current->user_count % BBS_user_limit_per_page == 0 ? 0 : 1);
826    
827     if (page_id < 0 || page_id >= *p_page_count)
828     {
829     log_error("Invalid page_id = %d, not in range [0, %d)\n", page_id, *p_page_count);
830     ret = -3;
831     goto cleanup;
832     }
833    
834     *p_user_count = MIN(BBS_user_limit_per_page,
835     p_user_list_pool->p_online_current->user_count -
836     page_id * BBS_user_limit_per_page);
837    
838     memcpy(p_online_users,
839     p_user_list_pool->p_online_current->users + page_id * BBS_user_limit_per_page,
840     sizeof(USER_ONLINE_INFO) * (size_t)(*p_user_count));
841 sysadm 1.2
842     cleanup:
843 sysadm 1.6 // release lock of user list
844     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
845     {
846     log_error("user_list_rd_unlock() error\n");
847     ret = -1;
848     }
849 sysadm 1.2
850 sysadm 1.6 return ret;
851 sysadm 1.2 }
852 sysadm 1.4
853 sysadm 1.8 int query_user_info(int32_t id, USER_INFO *p_user)
854     {
855     int ret = 0;
856    
857     if (p_user == NULL)
858     {
859     log_error("NULL pointer error\n");
860     return -1;
861     }
862    
863     // acquire lock of user list
864     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
865     {
866     log_error("user_list_rd_lock() error\n");
867     return -2;
868     }
869    
870     if (id >= 0 && id < p_user_list_pool->p_current->user_count) // Found
871     {
872     *p_user = p_user_list_pool->p_current->users[id];
873     ret = 1;
874     }
875    
876     // release lock of user list
877     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
878     {
879     log_error("user_list_rd_unlock() error\n");
880     ret = -1;
881     }
882    
883     return ret;
884     }
885    
886     int query_user_info_by_uid(int32_t uid, USER_INFO *p_user)
887 sysadm 1.4 {
888 sysadm 1.6 int left;
889     int right;
890     int mid;
891 sysadm 1.8 int32_t id;
892 sysadm 1.6 int ret = 0;
893    
894     if (p_user == NULL)
895     {
896     log_error("NULL pointer error\n");
897     return -1;
898     }
899    
900     // acquire lock of user list
901     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
902     {
903     log_error("user_list_rd_lock() error\n");
904     return -2;
905     }
906    
907     left = 0;
908     right = p_user_list_pool->p_current->user_count - 1;
909    
910     while (left < right)
911     {
912     mid = (left + right) / 2;
913 sysadm 1.8 if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
914 sysadm 1.6 {
915     right = mid;
916     }
917 sysadm 1.8 else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
918 sysadm 1.6 {
919     left = mid + 1;
920     }
921 sysadm 1.8 else // if (uid == p_user_list_pool->p_current->index_uid[mid].uid)
922 sysadm 1.6 {
923     left = mid;
924     break;
925     }
926     }
927    
928 sysadm 1.8 if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
929     {
930     id = p_user_list_pool->p_current->index_uid[left].id;
931 sysadm 1.12 *p_user = p_user_list_pool->p_current->users[id];
932     ret = 1;
933 sysadm 1.8 }
934    
935     // release lock of user list
936     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
937     {
938     log_error("user_list_rd_unlock() error\n");
939     ret = -1;
940     }
941    
942     return ret;
943     }
944    
945     int query_user_online_info(int32_t id, USER_ONLINE_INFO *p_user)
946     {
947     int ret = 0;
948    
949     if (p_user == NULL)
950     {
951     log_error("NULL pointer error\n");
952     return -1;
953     }
954    
955     // acquire lock of user list
956     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
957     {
958     log_error("user_list_rd_lock() error\n");
959     return -2;
960     }
961    
962     if (id >= 0 && id < p_user_list_pool->p_online_current->user_count) // Found
963 sysadm 1.6 {
964 sysadm 1.8 *p_user = p_user_list_pool->p_online_current->users[id];
965 sysadm 1.6 ret = 1;
966     }
967    
968     // release lock of user list
969     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
970     {
971     log_error("user_list_rd_unlock() error\n");
972     ret = -1;
973     }
974 sysadm 1.4
975 sysadm 1.6 return ret;
976 sysadm 1.4 }
977 sysadm 1.11
978     int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
979     {
980     int left;
981     int right;
982     int mid;
983     int32_t id;
984     int ret = 0;
985     int i;
986    
987     if (p_users == NULL || p_user_cnt == NULL)
988     {
989     log_error("NULL pointer error\n");
990     return -1;
991     }
992    
993     // acquire lock of user list
994     if (user_list_rd_lock(p_user_list_pool->semid) < 0)
995     {
996     log_error("user_list_rd_lock() error\n");
997     return -2;
998     }
999    
1000     left = start_id;
1001     right = p_user_list_pool->p_online_current->user_count - 1;
1002    
1003     while (left < right)
1004     {
1005     mid = (left + right) / 2;
1006     if (uid < p_user_list_pool->p_online_current->index_uid[mid].uid)
1007     {
1008     right = mid;
1009     }
1010     else if (uid > p_user_list_pool->p_online_current->index_uid[mid].uid)
1011     {
1012     left = mid + 1;
1013     }
1014     else // if (uid == p_user_list_pool->p_online_current->index_uid[mid].uid)
1015     {
1016     left = mid;
1017     break;
1018     }
1019     }
1020    
1021     if (uid == p_user_list_pool->p_online_current->index_uid[left].uid)
1022     {
1023     right = left;
1024     left = start_id;
1025    
1026     while (left < right)
1027     {
1028     mid = (left + right) / 2;
1029     if (uid - 1 < p_user_list_pool->p_online_current->index_uid[mid].uid)
1030     {
1031     right = mid;
1032     }
1033     else // if (uid - 1 >= p_user_list_pool->p_online_current->index_uid[mid].uid)
1034     {
1035     left = mid + 1;
1036     }
1037     }
1038    
1039 sysadm 1.13 for (i = 0;
1040     left < p_user_list_pool->p_online_current->user_count && i < *p_user_cnt &&
1041     uid == p_user_list_pool->p_online_current->index_uid[left].uid;
1042     left++, i++)
1043 sysadm 1.11 {
1044 sysadm 1.13 id = p_user_list_pool->p_online_current->index_uid[left].id;
1045 sysadm 1.12 p_users[i] = p_user_list_pool->p_online_current->users[id];
1046 sysadm 1.11 }
1047    
1048 sysadm 1.12 if (i > 0)
1049 sysadm 1.11 {
1050     *p_user_cnt = i;
1051     ret = 1;
1052     }
1053     }
1054    
1055     // release lock of user list
1056     if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1057     {
1058     log_error("user_list_rd_unlock() error\n");
1059     ret = -1;
1060     }
1061    
1062     return ret;
1063     }

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