semaphoreセマフォとは、プロセス間でリソースの排他制御をするものですが、Raspbian Linuxとpepopifaceで実装した
pepopifaceとはRaspberry piの拡張基板PiFace を制御するものです。ダウンロードはhttp://osdn.jp/projects/pepolinux/downloads/63750/pepopiface-0.6.tar.gz/ から
セマフォを使うには初期化が必要です
union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad; }; union semun my_semun;
共有ロックするには各プロセスで共通のkeyが必要です。
以下の関数使用例では、予め用意した任意のパス+'S'の8ビットでkeyを作成
#define PIFACE_SEMA "/var/run/pepopiface.semaphore"
key = ftok(PIFACE_SEMA, 'S');
パスを元に作成したkeyで一個のセマフォIDをgetします。0666はファイルのパーミッションと同じ
mysemun_id = semget(key, 1, 0666 | IPC_CREAT);
getしたセマフォIDの0番目のセマフォに'1'を設定して初期化します
このvalの値を各プロセスが減算、加算してロック、アンロックをします
my_semun.val = 1;
semctl(mysemun_id, 0, SETVAL, my_semun);
これでセマフォが操作出来るようになりました
リソースを使う時は優先ロックを掛けます
sem_op=-1を設定してsemop関数を呼びます
semop関数は、valをマイナスして結果が負にならければこの関数の呼び出しが終了して、元のルーチンに戻ります
もし、結果が負になるとsemop関数の呼び出しでロックされて、優先ロックしたプロセスのアンロック操作待ちになります
/* The following are defined in the "<sys/sem.h>" */ // struct sembuf { // unsigned short sem_num; /* semaphore index in array */ // short sem_op; /* semaphore operation */ // short sem_flg; /* operation flags */ // }; void mysem_lock(int sid){ struct sembuf mysemop[1]; mysemop[0].sem_num = 0; mysemop[0].sem_op = LOCK; mysemop[0].sem_flg = SEM_UNDO; if(semop(sid, mysemop, 1) == -1){ perror("semop: semop lock-1 failed"); exit(1); }
次の関数は共有リソースの使用が終わりロックを開放する為に、sem_op=1を設定してsemop関数を呼びます
valをプラスして結果が負にならければこの関数の呼び出しが終了して元のルーチンに戻ります
void mysem_unlock(int sid){ struct sembuf mysemop[1]; mysemop[0].sem_num = 0; mysemop[0].sem_op = UNLOCK; mysemop[0].sem_flg = SEM_UNDO; if(semop(sid, mysemop, 1) == -1){ perror("semop: semop unlock failed"); exit(1); }
pepopiface.cでは、最初オプションなしで起動すると、セマフォ用ファイルを作成し、そのパスkeyを元にセマフォIDを取得、初期化します
次に通常の起動ではオプションは必ずあるので、作成されたセマフォIDを元に共有リソースを使う前にロック、使い終わったら開放します
セマフォ用のファイル作成、IDの取得、初期化を何時のタイミングで行うか暫く悩みましたがオプションあり、なしで判定して初期化処理をしました
こうする事でもしロックされたままの場合でも、オプションなしで起動すれば新しいセマフォIDを作成させ初期化する事ができます
root@pepopiface# make
gcc -Wall -L/usr/local/lib/ -lpiface-1.0 -o pepopiface pepopiface.c
root@pepopiface# ./pepopiface
** Welcome to pepopiface Version-0.4 Copyright Yamauchi.Isamu compiled:Dec 26 2014 **
usage:pepopiface port:0-8 0|1 [timer:0-65535ms]
root@pepopiface# ls /var/run/pepopiface.semaphore
/var/run/pepopiface.semaphore
root@pepopiface# ipcs -s
key semid owner perms nsems
0x530eb51d 894107648 root 666 1
セマフォ用のファイルとセマフォのキーが作成される
通常は必ずオプションがある、この場合はポート0へ『0』を書き込み、ライト後のアフタリードの結果は『0』
root@pepopiface-0.4# time ./pepopiface 0 0
0
real 0m0.014s
user 0m0.000s
sys 0m0.000s
DEBUGを有効にしてmake・・・pepopiface.debug
セマフォの値valをプリント、ロック10秒待ちアンロックします
root@pepopiface-0.4# time ./pepopiface.debug 1 0
semop_lock:val=0
sem_unlock:val=1
semop_lock:val=0
sem_unlock:val=1
semop_lock:val=0
sem_unlock:val=1
0semop_lock:val=0
sem_unlock:val=1
semop_lock:val=0
lock & wait 10000 milliseconds
sem_unlock:val=0
real 0m10.042s
user 0m0.010s
sys 0m0.000s
DEBUGコード有りコマンドの10秒待ちの間に、別shellでDEBUG無効のコードを起動
DEBUG無効のコードは8秒程終了待ちをしている事が分かる
root@pepopiface-0.4# time ./pepopiface 0 0
0
real 0m8.277s
user 0m0.000s
sys 0m0.000s
root@pepopiface# ipcs -s
key semid owner perms nsems
0x530eb51d 894107648 root 666 1
セマフォキーを削除
root@pepopiface# ipcrm -S 0x530eb51d
root@pepopiface# ipcs -s
key semid owner perms nsems
セマフォキーが削除された、次にセマフォー用のキーファイルを削除
root@pepopiface# rm /var/run/pepopiface.semaphore
rm: remove regular empty file /var/run/pepopiface.semaphore'? y
この状態でポート0の読み取りを行うと、エラーを表示してオプションなしを促します
root@~# pepopiface 0
ftok: failed: No such file or directory
** Please start first time is with no options **
/* Copyright Isamu.Yamauchi 2013-2017. update 2015.8.21 This program uses the libpiface. thanks. pepopiface.c is controls for Raspberry pi PiFace Digital I/O Expansion Board o 2013.07.20 ver0.1, 1st release. o 2013.9.5 ver0.2 , to match the input state of piface, modified to highlight the port data. o 2014.12.21 ver0.3, add an exclusive processing. o 2014.12.26 ver0.4, read & write command return value bug fixes. o 2015.1.11 ver0.5 , add without writing timer option to continuous processing to read. o 2015.8.21 Ver0.6 , Change the upper limit of 60 seconds timer to 5 minutes. */ /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/sem.h> /* <sys/ipc.h> is include in sem.h #include <sys/ipc.h> */ #include <libpiface-1.0/pfio.h> #define DEBUG #undef DEBUG /* Comment out the case when debugging */ #define READ 'R' #define WRITE 'W' #define VER "0.6" #define DAY "compiled:"__DATE__ #define LOCK -1 #define UNLOCK 1 #define PIFACE_SEMA "/var/run/pepopiface.semaphore" #ifdef DEBUG #define DEBUG_WAIT 10000 /* debug wait timer, ms */ #endif int get_myval(int sid) { union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad; }; union semun my_semun; uint16_t d_result = semctl(sid, 0, GETVAL, my_semun); if (d_result == -1) { perror("semctl: GETVAL failed"); exit(1); } #ifdef DEBUG printf("%s%d\n","val=",d_result); #endif return(d_result); } int get_sempid(int sid) { union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad; }; union semun my_semun; pid_t sem_pid; sem_pid = semctl(sid, 0, GETPID, my_semun); if (sem_pid == -1) { perror("semctl: GETPID failed"); exit(1); } return(sem_pid); } void usage() { union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; void *__pad; }; union semun my_semun; FILE *fdsem; uint16_t d_result; int mysemun_id; key_t key; #ifdef DEBUG pid_t my_pid, sem_pid; my_pid = getpid(); #endif fprintf(stderr,"\r\n** Welcome to pepopiface Version-%s Copyright Yamauchi.Isamu %s **",VER,DAY); fprintf(stderr,"\n\rusage:pepopiface port:0-8 [0|1] [timer:0-300000ms]\n\r"); fdsem = fopen(PIFACE_SEMA,"r"); if (fdsem != NULL) { if ((key = ftok(PIFACE_SEMA, 'S')) == -1) { perror("ftok: failed"); exit(1); } /* Creating of the semaphore */ mysemun_id = semget(key, 1, 0666 | IPC_CREAT); if (mysemun_id == -1) { perror("semget: semget get failed"); exit(1); } #ifdef DEBUG sem_pid = get_sempid(mysemun_id); fprintf(stderr,"\r\nmy_pid:%d, sem_pid:%d\r\n",my_pid, sem_pid); #endif /* remove of the semaphore */ my_semun.val = 1; if (semctl(mysemun_id , 0, IPC_RMID, my_semun) == -1) { perror("semctl: semaphore remove failed"); exit(1); } /* semaphore of the file delete */ unlink(PIFACE_SEMA); } fdsem = fopen(PIFACE_SEMA,"r"); if (fdsem == NULL) { /* File creation of semaphore */ fdsem = fopen(PIFACE_SEMA,"w"); if (fdsem == NULL) { perror("fopen: failed"); exit(1); } #ifdef DEBUG fprintf(stderr,"\r\n** %s file creation succeed of semaphore! **\r\n",PIFACE_SEMA); #endif fclose(fdsem); } if ((key = ftok(PIFACE_SEMA, 'S')) == -1) { perror("ftok: failed"); exit(1); } /* Creating of the semaphore */ mysemun_id = semget(key, 1, 0666 | IPC_CREAT); if (mysemun_id == -1) { perror("semget: semget Initialization failed"); exit(1); } d_result = get_myval(mysemun_id); if (d_result == 0) { /* Initialization of the semaphore */ my_semun.val = 1; if (semctl(mysemun_id, 0, SETVAL, my_semun) == -1) { perror("semctl: Initialization failed"); exit(1); } #ifdef DEBUG fprintf(stderr,"\r\n** Initialization succeed of semaphore! **\r\n"); #endif } } /* The following are defined in the "<sys/sem.h>" */ // struct sembuf { // unsigned short sem_num; /* semaphore index in array */ // short sem_op; /* semaphore operation */ // short sem_flg; /* operation flags */ // }; void mysem_lock(int sid){ struct sembuf mysemop[1]; mysemop[0].sem_num = 0; mysemop[0].sem_op = LOCK; mysemop[0].sem_flg = SEM_UNDO; if(semop(sid, mysemop, 1) == -1){ perror("semop: semop lock-1 failed"); exit(1); } #ifdef DEBUG printf("semop_lock:");get_myval(sid); #endif } void mysem_unlock(int sid){ struct sembuf mysemop[1]; mysemop[0].sem_num = 0; mysemop[0].sem_op = UNLOCK; mysemop[0].sem_flg = SEM_UNDO; if(semop(sid, mysemop, 1) == -1){ perror("semop: semop unlock failed"); exit(1); } #ifdef DEBUG printf("sem_unlock:");get_myval(sid); #endif } int msleep(int ms) { if ( ms > 0 ) { struct timeval timeout; timeout.tv_sec = ms / 1000; timeout.tv_usec = (ms % 1000) * 1000; if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &timeout) < 0) { perror("msleep"); return 1; } } return 0; } int main(int argc, char *argv[]) { int port = 0; int data = 0; int invert_data = 0; int wait_time = 1; int port_timer = 0; char rw_flag = READ; int i = 0x0000; int j = 0x0000; uint8_t s_result = 0x00; uint16_t d_result = 0x0000; int mysem_id = 0; key_t key; char patterns[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; if ( argc > 4 || argc < 2 ) { usage(); exit(1); } else { port = atoi(argv[1]); if ( port > 8 || port < 0 ) { usage(); exit(1); } } if ( argc == 3 || argc == 4) { data = atoi(argv[2]); if ( data != 0 && data != 1 ) { usage(); exit(1); } else { rw_flag = WRITE; } } if ( argc == 4 ) { port_timer = atoi(argv[3]); if ( port_timer < 0 || port_timer > 300000 ) { usage(); exit(1); } rw_flag = WRITE; } if ((key = ftok(PIFACE_SEMA, 'S')) == -1) { perror("ftok: failed"); fprintf(stderr,"\r\n** Please start first time is with no options **\r\n"); exit(1); } /* Creating of the semaphore */ mysem_id = semget(key, 1, 0666 | IPC_CREAT); if (mysem_id == -1) { perror("semget: semget Initialization failed"); exit(1); } mysem_lock(mysem_id); if (pfio_init() < 0) exit(-1); mysem_unlock(mysem_id); if ( rw_flag == WRITE ) { /* port write */ mysem_lock(mysem_id); pfio_digital_write(port, data); if ( port_timer > 0 ) { mysem_unlock(mysem_id); if ( data == 0 ) { invert_data = 1; } else { invert_data = 0; } msleep(port_timer); mysem_lock(mysem_id); pfio_digital_write(port, invert_data); } msleep(wait_time); s_result = pfio_read_output() & patterns[port]; mysem_unlock(mysem_id); s_result = s_result >> port; fprintf(stderr,"%1x",s_result); } if ( rw_flag == READ ) { /* port read */ mysem_lock(mysem_id); if ( port == 8 ) { i = pfio_read_input() & 0xffff; j = pfio_read_output() << 8; j = j & 0xffff; i = i ^ 0xffff; i = i & 0x00ff; d_result = j | i; fprintf(stderr,"%04x",d_result); } else { s_result = (pfio_read_input() & patterns[port]); s_result = s_result >> port; s_result = s_result ^ 0x01; fprintf(stderr,"%1x",s_result); } mysem_unlock(mysem_id); } msleep(wait_time); mysem_lock(mysem_id); pfio_deinit(); mysem_unlock(mysem_id); #ifdef DEBUG mysem_lock(mysem_id); fprintf(stderr,"lock & wait %d milliseconds\n",DEBUG_WAIT); msleep(DEBUG_WAIT); mysem_unlock(mysem_id); #endif exit(0); }
[PageInfo]
LastUpdate: 2015-09-25 05:38:01, ModifiedBy: pepolinux
[License]
GNU Free Documentation License
[Permissions]
view:all, edit:doc editors, delete/config:doc editors