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.