I've written a program which does following things when given its
desired inputs:
* Attaches signal handlers to SIGINT and SIGTERM signal.
* Creates a TCP/IPv4 socket
* Binds to the TCP/IPv4 address provided by user at command line.
* Creates a Mutex attribute with type "PTHREAD_MUTEX_NORMAL".
* Initializes a new Mutex with the newly created attribute
* Locks the mutex.
* Relocks the mutex and blocks.
* Destroys mutex, and mutex attribute.
* Closes the socket file descriptor
The SIGINT handler is used for unlocking mutex.
If I don't call "pthread_mutexattr_settype(&attr,
PTHREAD_MUTEX_NORMAL)", FreeBSD won't allow mutex to relock, which it
does to prevent deadlocks.
Following is the program:
-- begin source --
/* bind.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
static pthread_mutex_t mutex;
void
ctrl_c_handler(int signo)
{
fprintf(stderr, "Ctrl+C pressed.\n");
pthread_mutex_unlock(&mutex);
}
int
main(int argc, char** argv)
{
int fd, err;
struct sockaddr_in addr;
pthread_mutexattr_t attr;
sig_t old;
if(argc < 3)
{
fprintf(stderr, "Usage: %s [ipv4-address] [port]\n", argv[0]);
return 0;
}
if((old = signal(SIGINT, &ctrl_c_handler)) == SIG_ERR)
{
perror("signal");
return 5;
}
if((old = signal(SIGTERM, &ctrl_c_handler)) == SIG_ERR)
{
perror("signal");
return 6;
}
if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
return 1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
#ifdef DEBUG
printf("Binding to %s:%d\n", inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
#endif
if(bind(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) ==
-1)
{
perror("Error, binding to port");
close(fd);
return 2;
}
if(err = pthread_mutexattr_init(&attr))
{
fprintf(stderr, "Error initializing mutex attribute: %s\n",
strerror(err));
close(fd);
return 3;
}
if(err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL))
{
fprintf(stderr, "Error setting type of mutex attribute: %s\n",
strerror(err));
close(fd);
return 3;
}
if(err = pthread_mutex_init(&mutex, &attr))
{
fprintf(stderr, "Error initializing mutex: %s\n", strerror(err));
close(fd);
return 3;
}
if(err = pthread_mutex_lock(&mutex))
{
fprintf(stderr, "Error locking mutex: %s\n", strerror(err));
close(fd);
return 3;
}
fprintf(stderr, "Press Ctrl+C to terminate\n");
if(err = pthread_mutex_lock(&mutex))
{
fprintf(stderr, "Error locking mutex: %s\n", strerror(err));
close(fd);
return 3;
}
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&mutex);
close(fd);
return 0;
}
-- end source --
The program can be compiled with following command line:
-- begin command line --
[abbe@chatteau sockets]$ cc -o bind bind.c -DDEBUG -pthread
-- end command line --
And can be executed with following command line. In following command
line, 19245 is an unused TCP port:
-- begin command line --
[abbe@chatteau sockets]$ ./bind 127.0.0.1 19245
Binding to 127.0.0.1:19245
Press Ctrl+C to terminate
-- end command line --
The expected output from the program is that it should terminate when
Ctrl+C is pressed. On Debian 4 Etch (amd64), to compile the program,
I've to remove "if" block containing "pthread_mutexattr_settype(&attr,
PTHREAD_MUTEX_NORMAL)". And after that it executes as expected.
Whereas on FreeBSD, it waits for an infinite period. And to terminate
it, process has to be killed.
Any ideas what is wrong in the above program ? I've truss-ed it in
FreeBSD, some of the initial lines from truss output are pasted below:
-- begin output --
mmap(0x0,7744,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365136896 (0x800526000)
munmap(0x800526000,7744) = 0 (0x0)
__sysctl(0x7fffffffe910,0x2,0x80062e180,0x7fffffffe908,0x0,0x0) = 0
(0x0)
mmap(0x0,32768,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,
4294967295,0x0) = 34365136896 (0x800526000)
issetugid() = 0 (0x0)
open("/etc/libmap.conf",O_RDONLY,0666) ERR#2 'No such file or
directory'
open("/var/run/ld-elf.so.hints",O_RDONLY,00) = 3 (0x3)
read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\M-G\0\0"...,128) = 128 (0x80)
lseek(3,0x80,SEEK_SET) = 128 (0x80)
read(3,"/lib:/usr/lib:/usr/lib/compat:/u"...,199) = 199 (0xc7)
close(3) = 0 (0x0)
access("/lib/libpthread.so.2",0) = 0 (0x0)
open("/lib/libpthread.so.2",O_RDONLY,0400030560140) = 3 (0x3)
fstat(3,{mode=-r--r--r-- ,inode=70686,size=160552,blksize=4096}) = 0
(0x0)
read(3,"\^?ELF\^B\^A\^A\t\0\0\0\0\0\0\0"...,4096) = 4096 (0x1000)
mmap(0x0,1224704,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_NOCORE,3,0x0) =
34366234624 (0x800632000)
mprotect(0x800654000,4096,PROT_READ|PROT_WRITE|PROT_EXEC) = 0 (0x0)
mprotect(0x800654000,4096,PROT_READ|PROT_EXEC) = 0 (0x0)
mmap(0x800754000,16384,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,
3,0x0) = 34367422464 (0x800754000)
mmap(0x800758000,20480,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|
MAP_ANON,4294967295,0x0) = 34367438848 (0x800758000)
close(3) = 0 (0x0)
access("/lib/libc.so.6",0) = 0 (0x0)
open("/lib/libc.so.6",O_RDONLY,0143) = 3 (0x3)
fstat(3,{mode=-r--r--r-- ,inode=70674,size=1083208,blksize=4096}) = 0
(0x0)
read(3,"\^?ELF\^B\^A\^A\t\0\0\0\0\0\0\0"...,4096) = 4096 (0x1000)
mmap(0x0,2158592,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_NOCORE,3,0x0) =
34367459328 (0x80075d000)
mprotect(0x800838000,4096,PROT_READ|PROT_WRITE|PROT_EXEC) = 0 (0x0)
mprotect(0x800838000,4096,PROT_READ|PROT_EXEC) = 0 (0x0)
mmap(0x800938000,110592,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,
3,0x0) = 34369404928 (0x800938000)
mmap(0x800953000,102400,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|
MAP_ANON,4294967295,0x0) = 34369515520 (0x800953000)
close(3) = 0 (0x0)
sysarch(0x81,0x7fffffffe980) = 0 (0x0)
mmap(0x0,544,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365169664 (0x80052e000)
munmap(0x80052e000,544) = 0 (0x0)
mmap(0x0,7664,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365169664 (0x80052e000)
munmap(0x80052e000,7664) = 0 (0x0)
mmap(0x0,45440,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x800000000) =
34365169664 (0x80052e000)
munmap(0x80052e000,45440) = 0 (0x0)
getpid() = 71525 (0x11765)
__sysctl(0x7fffffffe8e8,0x2,0x800757b50,0x7fffffffe8e0,0x0,0x0) = 0
(0x0)
__sysctl(0x7fffffffe8e8,0x2,0x7fffffffe8f0,0x7fffffffe8e0,0x0,0x0) = 0
(0x0)
__sysctl(0x7fffffffe8d0,0x2,0x800968858,0x7fffffffe8c8,0x0,0x0) = 0
(0x0)
readlink("/etc/malloc.conf",0x7fffffffe7e0,63) ERR#2 'No such file or
directory'
issetugid() = 0 (0x0)
mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,
4294967295,0x800000000) = 34365169664 (0x80052e000)
break(0x503000) = 0 (0x0)
break(0x504000) = 0 (0x0)
break(0x505000) = 0 (0x0)
break(0x506000) = 0 (0x0)
break(0x50a000) = 0 (0x0)
break(0x50b000) = 0 (0x0)
break(0x50d000) = 0 (0x0)
break(0x50e000) = 0 (0x0)
break(0x511000) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|
SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|
SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|
SIGUSR2,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
mmap(0x7fffffbff000,4096,PROT_NONE,MAP_ANON,4294967295,0x0) =
140737484156928 (0x7fffffbff000)
break(0x512000) = 0 (0x0)
sysarch(0x81,0x7fffffffe8d0) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|
SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|
SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|
SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0
(0x0)
sigaction(SIGHUP,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGINT,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGQUIT,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGILL,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGTRAP,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGABRT,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGEMT,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGFPE,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGKILL,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGBUS,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGSEGV,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGSYS,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGPIPE,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGALRM,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGTERM,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGURG,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGSTOP,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGTSTP,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGCONT,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGCHLD,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGTTIN,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGTTOU,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGIO,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGXCPU,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGXFSZ,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGVTALRM,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGPROF,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGWINCH,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGINFO,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGUSR1,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGUSR2,0x0,{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(32,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(33,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(34,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(35,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(36,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(37,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(38,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(39,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(40,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(41,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(42,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(43,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(44,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(45,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(46,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(47,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(48,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(49,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(50,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(51,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(52,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(53,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(54,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(55,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(56,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(57,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(58,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(59,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(60,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(61,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(62,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(63,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(64,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(65,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(66,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(67,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(68,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(69,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(70,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(71,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(72,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(73,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(74,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(75,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(76,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(77,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(78,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(79,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(80,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(81,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(82,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(83,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(84,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(85,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(86,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(87,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(88,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(89,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(90,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(91,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(92,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(93,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(94,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(95,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(96,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(97,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(98,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(99,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(100,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(101,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(102,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(103,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(104,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(105,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(106,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(107,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(108,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(109,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(110,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(111,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(112,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(113,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(114,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(115,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(116,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(117,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(118,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(119,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(120,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(121,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(122,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(123,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(124,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(125,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(126,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(127,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigaction(128,0x0,{ SIG_DFL SA_RESTART ss_t }) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigaltstack(0x0,0x50d300) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|
SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|
SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|
SIGUSR2,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigaction(SIGINT,{ 0x8006412b0 SA_RESTART|SA_SIGINFO ss_t },0x0) = 0
(0x0)
sigaction(SIGTERM,{ 0x8006412b0 SA_RESTART|SA_SIGINFO ss_t },0x0) = 0
(0x0)
socket(PF_INET,SOCK_STREAM,0) = 3 (0x3)
fstat(1,{mode=crw------- ,inode=54,size=0,blksize=4096}) = 0 (0x0)
break(0x513000) = 0 (0x0)
ioctl(1,TIOCGETA,0x7fffffffe290) = 0 (0x0)
write(1,"Binding to 127.0.0.1:29023\n",27) = 27 (0x1b)
bind(3,{ AF_INET 127.0.0.1:29023 },16) = 0 (0x0)
Press Ctrl+C to terminate
write(2,"Press Ctrl+C to terminate\n",26) = 26 (0x1a)
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
-- end output --
As you can see, "kse_release" is invoked continously . Any ideas what
is wrong here ?
Thanks in advance,
Ashish Shukla
--
http://wahjava.wordpress.com/
Unlocking mutexes is not a signal-safe operation. You shouldn't be
using pthread_xxx() functions in a signal handler.
But my SIGINT handler code is never executed. And BtW, could you point
me to some resource which says, using pthread_xxxx() routines in
signal handler are unsafe.
Thanks in advance
"man sigaction" for the list of calls which are safe.
Everything else is unsafe.
Mark
Base Interfaces:
_exit(), access(), alarm(), cfgetispeed(), cfgetospeed(), cfsetispeed(),
cfsetospeed(), chdir(), chmod(), chown(), close(), creat(), dup(),
dup2(), execle(), execve(), fcntl(), fork(), fpathconf(), fstat(),
fsync(), getegid(), geteuid(), getgid(), getgroups(), getpgrp(),
getpid(), getppid(), getuid(), kill(), link(), lseek(), mkdir(),
mkfifo(), open(), pathconf(), pause(), pipe(), raise(), read(), rename(),
rmdir(), setgid(), setpgid(), setsid(), setuid(), sigaction(),
sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember(),
signal(), sigpending(), sigprocmask(), sigsuspend(), sleep(), stat(),
sysconf(), tcdrain(), tcflow(), tcflush(), tcgetattr(), tcgetpgrp(),
tcsendbreak(), tcsetattr(), tcsetpgrp(), time(), times(), umask(),
uname(), unlink(), utime(), wait(), waitpid(), write().
Realtime Interfaces:
aio_error(), clock_gettime(), sigpause(), timer_getoverrun(),
aio_return(), fdatasync(), sigqueue(), timer_gettime(), aio_suspend(),
sem_post(), sigset(), timer_settime().
ANSI C Interfaces:
strcpy(), strcat(), strncpy(), strncat(), and perhaps some others.
Extension Interfaces:
strlcpy(), strlcat().
All functions not in the above lists are considered to be unsafe with
respect to signals. That is to say, the behaviour of such functions when
called from a signal handler is undefined. In general though, signal
handlers should do little more than set a flag; most other actions are
not safe.
Also, it is good practice to make a copy of the global variable errno and
restore it before returning from the signal handler. This protects
against the side effect of errno being set by functions called from
inside the signal handler.
Thanks for this list. But any ideas, why signal handler never got
executed on FreeBSD despite pressing Ctrl+C multiple times. I tried it
on GNU/Linux, and there the signal handler gets executed when pressed
Ctrl+C.
In the BSD-part of the world, where I'm coming from, it's customary to
include <sys/...> headers before <stdio.h> and to keep the header list
sorted, unless there is a good reason not to do so, i.e.:
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
> static pthread_mutex_t mutex;
>
> void
> ctrl_c_handler(int signo)
> {
> fprintf(stderr, "Ctrl+C pressed.\n");
> pthread_mutex_unlock(&mutex);
> }
As mentioned earlier, it's not safe to call either fprintf() or
pthread_mutex_unlock() here, but let's ignore this for now. If the
signal handler can fire multiple times (i.e. because both SIGTERM and
SIGINT arrive in a short time), you will attempt to unlock &mutex twice!
The following is not perfectly safe either, but it's a small improvement:
% volatile sig_atomic_t flag = 0;
%
% void
% ctrl_c_handler(int signo)
% {
% (void) signo; /* ignore unused parameter */
% if (flag == 0) {
% flag = 1;
% (void) pthread_mutex_unlock(&mutex);
% }
% }
> int
> main(int argc, char** argv)
> {
> int fd, err;
> struct sockaddr_in addr;
> pthread_mutexattr_t attr;
> sig_t old;
>
> if(argc < 3)
> {
> fprintf(stderr, "Usage: %s [ipv4-address] [port]\n", argv[0]);
> return 0;
> }
It's probably a good idea to accept *only* 2 arguments here, with:
% static void
% usage(void)
% {
% fprintf(stderr, "usage: foo ADDR PORT\n");
% exit(EXIT_FAILURE);
% }
%
% int
% main(int argc, char **argv)
% {
% [...]
% if (argc != 3)
% usage();
> if((old = signal(SIGINT, &ctrl_c_handler)) == SIG_ERR)
> {
> perror("signal");
> return 5;
> }
> if((old = signal(SIGTERM, &ctrl_c_handler)) == SIG_ERR)
> {
> perror("signal");
> return 6;
> }
You are not using `old' anywhere, except for checking SIG_ERR. You can
delete the `old' variable altogether, and check for the same error with:
% #include <sysexits.h>
%
% if (signal(SIGTERM, &ctrl_c_handler) == SIG_ERR) {
% perror("signal");
% exit(EX_OSERR);
% }
It's probably a good idea to use EX_OSERR instead of 'magic' exit codes
in such places too.
> fprintf(stderr, "Press Ctrl+C to terminate\n");
>
> if(err = pthread_mutex_lock(&mutex))
> {
> fprintf(stderr, "Error locking mutex: %s\n", strerror(err));
> close(fd);
> return 3;
> }
> pthread_mutexattr_destroy(&attr);
> pthread_mutex_destroy(&mutex);
>
> close(fd);
> return 0;
> }
There's your bug. After setting up the mutex, and locking it, you
simply pthread_mutex_destroy() it and exit. This operation can be done
fast enough, and a signal may not have time to arrive before you call
the pthread_mutex_destroy() function.
By inserting a pause() call before the pthread_xxx_destroy() calls, you
can isntruct the program to block until a signal is delivered, and then
it will work on FreeBSD too.
Attached below is a complete version of the original program, including
some changes I made locally. Run a diff(1) between the two versions and
feel free to keep any parts you consider useful :-)
Have fun,
Giorgos
--- begin of modified program ---
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
static pthread_mutex_t mutex;
void ctrl_c_handler(int);
static void usage(void);
volatile sig_atomic_t flag = 0;
void
ctrl_c_handler(int signo)
{
(void) signo; /* LINT: unused parameter */
if (flag == 0) {
flag = 1;
(void) pthread_mutex_unlock(&mutex);
}
}
static void
usage(void)
{
fprintf(stderr, "usage: foo ADDR PORT\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
int fd, err;
struct sockaddr_in addr;
pthread_mutexattr_t attr;
if (argc != 3)
usage();
if (signal(SIGINT, &ctrl_c_handler) == SIG_ERR) {
perror("signal");
exit(EX_OSERR);
}
if (signal(SIGTERM, &ctrl_c_handler) == SIG_ERR) {
perror("signal");
exit(EX_OSERR);
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(EX_OSERR);
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
#ifdef DEBUG
printf("Binding to %s:%d\n", inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
#endif
if (bind(fd, (struct sockaddr *)&addr,
sizeof(struct sockaddr_in)) == -1) {
perror("Error, binding to port");
(void) close(fd);
exit(EX_OSERR);
}
err = pthread_mutexattr_init(&attr);
if (err != 0) {
fprintf(stderr, "Error initializing mutex attribute: %s\n",
strerror(err));
(void) close(fd);
exit(EX_OSERR);
}
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
if (err != 0) {
fprintf(stderr, "Error setting type of mutex attribute: %s\n",
strerror(err));
(void) close(fd);
exit(EX_OSERR);
}
err = pthread_mutex_init(&mutex, &attr);
if (err != 0) {
fprintf(stderr, "Error initializing mutex: %s\n",
strerror(err));
(void) close(fd);
exit(EX_OSERR);
}
err = pthread_mutex_lock(&mutex);
if (err != 0) {
fprintf(stderr, "Error locking mutex: %s\n", strerror(err));
(void) close(fd);
exit(EX_OSERR);
}
fprintf(stderr, "Press Ctrl+C to terminate\n");
err = pthread_mutex_lock(&mutex);
if (err != 0) {
fprintf(stderr, "Error locking mutex: %s\n", strerror(err));
(void) close(fd);
exit(EX_OSERR);
}
/* Block until a signal arrives. */
(void) pause();
(void) pthread_mutexattr_destroy(&attr);
(void) pthread_mutex_destroy(&mutex);
(void) close(fd);
return (EXIT_SUCCESS);
}
--- begin of modified program ---
First of all thanks for all the coding conventions you presented from
BSD world. I'm new to BSD world, and your conventions will definitely
help me in writing good code adhering to BSD conventions.
Anyways, I've saved you code as "bind2.c" and compiled and ran using
following command line:
-- begin output --
[abbe@chatteau sockets]$ cc -DDEBUG -o bind2 bind2.c -lpthread
[abbe@chatteau sockets]$ ./bind2 127.0.0.1 65320
Binding to 127.0.0.1:65320
Press Ctrl+C to terminate
^C^C^C
-- end output --
As you can see, the I'm not able to terminate process even pressing
Ctrl+C multiple times. The output of "truss ./bind2 127.0.0.1 65330"
is following:
-- begin output --
mmap(0x0,7744,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365136896 (0x800526000)
munmap(0x800526000,7744) = 0 (0x0)
__sysctl(0x7fffffffe530,0x2,0x80062e180,0x7fffffffe528,0x0,0x0) = 0
sysarch(0x81,0x7fffffffe5a0) = 0 (0x0)
mmap(0x0,544,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365169664 (0x80052e000)
munmap(0x80052e000,544) = 0 (0x0)
mmap(0x0,7664,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x0) =
34365169664 (0x80052e000)
munmap(0x80052e000,7664) = 0 (0x0)
mmap(0x0,45440,PROT_READ|PROT_WRITE,MAP_ANON,4294967295,0x800000000) =
34365169664 (0x80052e000)
munmap(0x80052e000,45440) = 0 (0x0)
getpid() = 1362 (0x552)
__sysctl(0x7fffffffe508,0x2,0x800757b50,0x7fffffffe500,0x0,0x0) = 0
(0x0)
__sysctl(0x7fffffffe508,0x2,0x7fffffffe510,0x7fffffffe500,0x0,0x0) = 0
(0x0)
__sysctl(0x7fffffffe4f0,0x2,0x800968858,0x7fffffffe4e8,0x0,0x0) = 0
(0x0)
readlink("/etc/malloc.conf",0x7fffffffe400,63) ERR#2 'No such file or
directory'
issetugid() = 0 (0x0)
mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,
4294967295,0x800000000) = 34365169664 (0x80052e000)
break(0x503000) = 0 (0x0)
break(0x504000) = 0 (0x0)
break(0x505000) = 0 (0x0)
break(0x506000) = 0 (0x0)
break(0x50a000) = 0 (0x0)
break(0x50b000) = 0 (0x0)
break(0x50d000) = 0 (0x0)
break(0x50e000) = 0 (0x0)
break(0x511000) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|
SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|
SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|
SIGUSR2,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
mmap(0x7fffffbff000,4096,PROT_NONE,MAP_ANON,4294967295,0x0) =
140737484156928 (0x7fffffbff000)
break(0x512000) = 0 (0x0)
sysarch(0x81,0x7fffffffe4f0) = 0 (0x0)
bind(3,{ AF_INET 127.0.0.1:29045 },16) = 0 (0x0)
Press Ctrl+C to terminate
write(2,"Press Ctrl+C to terminate\n",26) = 26 (0x1a)
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
kse_release({60.000000000}) ERR#22 'Invalid argument'
-- end output --
The output of "uname -a" is following:
-- begin output --
FreeBSD chatteau.d.lf 6.2-RELEASE-p4 FreeBSD 6.2-RELEASE-p4 #0: Thu
Apr 26 15:04:52 UTC 2007 ro...@amd64-builder.daemonology.net:/usr/
obj/usr/src/sys/SMP amd64
-- end output --
I'm quite confused. What is the output of program on your box ?
I'll reply after 2 days once I'll be back at my place.
Thanks again,
- Will
>Thanks for this list. But any ideas, why signal handler never got
>executed on FreeBSD despite pressing Ctrl+C multiple times. I tried it
>on GNU/Linux, and there the signal handler gets executed when pressed
>Ctrl+C.
The most obvious possibility is some issue with your shell setup.
There is no inherent mapping of ctrl-C to SIGINT. For example,
my default bindkey settings in tcsh map it to tty-sigintr (which
*does* send a SIGINT), but it could be mapped to something else.
If you are bouncing here from linux, I'll assume you are using bash.
Unfortunately, that means I can't tell you what settings to check,
as I've never used bash.
--
Drew Lawson | We were taking a vote when
dr...@furrfu.com | the ground came up and hit us.
http://www.furrfu.com/ | -- Cylon warrior
The program I sent has a bug. It tries to pthread_mutex_lock() the same
mutex twice, before calling pause(). Removing the second lock attempt
before pause() is called, unbreaks it :)
It's not a "hard rule", if the user level headers include their own
dependencies (risking other things, though, like unneeded namespace
pollution). I think the rationale behind the rule is something like:
Kernel include files (the sys/*.h collection) may contain options
which affect which parts of the rest of the headers are valid, or
type definitions which are useful for user level headers.
but that's only a guesstimate of the reason behind the original style
mentioned in the style(9) manpage.
I'm sure older and more experienced BSD hackers will know far more
details than I can guess :)
- Giorgos
No, shell setup is the *least* obvious possibility, and there *is* an
inherent mapping, provided by the tty driver defaults. You may of course
re-map ^C to something else in your shell (though actually it doesn't
seem to work in tcsh), but this has no bearing on what happens when you
press ^C while a different program is running in the foreground - the
shell is not involved in delivering the SIGINT (or not) to that program.
You can change *that* action via 'stty', but that is also very unlikely
to be the problem here.
--Per Hedeland
p...@hedeland.org
It seems, I've also found the bug in my program. I'm trying to lock
the same mutex multiple times in the same thread. As, I've just gone
through the "/usr/src/lib/libpthread/thr_private.h" header file and
found that in "pthread_mutex" structure, there is a member variable
"owner" of type "pthread", which is used to keep track of the thread
currently owning the mutex. And in the implementation of
"pthread_mutex_lock" routine, during a request to lock mutex owned by
self, after mutex locking is done, a thread switch occurs, but since,
we've only single thread, this forces application into an infinite
loop.
I hope my explanation is correct. In case there is some other reason
behind this behavior, please correct me.
Thanks in advance,
Your explanation looks fine.
I did some source reading too, and I used FreeBSD 7.0-CURRENT as the
source code to browse. In CURRENT, the default threading library is
`libthr.so', whose source lives under `/usr/src/lib/libthr'. This
library defines a `weak reference' for pthread_mutex_lock(), pointing
at the function __pthread_mutex_lock() in the same source file.
The __pthread_mutex_lock() calls mutex_lock_common(), which contains:
355 } else if (m->m_owner == curthread) {
356 ret = mutex_self_lock(m, abstime);
357 } else {
and the code of mutex_self_lock() is pretty self-explanatory about
what happens when a thread tries to re-lock a mutex it has already
locked:
1) If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then an error of
EDEADLK is returned, and the lock operation fails.
2) If the mutex type is PTHREAD_MUTEX_NORMAL, then a deadlock happens.
The implementation of mutex_self_lock() for the `libpthread.so'
library shows similar behavior, at least if my reading of the source
is ok. The `libpthread.so' implementation of this function can be
found in the source file `/usr/src/lib/libpthread/thread/thr_mutex.c'.
Sometimes it is _very_ useful and educational to have the source code
of the entire system around :-D
Looking at the source, we now know that if you create a mutex of type
`PTHREAD_MUTEX_ERRORCHECK', the pthread_mutex_lock() operation will
*fail* with EDEADLK, so you can check for this sort of thing, and
handle the error/bug in any manner you see fit for your application,
by writing (for example):
#include <err.h>
#include <pthread.h>
pthread_mutexattr_t foo_attr;
pthread_mutex_t foo_lock;
int rc;
if ((rc = pthread_mutexattr_init(&attr)) != 0)
errc(1, rc, "pthread_mutexattr_init: a=%p",
(void *)&foo_attr);
if ((rc = pthread_mutexattr_settype(&foo_attr,
PTHREAD_MUTEX_ERRORCHECK)) != 0)
errc(1, rc, "pthread_mutexattr_settype: m=%p",
(void *)&foo_attr);
if ((rc = pthread_mutex_init(&foo_lock, &foo_attr)) != 0)
errc(1, rc, "pthread_mutex_init: m=%p, a=%p",
(void *)&foo_lock, (void *)&foo_attr);
and you should have an error-checking mutex, which will fail to lock
with EDEADLK when you try to lock the mutex multiple times from the
same program thread.
I hope this helps a bit,
- Giorgos
PS: You may find that error-checking mutexes come with a performance
penalty too. Please make sure you profile your program to see if this
is true. I am not an expert about threading libraries, so please take
the above post with a huge grain of salt and measure, _measure_ and
then *measure* again :)