#include "bh_api.h" #include "svsem.h" #include "msg_mgr.h" int svsem_get(key_t key, unsigned int value) { int semid, perms; perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; semid = semget(key, 2, IPC_CREAT | IPC_EXCL | perms); if (semid != -1) { /* Successfully created the semaphore */ union semun arg; struct sembuf sop; arg.val = 0; /* So initialize it to 0 */ if (semctl(semid, 0, SETVAL, arg) == -1) err_exit(errno, "semctl 1"); arg.val = 1; if (semctl(semid, 1, SETVAL, arg) == -1) err_exit(errno, "semctl 2"); /* Perform a "no-op" semaphore operation - changes sem_otime so other processes can see we've initialized the set. */ sop.sem_num = 0; /* Operate on semaphore 0 */ sop.sem_op = value; sop.sem_flg = SEM_UNDO; if (semop(semid, &sop, 1) == -1) err_exit(errno, "semop"); } else { /* We didn't create the semaphore set */ if (errno != EEXIST) { /* Unexpected error from semget() */ err_exit(errno, "semget 1"); } else { /* Someone else already created it */ const int MAX_TRIES = 10; int j; union semun arg; struct semid_ds ds; semid = semget(key, 1, perms); /* So just get ID */ if (semid == -1) err_exit(errno, "semget 2"); /* Wait until another process has called semop() */ arg.buf = &ds; for (j = 0; j < MAX_TRIES; j++) { if (semctl(semid, 0, IPC_STAT, arg) == -1) err_exit(errno, "semctl 2"); if (ds.sem_otime != 0) /* Semop() performed? */ break; /* Yes, quit loop */ sleep(1); /* If not, wait and retry */ } if (ds.sem_otime == 0) /* Loop ran to completion! */ err_exit(errno, "Existing semaphore not initialized"); } } return semid; } /* Reserve semaphore (blocking), return 0 on success, or -1 with 'errno' set to EINTR if operation was interrupted by a signal handler */ /* Reserve semaphore - decrement it by 1 */ int svsem_wait(int semid) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = SEM_UNDO; while (semop(semid, &sops, 1) == -1) if (errno != EINTR) { err_msg(errno, "svsem_dec"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_GET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_trywait(int semid) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = IPC_NOWAIT | SEM_UNDO; #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_GET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return semop(semid, &sops, 1) ; } int svsem_timedwait(int semid, struct timespec *timeout) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = SEM_UNDO; while (semtimedop(semid, &sops, 1, timeout) == -1) if (errno != EINTR) { // err_msg(errno, "svsem_psem_timedwait"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_GET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_uni_wait(int semid) { struct timespec res; res.tv_sec = SEM_WT_TIMEOUT; res.tv_nsec = 0; while(1) { if(svsem_timedwait(semid, &res) != 0) { if(svsem_post(semid) != 0) { err_msg(errno, "_inc"); } } else { break; } } return 0; } /* Release semaphore - increment it by 1 */ int svsem_post(int semid) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = 1; sops.sem_flg = SEM_UNDO; int rv = semop(semid, &sops, 1); if (rv == -1) { // err_msg(errno, "svsem_inc"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_POST; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_cond_wait(int semid ){ struct sembuf sops[2]; union semun arg; arg.val = 1; if (semctl(semid, 1, SETVAL, arg) == -1) { err_msg(errno, "svsem_set"); return -1; } //释放mutex sops[0].sem_num = 0; sops[0].sem_op = 1; sops[0].sem_flg = SEM_UNDO; // 等待cond sops[1].sem_num = 1; sops[1].sem_op = 0; sops[1].sem_flg = SEM_UNDO; while (semop(semid, sops, 2) == -1) if (errno != EINTR) { // err_msg(errno, "Svsvsem_dec"); return -1; } //重新获取mutex sops[0].sem_num = 0; sops[0].sem_op = -1; sops[0].sem_flg = SEM_UNDO; while (semop(semid, sops, 1) == -1) if (errno != EINTR) { // err_msg(errno, "Svsvsem_dec"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_GET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_cond_signal(int semid ){ union semun arg; arg.val = 0; if (semctl(semid, 1, SETVAL, arg) == -1) { err_msg(errno, "svsem_set"); return -1; } return 0; } /** * If sem_op equals 0, the value of the semaphore is checked to see whether it * currently equals 0. If it does, the operation completes immediately; otherwise, * semop() blocks until the semaphore value becomes 0. */ int svsem_zero(int semid) { // logger.debug("%d: svsem_dec\n", semid); struct sembuf sops; sops.sem_num = 0; sops.sem_op = 0; sops.sem_flg = SEM_UNDO; while (semop(semid, &sops, 1) == -1) if (errno != EINTR) { // err_msg(errno, "svsem_zero"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_RESET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_zero_nowait(int semid) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = 0; sops.sem_flg = IPC_NOWAIT | SEM_UNDO; while (semop(semid, &sops, 1) == -1) if (errno != EINTR) { // err_msg(errno, "svsem_zero_nowait"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_RESET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_zero_timeout(int semid, struct timespec *timeout) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = 0; sops.sem_flg = SEM_UNDO; while (semtimedop(semid, &sops, 1, timeout) == -1) if (errno != EINTR) { // err_msg(errno, "svsem_zero_timeout"); return -1; } #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_RESET; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif return 0; } int svsem_set(int semid, int val) { union semun arg; arg.val = val; return semctl(semid, 0, SETVAL, arg); } void svsem_remove(int semid) { union semun dummy; if (semctl(semid, 0, IPC_RMID, dummy) == -1) err_msg(errno, "svsem_remove"); #if defined(MSG_HANDLER) Msg_info msg_obj; msg_obj.key = inter_key_get(); msg_obj.id = semid; msg_obj.act = SEM_RM; msg_distrib(SEM_TYPE_ID, &msg_obj); #endif }