2013/01/08(火)sigprocmaskの検証

Linux実装は pthread*のマスクと sigprocmask()とは同じって書いてた。。
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>

#define gettid() syscall(SYS_gettid)

// 0: sigprocmask at process, 1:thr1, 
#define DF_CHGMASK_ID 2
//#define DF_USE_PTHREADMASK
//#define DF_INITIAL_MASK (SIGSEGV)
//#define DF_INITIAL_MASK (SIGABRT)
#define DF_INITIAL_MASK (12)


void abt_handler(int n, siginfo_t *pSigInf, void *pContext)
{
struct sigaction sa;

	printf("I am dead...[%d][parent:%d][tid=%d][thread_id=%ld]", getpid(), getppid(), gettid(), (long)pthread_self());
	memset(&sa,0,sizeof(struct sigaction));
//_exit(1);
	sigemptyset(&sa.sa_mask);
//	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_handler = SIG_DFL;
//	sigaction(SIGABRT,&sa,NULL);
//	raise(SIGABRT);
}

void register_handler()
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = abt_handler;
//	sigaction(SIGABRT,&sa,NULL);
	sigaction( 12,&sa,NULL);
}


struct st_signals_st {
	int signo;
	const char *pcSignal ;
	} st_signals[] = {
			{SIGHUP,    "SIGHUP"},
			{SIGINT,    "SIGINT"},
			{SIGQUIT,   "SIGQUIT"},
			{SIGILL,    "SIGILL"},
			{SIGTRAP,   "SIGTRAP"},
			{SIGABRT,   "SIGABRT"},
			{SIGIOT,    "SIGIOT"},
			{SIGBUS,    "SIGBUS"},
			{SIGFPE,    "SIGFPE"},
			{SIGKILL,   "SIGKILL"},
			{SIGUSR1,   "SIGUSR1"},
			{SIGSEGV,   "SIGSEGV"},
			{SIGUSR2,   "SIGUSR2"},
			{SIGPIPE,   "SIGPIPE"},
			{SIGALRM,   "SIGALRM"},
			{SIGTERM,   "SIGTERM"},
			{SIGSTKFLT, "SIGSTKFLT"},
			{SIGCHLD,   "SIGCHLD"},
			{SIGCONT,   "SIGCONT"},
			{SIGSTOP,   "SIGSTOP"},
			{SIGTSTP,   "SIGTSTP"},
			{SIGTTIN,   "SIGTTIN"},
			{SIGTTOU,   "SIGTTOU"},
			{SIGURG,    "SIGURG"},
			{SIGXCPU,   "SIGXCPU"},
			{SIGXFSZ,   "SIGXFSZ"},
			{SIGVTALRM, "SIGVTALRM"},
			{SIGPROF,   "SIGPROF"},
			{SIGWINCH,  "SIGWINCH"},
			{SIGIO,     "SIGIO"},
			{SIGPOLL,   "SIGPOLL"},
			{SIGPWR,    "SIGPWR"},
			{SIGSYS,    "SIGSYS"},
			{0, NULL}
		} ;

void dump_sigmask(const char* pMsg, sigset_t* sig_mask)
{
struct st_signals_st* pStSignal = st_signals ;
int i;
	puts(pMsg);
	while( pStSignal->pcSignal ){
		if (sigismember( sig_mask, pStSignal->signo )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
		pStSignal++;
	}
	putchar('_');
	for (i=SIGRTMIN; i<=SIGRTMAX; i++) {
		if (sigismember( sig_mask, i )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
	}
	puts("");
return ;
}


void* thr1(void* arg)
{
sigset_t sig_mask ;

	sleep(1);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr1!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigfillset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigemptyset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);
	sleep(10);
}

void* thr2(void* arg)
{
sigset_t sig_mask ;

	register_handler();
//	sigaddset(&sig_mask, DF_INITIAL_MASK) ;

	sigemptyset(&sig_mask);
	sigaddset(&sig_mask, 12) ;
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#endif
		perror ("thr2(): Dead set...");
	}


	sleep(2);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr2!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	system("echo thr2 is spawn $$ ; sleep 17");

	sleep(3);
}



int
main(int argc, char *argv[])
{
int status=0;
int fd;
pthread_t child[2];
sigset_t sig_mask ;

	sigfillset(&sig_mask);
	if (sigprocmask(SIG_BLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
/*
	sigaddset(&sig_mask, DF_INITIAL_MASK) ;
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
*/
//	register_handler();

	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);



/* スレッド生成 */
	pthread_create(&child[0], NULL, thr1, NULL );
	pthread_create(&child[1], NULL, thr2, NULL );

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigemptyset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigfillset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	status = pthread_join(child[0], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
	status = pthread_join(child[1], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
return 0;
}

2013/01/08(火)sigactionを触ってみる。

backtraceを取れるか確認する(PwerPC 32bitでのみ確認)

glibcに、backtrace()函数があって、便利だなぁ、と。
自分で書かなくて良いんだねぇ。組み込みRTOSで触ってた何か、は、スタックを手動で追っていたわ~。
コレも自動化しすぎて、スタックと思ったアドレスが別空間だとSIGSEGVでおちるけどな…
/*
 * sigaction sample program for powerpc32
 *  You can add more informations in segv_handler().
 *  In this fucntion, you have pointer of stacks, regs, contexts...
 *  If we can allow increase size of binary, we can continu using backtrace_symbols()/backtrace_symbols_fd().
 *  Please refer man-pages, info-pages and a lot of WEB-pages B)
 *
 * Author: 30/Aug./2012 YNK
 * NOTE: Don't use '=O2' because optimization makes no 'bl' instructions to call function.
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <linux/sysctl.h>
#include <sys/ucontext.h>

int (*func_ptr)() = (void *)0x1234567;
int func1();
int func2();
void segv_handler(int n, siginfo_t *pSigInf, void *pContext);

int main(int argc,char ** argv)
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = segv_handler;
	sigaction(SIGSEGV,&sa,NULL);
	func1();
return 0;
}

int func1()
{
  func2();
return 0;
}

int func2()
{
  *(int*)0xBAD2DEAD = 2;
  func_ptr();
return 0;
}

void segv_handler(int n, siginfo_t *pSigInf, void *pContext)
{
int cnt, i;
void **arr = alloca(256 * sizeof(void *));
ucontext_t* pCon = (ucontext_t *)pContext;

	printf("*** segmentation fault! (No=%d)\n", n);
	printf("  An errno value: %d\n", pSigInf->si_errno );
	printf("  Signal code   : %d\n", pSigInf->si_code );
	printf("  access address  : %p\n", pSigInf->si_addr );

// struct defined in ptrace.h
	for(i=0;i<32;i++) {
		printf("GPRS%2d: 0x%08X\n", i, pCon->uc_mcontext.regs->gpr[i]);
	}
	printf("NIP=0x%08X  MSR=0x%08X\n", pCon->uc_mcontext.regs->nip, pCon->uc_mcontext.regs->msr );

	printf("\n\n *** backtrace address ***\n");
	cnt = backtrace(arr, 256);
	for(i=0;i<cnt;i++) {
		printf("\t%3d: 0x%08X\n", i, arr[i]);
	}
/* if included symbolx(compile with "-r dynamic") */
	backtrace_symbols_fd(arr, cnt, 2);

        abort();
}