using example I have created two process a master and a slave, to test shared memory IPC. Master creates shared memory and starts writing and after some time slave connects, this is working but onces slave connects its not receiving/getting all the data that master writes to share memory.
master code looks like this:
typedef struct custom_data_s {
int min;
int max;
/* for shared */
pthread_mutex_t ipc_mutex;
pthread_cond_t ipc_condvar;
} custom_data_t;
int main(void) {
int fd = -1;
custom_data_t *this_custom_data;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
fd = shm_open("/A_CUSTOM_DATA", O_RDWR | O_CREAT | O_EXCL , (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if(fd == -1) {
printf("ERROR fd %d %s\n",fd,strerror(errno));
}
if (ftruncate (fd,sizeof(custom_data_t)) == -1) {
printf("ERROR trucate fd %d %s\n",fd,strerror(errno));
exit(1);
}
this_custom_data = (custom_data_t *) mmap(NULL, sizeof(custom_data_t), PROT_READ | PROT_WRITE , MAP_SHARED ,fd ,0);
if(this_custom_data ==(custom_data_t *) -1) {
printf("ERROR mapping fd %d %s\n",fd,strerror(errno));
exit(1);
}
close(fd);
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&this_custom_data->ipc_mutex, &mutex_attr);
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&this_custom_data->ipc_condvar, &cond_attr);
for (fd=0; fd != 100000; fd++) {
pthread_mutex_lock(&this_custom_data->ipc_mutex);
this_custom_data->min = fd;
this_custom_data->max = fd+5;
pthread_cond_signal(&this_custom_data->ipc_condvar);
pthread_mutex_unlock(&this_custom_data->ipc_mutex);
}
/* Clean up and exit should check exit codes of all*/
pthread_mutexattr_destroy(&mutex_attr);
pthread_condattr_destroy(&cond_attr);
pthread_cond_destroy(&this_custom_data->ipc_condvar);
pthread_mutex_destroy(&this_custom_data->ipc_mutex);
if(0 != munmap(this_custom_data, sizeof(custom_data_t))) {
printf("ERROR unmapping %s\n",strerror(errno));
exit(1);
}
if (0 != shm_unlink("/A_CUSTOM_DATA")){
printf("ERROR unlinking %s\n",strerror(errno));
exit(1);
}
return 0;
}
For example master starts writing min and max to shared memory from 1 to 10000 after some time slave connects once slave connects it should read all data that is written by master but if in the code once slave connects, it still not reading all data, what I am doing wrong? Should there be another condition variable that slave sets? I am trying to learn shared memory and I think I am doing something wrong or not understanding how mutex and shared memory. In slave I am waiting for condition variable to get set, here is code for slave.
typedef struct custom_data_s {
int min;
int max;
/* for shared */
pthread_mutex_t ipc_mutex;
pthread_cond_t ipc_condvar;
} custom_data_t;
int main(void) {
int fd = -1;
custom_data_t *this_custom_data_ptr;
custom_data_t this_data;
int prv_packet = 0;
fd = shm_open("/A_CUSTOM_DATA", O_RDWR , (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if(fd == -1) {
printf("ERROR fd %d %s\n",fd,strerror(errno));
}
if (ftruncate (fd,sizeof(custom_data_t)) == -1) {
printf("ERROR trucate fd %d %s\n",fd,strerror(errno));
exit(1);
}
this_custom_data_ptr = (custom_data_t *) mmap(NULL, sizeof(custom_data_t), PROT_READ | PROT_WRITE , MAP_SHARED ,fd ,0);
if(this_custom_data_ptr ==(custom_data_t *) -1) {
printf("ERROR mapping fd %d %s\n",fd,strerror(errno));
exit(1);
}
close(fd);
while (1) {
pthread_mutex_lock(&this_custom_data_ptr->ipc_mutex);
pthread_cond_wait(&this_custom_data_ptr->ipc_condvar, &this_custom_data_ptr->ipc_mutex);
memcpy(&this_data, this_custom_data_ptr, sizeof(this_custom_data_ptr));
if (prv_packet == 0){
printf ("got first ");
prv_packet = this_data.min;
}
if ((prv_packet +1) != this_data.min){
printf ("error prv:%d this:%d\n", prv_packet, this_data.min);
}
pthread_mutex_unlock(&this_custom_data_ptr->ipc_mutex);
prv_packet = this_data.min;
}
return 0;
}
What am I doing wrong? How do I synchronize so that once slave is connected it will not loose any data but if its not connected then master will not be blocked also.
Related
I'm reading the source code in https://wayland-book.com/surfaces/shared-memory.html .
The author create a shared memory using shm_open(), and shm_unlink() it immediately, then ftruncate() the fd to a specific size, mmap() the fd and fill the region with pixels.
I'm so confused why the fd still available after shm_unlink().
according to the man page:
The operation of shm_unlink() is analogous to unlink(2): it removes a shared memory object name, and, once all processes have unmapped the object, de-allocates and destroys the contents of the associated memory region. After a successful shm_unlink(), attempts to shm_open() an object with the same name will fail (unless O_CREAT was specified, in which case a new, distinct object is created).
so shm_unlink() will cause the memory destroyed because there is no process mmap
the region. But how fd still avaliable?
here is the code:
static int
create_shm_file(void)
{
int retries = 100;
do {
char name[] = "/wl_shm-XXXXXX";
randname(name + sizeof(name) - 7);
--retries;
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd >= 0) {
shm_unlink(name); // unlink immediately
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int
allocate_shm_file(size_t size)
{
int fd = create_shm_file();
if (fd < 0)
return -1;
int ret;
do {
ret = ftruncate(fd, size); //why the fd still available?
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
close(fd);
return -1;
}
return fd;
}
//after above, there was mmap
uint32_t *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
Hi I'm trying to write a client application which will try to connect a remote server. If it can not connect to the server, it will try once again after 5 seconds. If the socket is closed somehow, it will try to connect once again.
I'm getting an error like connect: Transport endpoint is already connected
What could be the problem ?
static void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
pid_t childpid;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(PORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
for ( ; ; ) {
while (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
sleep(5);
}
if ( (childpid = fork()) == 0)
{ /* child process */
while(1)
{
if (send(sockfd, "Hello, world!\n", 14, 0) == -1)
{
perror("send");
}
sleep(3);
}
close(sockfd);
}
}
return 0;
}
You can't reconnect a socket once you have even tried to connect it before, even if it failed. You have to close it and create a new one.
I use netlink to receive an interrupt number from kernel. The application in user space uses libevent to handle TCP/IP request and netlink message. Does libevent support Linux netlink socket? I will appreciate for a simple example.
Yes, libevent supports netlink socket.
There is https://github.com/libevent/libevent/blob/master/sample/hello-world.c, it is modified below to listen to netlink socket.
The basic example listens to Linux network interface creation/deletion and can be executed with sudo to gain privilege needed. It listens to same events as ip monitor link.
Another example of listening to RAW sockets with libevent is here https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c.
static void link_recvmsg(int fd, short event, void *arg)
{
char buf[NLMSG_SPACE(BUF_SIZE)] = {0};
socklen_t socklen;
struct iovec iov = {.iov_base = buf, .iov_len = sizeof(buf)};
struct sockaddr addr;
memset(&addr, 0, sizeof(struct sockaddr));
if (!fd || -1 == fd)
return;
int status = getsockname(fd, &addr, &socklen);
if(-1 == status)
return;
struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
.msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
status = recvmsg(fd, &mh, 0);
if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
return;
if(-1 == status)
return;
if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
return;
if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
return;
for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
switch (h->nlmsg_type) {
case RTM_NEWLINK:
fprintf(stderr, "got RTM_NEWLINK\n");
break;
case RTM_DELLINK:
fprintf(stderr, "got RTM_DELLINK\n");
break;
default:
fprintf(stderr, "unexpected case in swtch statement\n");
break;
}
}
}
int main(int argc, char **argv)
{
/* some init code here */
/* NETLINK socket */
int status;
int buf_size = BUF_SIZE;
struct sockaddr_nl src_addr;
int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
if(-1 == socket_nl) return -1;
memset(&src_addr, 0, sizeof(struct sockaddr_nl));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups |= RTNLGRP_LINK;
status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
&buf_size, sizeof(buf_size));
if(-1 == status) return -1;
status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
if(status < 0) return -1;
static struct event nl_ev;
event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
NULL);
if (base) {
event_base_set(base, &nl_ev);
}
event_add(&nl_ev, NULL);
/* some other code, dispatch event and deinit */
}
My goal is to set 2 threads for serial ports: one for read, one for write.
My example is refer to the [one](//refer to how to open, read, and write from serial port in C) heavily, but I added pthread to my code:
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h> /* POSIX Threads */
#define MAX_STR_LEN 256
/*
* The values for speed are
* B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc
*
* The values for parity are 0 (meaning no parity),
* PARENB|PARODD (enable parity and use odd),
* PARENB (enable parity and use even),
* PARENB|PARODD|CMSPAR (mark parity),
* and PARENB|CMSPAR (space parity).
* */
int SetInterfaceAttribs(int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) /* save current serial port settings */
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
return 0;
}/*set_interface_attribs*/
void SetBlocking(int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
}/*SetBlocking*/
void *sendThread(void *parameters)
{
char sendBuff[MAX_STR_LEN];
memset(&sendBuff[0], 0, MAX_STR_LEN);
snprintf(&sendBuff[0], MAX_STR_LEN, "hello!");
int fd;
fd = *((int*)parameters);
while(1)
{
write(fd, &sendBuff[0], strlen(&sendBuff[0]) );
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((strlen(&sendBuff[0]) + 25) * 100);
}/*while*/
pthread_exit(0);
}/*sendThread */
void *readThread(void *parameters)
{
char readBuff[MAX_STR_LEN];
int fd;
fd = *((int*)parameters);
while(1)
{
ssize_t len;
memset(&readBuff[0], 0, MAX_STR_LEN);
len = read(fd, &readBuff[0], MAX_STR_LEN);
if (len == -1)
{
switch(errno)
{
case EAGAIN:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
usleep(5*1000);
continue;
break;
default:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
pthread_exit(0);
break;
}
}
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((len + 25) * 100);
printf("len = %d\n", (int)len);
int i;
for(i = 0; i< len; i++)
printf("%c(%d %#x)\t", readBuff[i], readBuff[i], readBuff[i]);
printf("\n");
}/*while*/
pthread_exit(0);
}/*readThread */
int main(int argc, char *argv[])
{
int fd, c, res;
struct termios oldtio,newtio;
char buf[MAX_STR_LEN];
int k;
char deviceName[MAX_STR_LEN];
memset(&deviceName[0], 0, MAX_STR_LEN);
snprintf(&deviceName[0], MAX_STR_LEN, "/dev/ttyUSB0");
k = 1;
while(argc > k)
{
if(0 == strncmp(argv[k], "-d", MAX_STR_LEN))
{
if(k + 1 < argc)
{
snprintf(&deviceName[0], MAX_STR_LEN, "%s", argv[k + 1]);
}
else
{
printf("error : -d should be follow a device!\n");
return 0;
}/*if */
}
k++;
}/*while k*/
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
if(0 > fd)
{
perror(&deviceName[0]);
exit(-1);
}/*if */
SetInterfaceAttribs(fd, B115200, 0); /* set speed to 115,200 bps, 8n1 (no parity)*/
SetBlocking(fd, 1);
pthread_t readThread_t, sendThread_t; /* thread variables */
pthread_create(&sendThread_t, NULL, (void *)sendThread, (void *)&fd);
pthread_create(&readThread_t, NULL, (void *)readThread, (void *)&fd);
pthread_join(sendThread_t, NULL);
pthread_join(readThread_t, NULL);
close(fd);
return 0;
}/*main*/
The send data thread works well.
But the read data thread : I could not set it as blocking, the read function returns immediately, even the read data length is zero.
How should I modify the code to make the read function be blocked?
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
Try removing O_NONBLOCK and O_NDELAY from your open call. Or is there a particular reason you have that even though you specifically want it to block?
I use multuple thread to receive data from one socket. they all can receive the same data. I want to know when the data will be taken away from recv buffer? Why does not one thread receive the next data when former thread read former data.
pthread_create(&(ntid[i]), NULL, find_host, (void *)&start_addr);
int find_host(void * arg)
{
int sockfd;
unsigned long ip ;
tv.tv_sec = 0;
tv.tv_usec = 100000;
struct sockaddr_in from;
char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];
ip = *(unsigned long *)arg;
struct sockaddr_in present_addr;
if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0)
{
perror("socket error");
exit(1);
}
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) );
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))<0){
printf("socket option SO_RCVTIMEO not support\n");
return;
}
bzero(&present_addr,sizeof(present_addr));
present_addr.sin_family=AF_INET;
present_addr.sin_addr.s_addr = htonl(ip);
pthread_mutex_unlock(&lock);
printf("PING (%s): %d bytes data in ICMP packets.\n",
inet_ntoa(present_addr.sin_addr),ICMP_DATA_LEN);
send_packet(sockfd, sendpacket, present_addr);
recv_packet(sockfd, recvpacket, from);
close(sockfd);
}
void recv_packet(int sockfd, char * recvpacket, struct sockaddr_in from)
{ int n,from_len;
extern int errno;
int nreceived = 0;
struct timeval recv_time;
from_len = sizeof(from);
while (nreceived < MAX_SEND_TIMES)
{
if((n=recvfrom(sockfd,recvpacket, PACKET_SIZE, 0,
(struct sockaddr *)&from,&from_len)) <0)
{
if(errno == EWOULDBLOCK || errno== EAGAIN )
{
printf("recvfrom Timeout!!!!\n");
pthread_exit(NULL);
}
}
gettimeofday(&recv_time,NULL);
if (1 == unpack(recv_time, recvpacket, n, from))
{
printf(" find %u\n", (unsigned short)pthread_self());
nreceived++;
}
else
printf(" not find\n");
}
}