close


筆者使用 Linux SIGUSR1 訊號 [ sigtimedwait() / sigqueue() ] 寫了一組簡單的行程間通訊範例 sigw.c / sigq.c . 

 

Sigw.c

 

I. sigw 是用來接收 messages. 我選擇 Linux SIGUSR1 訊號. 因為這兒使用了 sigtimedwait(),
      所以我們要 block 這個 Linux 訊號. 

 

      pthread_sigmask(SIG_BLOCK, &nset, &oset);

 

II. 接著將著 pthread_sigmask() 導出的 oset push 至 pthread cleanup stack. 

 

      pthread_cleanup_push((void (*)(void *))RestoreSigmask, (void *)&oset);

 

III. pthread_cleanup_push() 以及 pthread_cleanup_pop() 是 counterpart 函數. 在適當時機
      呼叫 pthread_cleanup_pop() , cleanup rountine 會被呼叫.
      在這裡 cleanup rountine 是 RestoreSigmask(). 也因此 unblock SIGUSR1. 

 

      pthread_cleanup_pop(1);

 

      block 是阻斷的意思. unblock 是 block 的相反詞. 

 

IV. 進入無窮迴圈 , 第1個呼叫 sigwaitinfo(). 
      sigwaitinfo() suspends execution of the calling thread until one of the signals in set is pending. 
      sigtimedwait() operates in exactly the same way as sigwaitinfo() except that it has an additional
      argument, timeout, which specifies a minimum interval for which the thread is suspended
      waiting for a signal. 

 

        signo = sigtimedwait(&nset, &info, &ts);
        if (-1 == signo && errno == EAGAIN)
                continue;
        if (-1 == signo && errno == EINTR)
            continue;
 

      if (-1 == signo && errno == EAGAIN)  這個 situation 是 TIMEOUT. 

 

V. 假如 sigw 收到 Linux SIGUSR1 訊號, 我們這樣處理. 

 

        r = info.si_value.sival_int;
        sprintf(path, "/tmp/msg-%08X.txt", r);
        f = fopen(path, "r");
        if (0 == f) {
            printf("(%s %d) `%s` NOT FOUND\n", __FILE__, __LINE__, path);
            continue;
        }
        fgets(msg, sizeof(msg), f);
        fclose(f), f = 0;
        unlink(path);
 

        收到 message 了以後別忘了 unlink(). 
        這個 info.si_value.sival_int 以及 /tmp/msg-XXXXXXXX.txt 其實是 sigq 傳送過來的.

        以下是範例程式 sigw.c. 

 

sigw.c
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <regex.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <signal.h>
#include <sys/msg.h>
#include <pthread.h>
#include <assert.h>
#include <regex.h>

///////////////////////////////////////////////////////////
static void RestoreSigmask(void *param) {
    pthread_sigmask(SIG_SETMASK, (sigset_t *)param, NULL);
}
int main( int argc, char *argv[] ) {
    sigset_t nset, oset;
    struct timespec ts = {0};
    siginfo_t info;
    FILE *f;
    int res = 0, signo = 0, r = 0;
    char path[1024] = {0}, msg[1024] = {0};
    pid_t pid = -1;

///////////////////////////////////////////////////////////
    sigemptyset(&nset), sigaddset(&nset, SIGUSR1), sigaddset(&nset, SIGINT), sigaddset(&nset, SIGTERM);
    pthread_sigmask(SIG_BLOCK, &nset, &oset);
#if 1
    pthread_cleanup_push(RestoreSigmask, (void *)&oset);
#else
    pthread_cleanup_push((void (*routine)(void *))pthread_sigmask, (void *)&oset);
#endif // 1

///////////////////////////////////////////////////////////
    ts.tv_sec = 0, ts.tv_nsec = 1000000 * 300;
    for(;;) {
        memset(&info, 0, sizeof(siginfo_t));
        signo = sigtimedwait(&nset, &info, &ts);
        if (-1 == signo && errno == EAGAIN)
                continue;
        if (-1 == signo && errno == EINTR)
            continue;
        if (-1 == signo) {
            printf("(%s %d) SIGTIMEDWAIT() fail, errno=%d, EXIT() \n", __FILE__, __LINE__, errno);
            res = errno;
            break;
        }
        if(SIGINT == signo) {
            printf("(%s %d) SIGINT\n", __FILE__, __LINE__);
            break;
        }
        if(SIGTERM == signo) {
            printf("(%s %d) SIGTERM\n", __FILE__, __LINE__);
            break;
        }
        if(SIGUSR1 != signo) {
            printf("(%s %d) UNTRAP SIGNAL=%d\n", __FILE__, __LINE__, signo);
            continue;
        }
        r = info.si_value.sival_int;
        if (0 == r) {
            printf("(%s %d) SIGUSR1=%d\n", __FILE__, __LINE__, info.si_value.sival_int);
            continue;
        }
        r = info.si_value.sival_int;
        sprintf(path, "/tmp/msg-%08X.txt", r);
        f = fopen(path, "r");
        if (0 == f) {
            printf("(%s %d) `%s` NOT FOUND\n", __FILE__, __LINE__, path);
            continue;
        }
        fgets(msg, sizeof(msg), f);
        fclose(f), f = 0;
        unlink(path);
        printf("(%s %d) %s\n", __FILE__, __LINE__, msg);
        if (0 == strcmp(msg, "QUIT") || 0 == strcmp(msg, "quit"))
            break;
    }
    pthread_cleanup_pop(1);
    return res;
}

 

 

