UNIX では、コマンドの終了値は、0 が正常終了を意味します。
従って、プログラムが終了するときは
exit(終了値)
に正しい終了値を設定する必要があります。
終了値を知るには、以下のようにします。
% echo $status [csh の場合] $ echo $? [sh/ksh の場合]
通常、システムコールなどからエラーで戻り、処理を続行できないときは、 その戻り値を 終了値とします。 そのようにすれば、終了値からエラーの原因を知ることができます。
システムコールからのエラー番号は通常 /usr/include/sys/errno.h に定義されています。
エラー番号からエラーメッセージを取得するには、以下のようにします。
char * = strerror(エラー番号);
システムコールから戻されるエラー番号から、 エラーメッセージを取得するプログラム err.c です。
/*
Function : output error message of system_call error
Usage : err ERR_NO
err Start_ERR_NO End_ERR_NO
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int start,end;
void usage(int no) {
printf("Usage : err ERR_NO [TO_ERR_NO]\n");
exit(no);
}
int main(int argc,char *argv[]) {
int i;
getarg(argc,argv);
for (i=start; i<=end; i++) {
printf("%3d] %s\n",i,strerror(i));
}
exit(0);
}
int getarg(int argc,char *argv[]) {
if (argc == 1) {
usage(EINVAL);
}
if (argc == 2) {
start=atoi(argv[1]);
end =start;
}
else if (argc == 3) {
start=atoi(argv[1]);
end =atoi(argv[2]);
}
else {
usage(EINVAL);
}
if ((start > 0) && (start<0xffff)) {
if ((end >= start) && (end <0xffff)) return 0;
}
usage(EINVAL);
}
シグナルを送信され結果として終了すると、 シグナル一覧表 に明記されている終了値が設定されます。
上記事項を確認するために、 以下は自分自身に指定したシグナルを送るプログラム sig.c です。
/*
sig.c -- send signal to myself
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
char *menu[]={
"Which SIGNAL do you want to send = ?\n",
" 1. SIGHUP Exit status=129\n",
" 2. SIGINT Exit status=130\n",
" 3. SIGQUIT Core status=131\n",
" 4. SIGILL Core status=132\n",
" 5. SIGTRAP Core status=133\n",
" 6. SIGABRT Core status=134\n",
" 7. Emulation Trap Core status=135\n",
" 8. Floating exception Core status=136\n",
" 9. Kill Exit status=137\n",
" 10. Bus error Core status=138\n",
" 11. Segmentation fault Core status=139\n",
" 12. SIGSYS Core status=140\n",
" 13. SIGPIPE Exit status=141\n",
" 14. SIGALRM Exit status=142\n",
" 15. SIGTERM Exit status=143\n",
" 16. SIGUSR1 Exit status=144\n",
" 17. SIGUSR2 Exit status=145\n",
" 18. SIGCHLD Igno status=146\n",
" 19. SIGPWR Igno status=147\n",
" 20. SIGWINCH Igno status=148\n",
" 21. SIGURG Igno status=149\n",
" 22. SIGPOLL Exit status=150\n",
" 23. SIGSTOP Stop status=151\n",
" 24. SIGTSTP Stop status=152\n",
" 25. SIGCONT Igno status=153\n",
" 26. SIGTTIN Stop status=154\n",
" 27. SIGTTOU Stop status=155\n",
" 28. SIGVTALRM Exit status=156\n",
" 29. SIGPROF Exit status=157\n",
" 30. SIGXCPU Core status=158\n",
" 31. SIGXFSZ Core status=159\n",
" 100. Quit \n",
};
#define SZ_MENU (sizeof(menu)/sizeof(char *))
int main(int argc,char *argv[]) {
char cp;
int i,pno,inpno,dum,ret;
for (;;) {
for (i=0; i<SZ_MENU; i++) printf(menu[i]);
inpno = scanf("%d",&pno);
if (! inpno) {
printf("Input error !!\n\n");
for (;;) {
dum = getchar();
if (dum == '\n') break;
}
continue;
}
if ((pno >0) && (pno <100)) {
ret = kill( getpid(),pno);
if (ret) exit(errno);
}
else exit(0);
}
}
pthread を3つ作ります。
threadTwo,threadThree は、メッセージを表示して終わりますが、 sigint スレッドは、CNTL_C を入力されるのを待っています。
/********************************************************************
compile with -D_POSIX_PTHREAD_SEMANTICS switch;
required by sigwait()
sigint thread handles delivery of signal. uses sigwait() to wait
for SIGINT signal.
********************************************************************/
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <synch.h>
static void *threadTwo(void *);
static void *threadThree(void *);
static void *sigint(void *);
sigset_t signalSet;
void * main(void) {
pthread_t t,t2,t3;
thr_setconcurrency(3);
sigfillset ( &signalSet );
/*
* Block signals in initial thread. New threads will
* inherit this signal mask.
*/
pthread_sigmask ( SIG_BLOCK, &signalSet, NULL );
printf("Creating threads\n");
/* POSIX thread create arguments:
* thr_id, attr, strt_func, arg
*/
pthread_create(&t, NULL, sigint, NULL);
pthread_create(&t2, NULL, threadTwo, NULL);
pthread_create(&t3, NULL, threadThree, NULL);
printf("##################\n");
printf("press CTRL-C to deliver SIGINT to sigint thread\n");
printf("##################\n");
thr_exit((void *)0);
}
static void * threadTwo(void *arg) {
printf("hello world, from threadTwo [tid: %d]\n",
pthread_self());
printf("threadTwo [tid: %d} is now complete and exiting\n",
pthread_self());
thr_exit((void *)0);
}
static void * threadThree(void *arg) {
printf("hello world, from threadThree [tid: %d]\n",
pthread_self());
printf("threadThree [tid: %d} is now complete and exiting\n",
pthread_self());
thr_exit((void *)0);
}
void * sigint(void *arg) {
int sig;
int err;
printf("thread sigint [tid: %d] awaiting SIGINT\n",
pthread_self());
/* use POSIX sigwait() -- 2 args
* signal set, signum
*/
err = sigwait ( &signalSet, &sig );
/* test for SIGINT; could catch other signals */
if (err || sig != SIGINT)
abort();
printf("\nSIGINT signal %d caught by sigint thread [tid: %d]\n",
sig, pthread_self());
thr_exit((void *)0);
}
次の例は、少し複雑です。
unix のスレッド関数は、SVR5 系と POSIX 系の2種類あります。 以下の thd.c では、それぞれの関数を使えるように、 条件付コンパイルができるようになっています。
このプログラムは、最大10のスレッドを生成し、その時刻を格納します。 そして、スレッドが終了するとその時刻を格納します。 すべてのスレッドが終了したら、各スレッドの開始時刻と終了時刻を表示します。
/*
thd.c -- test program for thread
Switch SVR5 - UNIX SVR5 thread
POSIX - POSIX thread
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#ifdef SVR5
#include <sys/unistd.h>
#include <thread.h>
#include <synch.h>
#endif
#ifdef POSIX
#include <unistd.h>
#include <pthread.h>
#define thread_t pthread_t
#define mutex_t pthread_mutex_t
#define mutex_lock pthread_mutex_lock
#define mutex_unlock pthread_mutex_unlock
#endif
#define min(a,b) ((a)>(b)?(b):(a))
#define SZ_STACK (128*1024L)
#define MAX_TIMESTR 26
#define MAX_PRIO 127
#define MAX_SECS 10
#define MAX_LOOP 10
#define MAX_LOOP2 100
#define MAX_THREADS 10
void * sb(void *);
static void * (*fun[])(void *)={sb,sb,sb,sb,sb,sb,sb,sb};
#define SZ_THREADS (sizeof(fun)/sizeof(void *))
#define NO_THREADS (min(MAX_THREADS,SZ_THREADS))
static thread_t thd_id[MAX_THREADS];
static int arginfo[MAX_THREADS],prio[MAX_THREADS],
slptm [MAX_THREADS] ;
static time_t start_tm[MAX_THREADS],end_tm[MAX_THREADS];
static char *info[]={
"AAA- 0","BBB- 1","CCC- 2","DDD- 3","EEE- 4","FFF- 5",
"GGG- 6","HHH- 7","III- 8","JJJ- 9","KKK-10","LLL-11"};
mutex_t mutex;
int thdno;
#ifdef POSIX
pthread_mutexattr_t attr;
#endif
main(int argc,char *argv[]) {
int i,rtn,stk_size;
void *status;
thread_t *thd = &thd_id[0];
caddr_t addr;
char *start,*end,str[MAX_TIMESTR];
time_t start_m,end_m;
/* 1. get general information */
getinfo();
time(&start_m);
mutexInit();
/* 2. set thread conditions and start */
for (i=0; i<NO_THREADS; i++) {
prio [i] = get_prio();
slptm [i] = get_sec();
arginfo[i] = i;
stk_size = SZ_STACK*(i+1);
rtn = createThd(stk_size,fun[i],&arginfo[i],thd);
thd++;
}
/* 3. wait to end executing of thread */
joinThd();
time(&end_m);
/* 4. print elapse time */
start = ctime(&start_m);
start[24] = ' ';
strcpy(str,start);
end = ctime(&end_m);
end[24] = ' ';
printf("\n TTL : %s - %s\n",str,end);
printf("---------- ---------------------------------------------------\n");
printf(" NO:PRI:SL: Start time - End time\n");
for (i=0; i<NO_THREADS; i++) {
start = ctime(&start_tm[i]);
start[24] = ' ';
strcpy(str,start);
end = ctime(&end_tm[i]);
end[24] = ' ';
printf(" %2d:%3d:%2d: %s - %s\n",i,prio[i],slptm[i],str,end);
}
}
void * sb(void *no) {
int i,*n,rtn,priority,secs;
stack_t stk;
long tmp1,tmp2;
thread_t tid;
setThdno(1);
n = (int *) no;
tid = thd_id[*n];
time(&start_tm[*n]);
#ifdef SVR5
setPriority(tid,prio[*n]);
rtn = thr_stksegment(&stk);
if (! rtn) {
thr_getprio(tid,&priority);
printf("New %d_thread start : %s \n",*n,info[*n]);
fflush(stdout);
}
#endif
sleep(slptm[*n]);
for (i=0; i<MAX_LOOP; i++) {
printf("%s no=%d i=%d\n",info[*n],*n,i);
fflush(stdout);
}
for (i=0,tmp1=MAX_LOOP2; i<MAX_LOOP2; i++) {
tmp2 = tmp1 * i;
}
time(&end_tm[*n]);
setThdno(-1);
return no;
}
int mutexInit() {
int err;
thdno = 0;
#ifdef SVR5
err = mutex_init(&mutex,USYNC_THREAD,0);
#endif
#ifdef POSIX
/*
int pthread_mutexattr_init(
pthread_mutexattr_t *attr);
int pthread_mutex_init(
pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr);
*/
err = pthread_mutexattr_init(&attr);
if (err) thd_exit("mutexInit:pthread_mutexattr_init",err);
err = pthread_mutex_init(&mutex,&attr);
#endif /* POSIX */
if (err) thd_exit("mutexInit:pthread_mutex_init",err);
}
int mutexLock() {
int err;
#ifdef POSIX
for (;;) {
err = pthread_mutex_trylock(&mutex);
if (! err ) break;
if (err != EBUSY) break;
}
if (err) thd_exit("mutextryLock",err);
#else
err = mutex_lock(&mutex);
if (err) thd_exit("mutexLock",err);
#endif
}
int mutexUnlock() {
int err;
err = mutex_unlock(&mutex);
if (err) thd_exit("mutexUnlock",err);
}
int thd_exit(char *fname,int err) {
printf("%s : %s\n",fname,strerror(err));
exit(err);
}
int get_prio() {
return (get_rand() % MAX_PRIO);
}
int get_sec() {
return (get_rand() % MAX_SECS);
}
int get_rand() {
static int start=0;
if (! start) {
srand(100);
start++;
}
return (rand());
}
#ifdef SVR5
int setPriority(thread_t tid,int prio) {
thr_setprio(tid,prio);
}
#endif
int getThdno() {
printf("getThdno : thread no=%d\n",thdno);
return thdno;
}
int setThdno(int no) {
mutexLock();
thdno += no;
printf("setThdno : thread no=%d\n",thdno);
mutexUnlock();
}
int createThd(int stk_size,void *fun(void *),int arginfo[],thread_t *thd) {
int err;
#ifdef SVR5
return thr_create(NULL,stk_size,fun,(void *)(arginfo),NULL,thd);
#endif
#ifdef POSIX
/*
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void * (*start_routine)(void *),
void *arg);
*/
err = pthread_create(thd,NULL,fun,(void *)(arginfo));
if (err) thd_exit("createThd:pthread_create",err);
return err;
#endif
}
int joinThd() {
int i,err;
void *val[MAX_THREADS];
for (i=0; i<NO_THREADS; i++) {
#ifdef SVR5
err = thr_join(thd_id[i],NULL,&val[i]);
#endif
#ifdef POSIX
/* int pthread_join(
pthread_t thread,
void **value_ptr);
*/
err = pthread_join(thd_id[i],&val[i]);
#endif
if (err) thd_exit("joinThd:pthread_join",err);
}
return err;
}
int getinfo() {
#ifdef HP_UX
printf("Running CPU is %ld and kernel is %ld mode\n",
sysconf(_SC_CPU_VERSION),sysconf(_SC_KERNEL_BITS));
#else
printf("Cpu no=%d online Cpu=%d\n",
sysconf(_SC_NPROCESSORS_CONF),sysconf(_SC_NPROCESSORS_ONLN));
#endif
fflush(stdout);
}
Makefile の内容
CC_SUN = /usr/ucb/cc
CC_DEC = /usr/bin/cc
LIBS_SUN = -lthread
LIBS_DEC = -lpthread
LIBS_IBM = -lpthreads
CFLAGS_SUN = -DSVR5 -I/usr/include -lthread -c -g
CFLAGS_DEC = -DPOSIX -I/usr/include -thread -c -g
CFLAGS_POSIX = -DPOSIX -I/usr/include -lpthread -c -g
CFLAGS_AIX = -DPOSIX -I/usr/include -c -g
CFLAGS_HP = -DPOSIX -DHP_UX -I/usr/include -lpthread -c -g
TAGS = thd
SRCS = $(TAGS).c
OBJS = $(TAGS).o
HDRS =
TAGS: $(SRCS) $(HDRS)
$(CC) $(CFLAGS) -c $(SRCS)
$(CC) -o $(TAGS) $(OBJS) $(LDFLAGS)
svr5: $(SRCS) $(HDRS)
$(CC_SUN) $(CFLAGS_SUN) $(SRCS)
$(CC_SUN) -o $(TAGS) $(OBJS) $(LIBS_SUN)
posixDEC: $(SRCS) $(HDRS)
$(CC_DEC) $(CFLAGS_DEC) $(SRCS)
$(CC_DEC) -o $(TAGS) $(OBJS) $(LIBS_DEC)
posixSUN: $(SRCS) $(HDRS)
$(CC_SUN) $(CFLAGS_POSIX) $(SRCS)
$(CC_SUN) -o $(TAGS) $(OBJS) $(LIBS_DEC)
posixAIX:$(SRCS) $(HDRS)
$(CC_DEC) $(CFLAGS_AIX) $(SRCS)
$(CC_DEC) -o $(TAGS) $(OBJS) -L/usr/lib $(LIBS_IBM)
posixHP:$(SRCS) $(HDRS)
$(CC_DEC) $(CFLAGS_HP) $(SRCS)
$(CC_DEC) -o $(TAGS) $(OBJS) -L/usr/lib $(LIBS_DEC)
clean:
rm -rf *.o $(TAGS) core