/[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.21 - (hide annotations)
Thu Oct 23 11:10:34 2025 UTC (4 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.20: +6 -4 lines
Content type: text/x-csrc
Format user info display

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

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