Sigq.c

 

I. sigw 是用來傳送 message. 當然我們必須找到 sigw 的 process id. 

 

   pidof("sigw", &pid);

 

II. message 從 main 函數的參數 argv[1] 傳入. 

 

    while (0 == r)
        srand(time(NULL)), r = rand();
    sprintf(path, "/tmp/msg-%08X.txt", r);
    f = fopen(path, "w"), assert(0 != f);
    strcpy(msg, argv[1]), fputs(msg, f);
    fclose(f), f = 0;
 

III. 呼叫 sigqueue() 將這 message 送給 sigw. 

 

    sigVal.sival_int = r;
    sigqueue(pid, SIGUSR1, sigVal);
 

    以下是範例程式 sigq.c. 

 

sigq.c
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <regex.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <signal.h>
#include <sys/msg.h>
#include <pthread.h>
#include <assert.h>
#include <regex.h>

///////////////////////////////////////////////////////////
// for I in $(seq 1 1000); do sigq $I; done; sigq QUIT

static char *stripCrLf(char *line) {
    int len = 0;

    if(line == 0)        return 0;
    len = strlen(line);
    if(len > 1000)        return line;
    if(len <= 0)        return line;
    if (line[len - 1] == '\n' || line[len - 1] == '\r')
        line[len - 1] = 0;
    len = strlen(line);
    if (len > 0)
        if (line[len - 1] == '\n' || line[len - 1] == '\r')
            line[len - 1] = 0;
    return line;
}
static int pidof(const char *name, pid_t *process) {
    regex_t Regx;
    char Pattern[128] = {0}, cmd[128] = {0}, line[128] = {0}, num[64] = {0};
    FILE *f = 0;
    regmatch_t Match[64];
    int len = 0, id = -1, I = 0;

    strcpy(Pattern, "^([0-9]{1,})$"), regcomp(&Regx, Pattern, REG_EXTENDED);
    sprintf(cmd, "pidof %s", name);
    f = popen(cmd, "r");
    if (0 == f)        return -1;
    fgets(line, sizeof(line), f);
    stripCrLf(line);
    if (0 != regexec(&Regx, line, sizeof(Match) / sizeof(regmatch_t), Match, 0)) {
        regfree(&Regx), pclose(f), f = 0;
        return -1;
    }
    I = 1, len = Match[I].rm_eo - Match[I].rm_so, memcpy(num, line + Match[I].rm_so, len), num[len] = 0;
    sscanf(num, "%d", &id);
    if (process)    *process = id;
    regfree(&Regx), pclose(f), f = 0;
    return 0;
}
int main(int argc, char *argv[]) {
    union sigval sigVal = {0};
    pid_t pid = -1;
    char msg[1024] = {0};
    int r = 0;
    char path[1024] = {0};
    FILE *f;

    if (2 != argc)
        printf("Usage: sigq 'HELLO'\n"), exit(1);
    if (0 != pidof("sigw", &pid))
        printf("(%s %d) sigw not running\n", __FILE__, __LINE__), exit(2);

    while (0 == r)
        srand(time(NULL)), r = rand();
    sprintf(path, "/tmp/msg-%08X.txt", r);
    f = fopen(path, "w"), assert(0 != f);
    strcpy(msg, argv[1]), fputs(msg, f);
    fclose(f), f = 0;

    memset(&sigVal, 0, sizeof(union sigval));
    sigVal.sival_int = r;
    if(sigqueue(pid, SIGUSR1, sigVal) == -1) {
        printf("(%s %d) sigqueue() error\n", __FILE__, __LINE__);
        unlink(path);
        exit(2);
    }
    //printf("(%s %d) sigqueue(). \n", __FILE__, __LINE__);
    return 0;
}

 

 

測試

 

I. sigw

$ ./sigw &

 

II. sigq

$ for I in $(seq 1 1000); do sigq $I; done; ./sigq QUIT;

 

...
(sigw.c 96) 990
(sigw.c 96) 991
(sigw.c 96) 992
(sigw.c 96) 993
(sigw.c 96) 994
(sigw.c 96) 995
(sigw.c 96) 996
(sigw.c 96) 997
(sigw.c 96) 998
(sigw.c 96) 999
(sigw.c 96) 1000
(sigw.c 96) QUIT
$

 

在 rk3328 上面執行, 大約 20 秒左右. 效能還不錯. 

 

 

 

 

z.png
Email: jasonc@mail2000.com.tw . 請尊重原創, 使用圖文時載明出處. 謝謝. 

 

(Finished)


 

 

 

 

 

 

 

 

arrow
arrow

    Lexra 發表在 痞客邦 留言(0) 人氣()