Thread: Problem with sigwait

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    2

    Problem with sigwait

    Greetings everyone.
    I'm currently working on a project that involves a process reading NMEA sentences from the serial Port and communicating with another process via a linux socket. I've got 3 threads running on the process:

    The COM thread, that listens for data arriving at COM1 and writes it to a FIFO when it does.

    The SOCKET thread, that listens for data arriving to the socket from the other process and writes it to another FIFO.

    The main thread that processes the data kept in the FIFOs (here just prints the data, for simplicity reasons).

    I've assigned SIGUSR1 to be the signal that the COM1 file descriptor will raise when data is available there, and SIGUSR2 to be the signal that the SOCKET file descriptor will raise when data is available there.

    Here is the main function, that works as the main thread and launches the other 2:

    Code:
    int main(){
    
    	sigset_t sigusr_set;
    	thread_args ta, ta1;				//thread arguments structure
    	
    	//serial port variables
    	int fd;					//serial port file descriptor
    	fifo com_fifo;				//serial port FIFO
    	pthread_t com_listen_thread;		//serial port listening thread
    	char NMEA_buf[GPS_ARRAY_NMEA];		//Buffer for the NMEA sentences
    	
    	//socket variables
    	int s;					//socket file descriptor
    	fifo sock_fifo;				//socket FIFO
    	pthread_t sock_listen_thread;		//socket listening thread
    	char SOCKET_buf[200];			//Buffer for socket messages
    	
    	//Opens COM1
    	fd = open_com(DEFAULT_COMM_DEVICE, 9600);
    	
    	sigemptyset(&sigusr_set);			//resets signal mask
    	sigaddset(&sigusr_set, SIGUSR1);		//adds SIGUSR1 bit to the mask
    	sigaddset(&sigusr_set, SIGUSR2);		//adds SIGUSR2 bit to the mask
    	sigprocmask( SIG_BLOCK, &sigusr_set, NULL);	//blocks both signals
    
    	//Creates socket
    	s = socket(AF_UNIX, SOCK_STREAM, 0)
    
    	//starts mutexes
    	pthread_mutex_init(&com_mutex, NULL);
    	pthread_mutex_init(&sock_mutex, NULL);
    	
    	//sets up the COM and SOCKET threads arguments
    	ta.t_fifo = &com_fifo;
    	ta.t_fd = fd;
    	ta.sigset = &sigusr_set;
    
    	ta1.t_fifo = &sock_fifo;
    	ta1.t_fd = s;
    	ta1.sigset = &sigusr_set;
    	
    	//Starts both threads
    	pthread_create( &com_listen_thread, NULL, t_com_listen, (void*)&ta);
    	pthread_create( &sock_listen_thread, NULL, t_sock_listen, (void*)&ta1);
    
    	
    	for(;;){
    	
    		////////////////////////////////SERIAL PORT////////////////////////////////////////////////		
    		
    		pthread_mutex_lock(&com_mutex);	//Entra em zona de exclusao
    		
    		//****************************MUTEX START*****************************
    		
    		if(data_ready_to_read_in_FIFO(&com_fifo)){
    			get_string_from_fifo(NMEA_buf);
    			read=true;
    		}
    		else{
    			read=false;
    		}
    		
    		pthread_mutex_unlock(&com_mutex);
    		
    		//*****************************MUTEX END*******************************	
    		
    		//read something from the COM fifo
    		if (read){
    			printf("Serial port: %s\n", NMEA_buf);
    		}		 
    		
    		////////////////////////////////////SOCKET////////////////////////////////////////////////
    		
    		pthread_mutex_lock(&sock_mutex);
    		
    		//****************************MUTEX START*****************************
    		
    		
    		if(data_ready_to_read_in_FIFO(&sock_fifo)){
    			get_string_from_fifo(SOCKET_buf);	
    			read=true;
    		}
    		else{
    			read=false;
    		}
    		
    		pthread_mutex_unlock(&sock_mutex);
    		
    		//*****************************MUTEX END*******************************	
    		//Read something from the socket 
    		if(read){
    			printf("socket: %s", SOCKET_buf);			
    		}
    		
    		if(kbhit()){
    			key_pressed=getchar();
    			if(key_pressed=='q'){
    				break;
    			}
    	}
    	
    
    	pthread_cancel(com_listen_thread);
    	pthread_join(com_listen_thread, NULL);
    	pthread_cancel(sock_listen_thread);
    	pthread_join(sock_listen_thread, NULL);
    	
    	pthread_mutex_destroy(&com_mutex);
    	pthread_mutex_destroy(&sock_mutex);
    	
    	close(fd);
    	close(s);
    	
    	return 0;
    }
    Now here are both thread functions:

    Code:
    void *t_com_listen(void * args){
    	
    	thread_args *ta = (thread_args *)args;
    	fifo *t_fifo_com = ta->t_fifo;
    	int fd = ta->t_fd;	
    	sigset_t *sg = ta->sigset;
            int tid = (long) syscall(SYS_gettid);
    	
    	int bytes_read, signumber;	
    	
    	fcntl(fd, F_SETSIG, SIGUSR1);
    	fcntl(fd, F_SETOWN, tid);
    	fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK);
    
    	
    	for(;;){
    		
    		sigwait(sg, &signumber);
    		
    		if(data_available(fd)){
    			pthread_mutex_lock(&com_mutex); 
    			//****************************MUTEX START*****************************
    
    			read_from_serial_port_to_fifo(fd, t_fifo_com);
    
    			pthread_mutex_unlock(&com_mutex);
    			//*****************************FIM ZONA EXCLUSAO*******************************
    		}
    		
    		pthread_testcancel();
    	}
    }
    
    
    void *t_sock_listen(void *args){
    	
    	thread_args *ta = (thread_args *)args;
    	fifo *t_fifo_sock = ta->t_fifo;
    	int sock = ta->t_fd;
    	sigset_t *sg = ta->sigset;
            int tid = (long) syscall(SYS_gettid);
        
    	sockaddr remote;
    	int len;
    	int signumber;
    	
    	remote.sun_family = AF_UNIX;
    	strcpy(remote.sun_path, SOCKETADD);
    	len = strlen(remote.sun_path) + sizeof(remote.sun_family);
    	
    	while(connect(sock, (struct sockaddr *)&remote, len) == -1){
    		sleep(1);
    	}
    	
    	printf("Socket connected\n");
    	
    	fcntl(sock, F_SETSIG, SIGUSR2);
    	fcntl(sock, F_SETOWN, tid);
    	fcntl(sock, F_SETFL, O_ASYNC | O_NONBLOCK);
    	
    	for(;;){
    
    		sigwait(sg, &signumber);
    		
    		if(data_available(sock)){
    
    			pthread_mutex_lock(&sock_mutex); //Entra em zona de exclusao
    			//****************************INICIO ZONA EXCLUSAO*****************************
    
    			read_from_socket_to_fifo(fd, t_fifo_sock);
    			
    			pthread_mutex_unlock(&sock_mutex); //Sai de zona de exclusao
    			
    			//*****************************FIM ZONA EXCLUSAO*******************************
    		}
    	
    		pthread_testcancel();
    	}
    }

    Now my problem is that this program works fine most of the times, but sometimes it gets stuck in the sigwait() that waits for SIGUSR1 to be raised from the serial port. I've checked with a normal hyperterminal program to check if data is still coming from the serial port and i've seen it arriving, yet it's as if the signal is not being sent to the thread and sigwait never unblocks. This behaviour is not constant, it only happens sometimes, so i cant even reproduce it whenever i please.
    I'm pretty sure it must me something to do with the way i block the signals or assign them to the file descriptors, but i havent found out why.

    Thanks in advance.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Think of another way to solve your problem, which doesn't involve signals.

    They're one of the more expensive ways of communicating between two processes.
    Since they cannot be queued in any meaningful fashion, if you raise them too quickly, you're going to lose signals, and this could explain why everything gets out of sync.

    I can't even see why you need threads to deal with this either. Once you figure out how to use select() with a timeout, you can do pretty much whatever you want in a single thread.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    pthreads delivers signals to ANY process which doesn't have that signal masked. You should be sigprocmask()'ing the SIGUSR1 and SIGUSR2 signals in each thread you spawn. Make sure that only ONE thread has it unblocked at any one time.

    I also question the wisdom of sharing the same sigset_t for all these operations. Who knows if something else modifies it in the meantime...

    You CAN get reliable signal delivery if you are masking everywhere properly.

    EDIT: This is the relevant bit from the manpage:

    For sigwait to work reliably, the signals being waited for must be
    blocked in all threads, not only in the calling thread, since otherwise
    the POSIX semantics for signal delivery do not guarantee that it’s the
    thread doing the sigwait that will receive the signal.
    The best way to
    achieve this is block those signals before any threads are created, and
    never unblock them in the program other than by calling sigwait.
    In other words, the OTHER thread might be receiving the signal. And of course, not doing anything with it.

    EDIT EDIT: Also, Salem is right. There are better ways to achieve this, i.e. condition variables.
    Last edited by brewbuck; 11-27-2007 at 05:38 PM.

  4. #4
    Registered User
    Join Date
    Nov 2007
    Posts
    2
    Thanks for the answers.
    I tried alot of stuff with the signals, like unblocking them in one thread only and vice-versa, but to no avail. I even tried to create handlers for SIGUSR1 and 2 in the main thread and then forwarding them to the listening threads with a pthread_kill(), but it wasnt successfull either. I fell back to a previous version i had with polling instead of sigwait(). It increases the processor workload, but i suppose that linux will take care of processor scheduling if other applications require computing time.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help understanding a problem
    By dnguyen1022 in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2009, 04:21 PM
  2. Memory problem with Borland C 3.1
    By AZ1699 in forum C Programming
    Replies: 16
    Last Post: 11-16-2007, 11:22 AM
  3. Someone having same problem with Code Block?
    By ofayto in forum C++ Programming
    Replies: 1
    Last Post: 07-12-2007, 08:38 AM
  4. A question related to strcmp
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 07-07-2007, 02:51 PM
  5. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM