I'm trying to share mmapped area in 2 processes.
In my program, I create memory_update() process and memory_read() process.
This memory_update() process update mmapped area and tried to read that area in memory_read() process.
But I got when I tried to read the mmapped area.
So far, I don't have good luck to find a solution for this problem.
If you have any idea, please leave your comments.
Here is the source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define COLUMN 80
#define ROW 10
#define BUFSIZE 80
#define SHM_KEY 0x9998
struct _row {
int32_t flag;
unsigned char *buffer;
};
typedef enum {
DATA_READY,
DATA_RESET
} msg_type_t;
struct _ipc_message {
msg_type_t type;
int32_t value;
};
typedef struct _ipc_message ipc_message_t;
typedef struct _row row_t;
int32_t format_number_string(char *buf, int32_t num)
{
sprintf(buf, "%02d", num);
return 0;
}
int32_t update_row(char *buf, char *str)
{
strncpy(buf, str, 80);
return 0;
}
int32_t print_row(char *buf)
{
printf("print_row buf = %p\n", (void *)buf);
printf("%s\n", buf);
return 0;
}
int32_t memory_update(int32_t sk)
{
row_t *p_row;
ipc_message_t msg;
unsigned char *shared_mem;
unsigned char *ptr;
char rbuf[BUFSIZE];
char nbuf[3];
int32_t shmid;
int32_t i;
int32_t ret;
int32_t fd;
shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory Error");
return -1;
}
/* Attach Shared Memory */
shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void *)-1)
{
perror("Shared Memory Attach Error");
return -1;
}
fd = open("testfile", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror("File Open Error");
}
ptr = mmap(
NULL,
COLUMN * ROW,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
printf("ptr = %p\n", (void *)ptr);
for (i = 0 ; i < ROW ; i++)
{
format_number_string(nbuf, i);
memset(rbuf, 0x20, BUFSIZE);
sprintf(rbuf, "LINE %s :", nbuf);
rbuf[strlen(rbuf)] = ' ';
rbuf[BUFSIZE-1] = 0x0;
update_row(&ptr[i * COLUMN], rbuf);
}
for (i = 0 ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
p_row->flag = 0x99;
p_row->buffer = &ptr[i * COLUMN];
// print_row(p_row->buffer);
}
msg.type = DATA_READY;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
i = 0;
for ( ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
if (p_row->flag == 0x0)
{
printf("row[%d] has processed\n", i);
}
else
{
i--;
sleep(1);
}
}
/* Detach Shared Memory */
ret = shmdt(shared_mem);
if (ret == -1)
{
perror("Shared Memory Detach Error");
return -1;
}
ret = munmap(ptr, COLUMN * ROW);
if (ret != 0)
{
printf("UnMapping Failed\n");
return -1;
}
close(fd);
return 0;
}
int32_t memory_read(int32_t sk)
{
row_t *p_row;
ipc_message_t msg;
unsigned char *shared_mem;
int32_t shmid;
int32_t ret;
int32_t i;
while (1)
{
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_READY)
{
continue;
}
else
{
break;
}
}
shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory Error");
return -1;
}
/* Attach Shared Memory */
shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void *)-1)
{
perror("Shared Memory Attach Error");
return -1;
}
for (i = 0 ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
printf("memory_read process [%d]\n", i);
print_row(p_row->buffer);
p_row->flag = 0x0;
sleep(1);
}
/* Detach Shared Memory */
ret = shmdt(shared_mem);
if (ret == -1)
{
perror("Shared Memory Detach Error");
return -1;
}
return 0;
}
int32_t main(void)
{
pid_t pid;
int32_t sp[2];
int32_t ret;
static const int32_t ps = 0;
static const int32_t cs = 1;
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
if (ret == -1)
{
perror("socketpair");
return -1;
}
pid = fork();
if (pid == 0)
{
close(sp[ps]);
memory_update(sp[cs]);
}
else
{
close(sp[cs]);
memory_read(sp[ps]);
}
return 0;
}
And this is the output.
$ ./mmm
ptr = 0x7fdc214a8000
memory_read process [0]
print_row buf = 0x7fdc214a8000
Segmentation fault (core dumped)
Modifed code to mmap before forking.
And it is working as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define COLUMNS 80
#define ROWS 60
#define BUFSIZE 80
typedef enum {
DATA_PRODUCED,
DATA_CONSUMED
} msg_type_t;
struct _ipc_message {
msg_type_t type;
int32_t value;
};
typedef struct _ipc_message ipc_message_t;
int32_t memory_update(int32_t sk, char *buf)
{
ipc_message_t msg;
int32_t ret;
char *msg2 = "updated buffer";
printf("memory_update : 1.buf = %s\n", buf);
memset(buf, 0, 80);
strncpy(buf, msg2, strlen(msg2));
buf[strlen(msg2)] = 0;
printf("memory_update : 2.buf = %s\n", buf);
printf("memory_update : send message from memory_update process\n");
msg.type = DATA_PRODUCED;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
while (1)
{
printf("memory_update : receive message from memory_read process\n");
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_CONSUMED)
{
continue;
}
else
{
break;
}
}
printf("memory_update : 3.buf = %s\n", buf);
return 0;
}
int32_t memory_read(int32_t sk, char *buf)
{
ipc_message_t msg;
int32_t ret;
int32_t i;
char *msg3 = "buffer processed";
printf("memory_read : 1.buf = %s\n", buf);
while (1)
{
printf("memory_read : receive message from memory_update process\n");
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_PRODUCED)
{
continue;
}
else
{
break;
}
}
printf("memory_read : 2.buf = %s\n", buf);
memset(buf, 0, 80);
strncpy(buf, msg3, strlen(msg3));
buf[strlen(msg3)] = 0;
printf("memory_read : 3.buf = %s\n", buf);
printf("memory_read : send message from memory_update process\n");
msg.type = DATA_CONSUMED;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
return 0;
}
int32_t main(void)
{
pid_t pid;
int32_t sp[2];
int32_t ret;
int32_t fd;
int32_t i;
char *ptr;
char *msg1 = "initial message";
static const int32_t ps = 0;
static const int32_t cs = 1;
fd = open("80bytes", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror("File Open Error");
}
ptr = mmap(
NULL,
80,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
memset(ptr, 0, 80);
strncpy(ptr, msg1, strlen(msg1));
ptr[strlen(msg1)] = 0;
printf("ptr = %s\n", ptr);
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
if (ret == -1)
{
perror("socketpair");
return -1;
}
pid = fork();
if (pid == 0) /* child process */
{
close(sp[ps]);
memory_update(sp[cs], ptr);
}
else /* parent process */
{
close(sp[cs]);
memory_read(sp[ps], ptr);
ret = munmap(ptr, 80);
if (ret != 0)
{
printf("UnMapping Failed\n");
return -1;
}
close(fd);
}
return 0;
}
Related
I'm planing to monitor the fifo and stdin with select function, but it always block the code flow even though O_NONBLOCK is configured, would anyone help check about it please ?
I'm not sure it's the code issue or solution is not a right direction to try, thanks in advance.
There are 2 problems :
stdin is not able to read when the program start.
FD_ISSET(pipe_fd, &fds) will continuously be true, if do not close pipe_fd manually.
if (FD_ISSET(pipe_fd, &fds)) {
read_pipe(pipe_fd);
close_pipe(pipe_fd); // continously triggered if not close here
}
Here is the full code.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define BUF_SZ 128
#define FIFO_BUF_SZ 128
#define PIPE_PATH "./test_fifo"
int create_pipe_fd()
{
char *f_path = PIPE_PATH;
int ret;
// creating the named file(FIFO)
// mkfifo(<pathname>, <permission>)
//ret = mkfifo(f_path, 0666);
ret = mkfifo(f_path, 0666);
if (ret < 0) {
printf("create fifo file failed, err = %s\n", strerror(errno));
}
}
int open_pipe()
{
char *f_path = PIPE_PATH;
int fd;
// open fifo for read only
fd = open(f_path, O_RDONLY);
// non blocking mode
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
printf("mode set failed, err = %s\n", strerror(errno));
}
return fd;
}
int read_pipe(int fd)
{
uint8_t buf[FIFO_BUF_SZ];
ssize_t cnt;
size_t end;
size_t sz = sizeof(buf);
cnt = read(fd, buf, sz);
end = (cnt > (sz - 1)) ? (sz - 1) : cnt;
buf[end] = '\0';
printf("read pipe = %s\n", buf);
}
void close_pipe(int fd)
{
close(fd);
//printf("pipe closed.\n");
}
uint16_t read_stdin()
{
char *line = NULL;
size_t len = 0;
ssize_t lineSize = 0;
uint8_t stdin_buf[BUF_SZ];
lineSize = getline(&line, &len, stdin);
printf("[stdin %zu bytes] : %s", lineSize, line);
if (0 == strncmp("stop", line, strlen("stop"))) {
return 0;
}
free(line);
return (int)lineSize;
}
int main()
{
fd_set fds;
int max_fd = 0;
int pipe_fd = -1;
uint16_t bytes;
printf("start.\n");
// get pipe file descriptor
//pipe_fd = create_pipe_fd();
create_pipe_fd();
pipe_fd = open_pipe();
//max_fd = pipe_fd > max_fd ? pipe_fd : max_fd;
while (1) {
FD_ZERO(&fds);
// stdin
FD_SET(0, &fds);
//pipe_fd = open_pipe();
if (pipe_fd > 0) {
FD_SET(pipe_fd, &fds);
}
max_fd = pipe_fd > max_fd ? pipe_fd : max_fd;
select(max_fd + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(0, &fds)) {
bytes = read_stdin();
if (0 == bytes) {
break;
}
}
if (FD_ISSET(pipe_fd, &fds)) {
read_pipe(pipe_fd);
close_pipe(pipe_fd);
}
}
_EXIT:
if (pipe_fd) {
close_pipe(pipe_fd);
}
printf("exit.\n");
}
I have a working code with performs asynchronous DNS resolution with c-ares library calls. The program uses select to monitor file descriptors up to a maximum of FD_SETSIZE which is 1024 on my system. I want to use many more file descriptors so want to rewrite the code to use epoll instead of select.
Here is the select based function of my current program:
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
I've done some googling before posting my question and I've found out that to implement this with epoll I can no longer use ares_fds, ares_timeout and ares_process but must use ares_getsock() and ares_process_fd() instead. But further than that I have no idea how to do this and can't find any example codes using epoll with c-ares. Can anyone modify the code provided below to use epoll instead of select? Or at least give me some pointers to get me started?
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
The program requires a file with a domain name on each line to work.
This is what I ended up coming up with.
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define DNS_MAX_EVENTS 10000
#define DNS_MAX_SERVERS 2
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
ares_socket_t dns_client_fds[ARES_GETSOCK_MAXNUM] = {0};
struct epoll_event ev, events[DNS_MAX_EVENTS];
int i,bitmask,nfds, epollfd, timeout, fd_count, ret;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
nfds=0;
bitmask=0;
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, dns_client_fds[i], NULL) < 0) {
continue;
}
}
}
memset(dns_client_fds, 0, sizeof(dns_client_fds));
bitmask = ares_getsock(channel, dns_client_fds, DNS_MAX_SERVERS);
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
ev.events = 0;
if (ARES_GETSOCK_READABLE(bitmask, i)) {
ev.events |= EPOLLIN;
}
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
ev.events |= EPOLLOUT;
}
ev.data.fd = dns_client_fds[i];
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, dns_client_fds[i], &ev) < 0) {
if(errno == EEXIST) {
nfds++;
continue;
}
continue;
}
nfds++;
}
}
if(nfds==0)
{
return;
}
timeout = 1000;//millisecs
fd_count = epoll_wait(epollfd, events, DNS_MAX_EVENTS, timeout);
if (fd_count < 0) {
return;
}
if (fd_count > 0) {
for (i = 0; i < fd_count; ++i) {
ares_process_fd(channel, ((events[i].events) & (EPOLLIN) ? events[i].data.fd:ARES_SOCKET_BAD), ((events[i].events) & (EPOLLOUT)? events[i].data.fd:ARES_SOCKET_BAD));
}
} else {
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
memset(dns_client_fds, 0, sizeof(dns_client_fds));
memset((char *)&ev, 0, sizeof(struct epoll_event));
memset((char *)&events[0], 0, sizeof(events));
epollfd = epoll_create(DNS_MAX_SERVERS);
if (epollfd < 0) {
perror("epoll_create: ");
}
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
I was writing a simple shared memory test program like below.
And I used a line like below.
e_intf[i % 8].flag = i;
I thought it should be like below.
e_intf[i % 8]->flag = i;
But if I use "->" operator, I have errors.
This is a full source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#define SHM_KEY 0x9998
typedef struct _ethernet_interface {
char name[8];
int32_t flag;
} Ethernet_Interface_t;
int32_t memory_update(void)
{
int32_t i = 0;
int32_t shmid;
Ethernet_Interface_t *e_intf;
int32_t ret;
shmid = shmget(SHM_KEY, 8 * sizeof(Ethernet_Interface_t), 0644|IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory");
return -1;
}
e_intf = shmat(shmid, NULL, 0);
if (e_intf == (void *)-1)
{
perror("Shared Memory Attach");
return -1;
}
while (1)
{
e_intf[i % 8].flag = i;
if (i < 8)
{
sprintf(e_intf[i % 8].name, "%s%d", "eth", (i % 8));
}
printf("memory_update : e_intf[%d].name = %s, e_intf[%d] = %d\n", i % 8, e_intf[i % 8].name, (i % 8), i);
sleep(2);
i++;
}
ret = shmdt(e_intf);
if (ret == -1)
{
perror("shmdt");
return -1;
}
return 0;
}
int32_t memory_read(void)
{
int32_t i;
int32_t shmid;
Ethernet_Interface_t *e_intf;
int32_t ret;
shmid = shmget(SHM_KEY, 8 * sizeof(Ethernet_Interface_t), 0644|IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory");
return -1;
}
e_intf = shmat(shmid, NULL, 0);
if (e_intf == (void *)-1)
{
perror("Shared Memory Attach");
return -1;
}
i = 0;
while (1)
{
printf("[%d]memory_read : index = %d\n", i, (i % 8));
printf("[%d]memory_read : e_intf[%d].name = %s\n", i, (i % 8), e_intf[i % 8].name);
printf("[%d]memory_read : e_intf[%d].flag = %d\n", i, (i % 8), e_intf[i % 8].flag);
if (e_intf[i % 8].flag == 42)
{
printf("[%d]memory_read : Exiting\n", i);
break;
}
sleep(1);
i++;
}
ret = shmdt(e_intf);
if (ret == -1)
{
perror("shmdt");
return -1;
}
ret = shmctl(shmid, IPC_RMID, 0);
if (ret == -1)
{
perror("shmctl");
return -1;
}
return 0;
}
int32_t main(int32_t argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid == 0)
{
/* child process */
memory_update();
}
else
{
/* parent process */
memory_read();
}
exit(0);
}
But when I made another simple test program for pointer operation.
I can use "->" operator as I expected.
Here is the source code for the test program for pointer operation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct _ethernet_interface {
char name[8];
int32_t flag;
} Ethernet_Interface_t;
int32_t main(int32_t argc, char *argv[])
{
Ethernet_Interface_t intf;
Ethernet_Interface_t *p_intf;
p_intf = malloc(sizeof(Ethernet_Interface_t));
intf.flag = 1111;
p_intf->flag = 2222;
printf("intf.flag = %d\n", intf.flag);
printf("p_intf->flag = %d\n", p_intf->flag);
return 0;
}
Can someone point out why I am confused with these 2 cases?
The answer is very simple - index dereferences the pointer:
pointer[n] === *(pointer + n)
so in your case:
e_intf[i % 8] === *(e_intf + i % 8)
and
e_intf[i % 8].flag == (*(e_intf + i % 8)).flag
if you want to use the -> operator you need pointer, not referenced object.
(&e_intf[i % 8]) -> flag
or
(e_intf + i % 8) -> flag
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm setting up a prototype for a DAQ system for Zynq FPGAs. I receive data from a server through ethernet, write it to a FIFO using the DMA and viceversa using two different pthreads. However, threads work correctly only if printf are executed. I expect there is a memory leak or some lines leading to a undefined behaviour, but I can't spot it.
Placing output to stderr has the same result. Changing addresses does nothing different.
Sorry for the shameful code, but I tried replacing almost every line by now to spot the problem.
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/stat.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>
#define PORT 8080
#define SA struct sockaddr
#define MM2S_CONTROL_REGISTER 0x00
#define MM2S_STATUS_REGISTER 0x04
#define MM2S_START_ADDRESS 0x18
#define MM2S_LENGTH 0x28
#define S2MM_CONTROL_REGISTER 0x30
#define S2MM_STATUS_REGISTER 0x34
#define S2MM_DESTINATION_ADDRESS 0x48
#define S2MM_LENGTH 0x58
#define VIRT_ADDR 0x40400000
#define FIFO_ADDR 0x0c000000
#define SEND_ADDR 0x0a000000
#define RECV_ADDR 0x0b000000
#define TIMEOUT 10
#define MAX_TRANSF 12274
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value);
unsigned int dma_get(unsigned int *dma_virtual_address, int offset);
int dma_mm2s_sync(unsigned int *dma_virtual_address);
int dma_s2mm_sync(unsigned int *dma_virtual_address);
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address);
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address);
void memdump(void *virtual_address, int byte_count);
void print_status(unsigned int status);
unsigned long int elements = 0;
clock_t start_time;
typedef struct arg_struct {
unsigned int *virtual_address;
unsigned int *virtual_buffer;
unsigned int *head;
unsigned int *tail;
unsigned int buffsize;
unsigned int fifosize;
unsigned int sockfd;
pthread_mutex_t *lock;
char verbose;
} arguments;
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value) {
dma_virtual_address[offset >> 2] = value;
}
unsigned int dma_get(unsigned int *dma_virtual_address, int offset) {
return dma_virtual_address[offset >> 2];
}
int dma_mm2s_sync(unsigned int *dma_virtual_address) {
unsigned int mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
while (!(mm2s_status & 1 << 12) || !(mm2s_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
}
int dma_s2mm_sync(unsigned int *dma_virtual_address) {
unsigned int s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
while (!(s2mm_status & 1 << 12) || !(s2mm_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
}
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
void print_mm2s_status(unsigned int status) {
fprintf(stderr, "[*] Stream to memory-mapped status (0x%08x#0x%02x):", status, S2MM_STATUS_REGISTER);
print_status(status);
}
void print_s2mm_status(unsigned int status) {
fprintf(stderr, "[*] Memory-mapped to stream status (0x%08x#0x%02x):", status, MM2S_STATUS_REGISTER);
print_status(status);
}
void print_status(unsigned int status) {
if (status & 0x00000001) fprintf(stderr, " halted");
else fprintf(stderr, " running");
if (status & 0x00000002) fprintf(stderr, " idle");
if (status & 0x00000008) fprintf(stderr, " SGIncld");
if (status & 0x00000010) fprintf(stderr, " DMAIntErr");
if (status & 0x00000020) fprintf(stderr, " DMASlvErr");
if (status & 0x00000040) fprintf(stderr, " DMADecErr");
if (status & 0x00000100) fprintf(stderr, " SGIntErr");
if (status & 0x00000200) fprintf(stderr, " SGSlvErr");
if (status & 0x00000400) fprintf(stderr, " SGDecErr");
if (status & 0x00001000) fprintf(stderr, " IOC_Irq");
if (status & 0x00002000) fprintf(stderr, " Dly_Irq");
if (status & 0x00004000) fprintf(stderr, " Err_Irq");
fprintf(stderr, "\n");
}
void memdump(void *virtual_address, int byte_count) {
char * p = virtual_address;
int offset;
for (offset = 0; offset < byte_count; offset++) {
fprintf(stderr, "%02x", p[offset]);
if (offset % 4 == 3) {
fprintf(stderr, " ");
}
}
}
void DMATransfer(unsigned int *virtual_address, long unsigned int src, long unsigned int dest, unsigned int length, char verbose) {
unsigned int s2mm_status = 0;
unsigned int mm2s_status = 0;
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 4);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 4);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_DESTINATION_ADDRESS, dest);
dma_set(virtual_address, MM2S_START_ADDRESS, src);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0xf001);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0xf001);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_LENGTH, length);
dma_set(virtual_address, MM2S_LENGTH, length);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_mm2s_sync(virtual_address);
dma_s2mm_status(virtual_address);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
}
int GetCPULoad() {
int FileHandler;
char FileBuffer[1024];
float load;
FileHandler = open("/proc/loadavg", O_RDONLY);
if(FileHandler < 0) {
return -1;
}
read(FileHandler, FileBuffer, sizeof(FileBuffer) - 1);
sscanf(FileBuffer, "%f", &load);
close(FileHandler);
return (int)(load * 100);
}
void *sender(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Send buffer pointer not valid\n");
exit(0);
}
unsigned long int units_sent = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Send Head: %d Tail: %d\n", myhead, mytail);
if (myhead != mytail) {
int remaining = args->buffsize;
int sent = 0;
int src = FIFO_ADDR + mytail * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Sender: DMA is transferring data from 0x%x to 0x%x\n", src, SEND_ADDR);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, src + sent, SEND_ADDR, length, verb);
remaining -= args->buffsize;
sent += remaining;
}
pthread_mutex_unlock(args->lock);
elements--;
units_sent++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to buffer: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
remaining = args->buffsize;
sent = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = send(args->sockfd, args->virtual_buffer + sent, remaining, 0);
if (result > 0) {
remaining -= result;
sent += remaining;
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
*(args->tail) = (mytail + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit sent: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet retrieved");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("0000000000000000000000000\n");
}
}
void *receiver(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Recv buffer pointer not valid\n");
exit(0);
}
unsigned long int units_received = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Recv Head: %d Tail: %d\n", myhead, mytail);
if (mytail != myhead + 1) {
int remaining = args->buffsize;
int received = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = recv(args->sockfd, args->virtual_buffer + received, remaining, 0);
fprintf(stderr, "[*] Recv result: %d\n", result);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
printf("++++++++++++++++++++++++++++\n");
pthread_mutex_unlock(args->lock);
units_received++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit recv: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
remaining = args->buffsize;
received = 0;
int dest = FIFO_ADDR + myhead * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Receiver: DMA is transferring data from 0x%x to 0x%x\n", RECV_ADDR, dest);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
printf("############################\n");
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, RECV_ADDR, dest + received, length, verb);
remaining -= args->buffsize;
received += args->buffsize;
}
printf("*************************\n");
*(args->head) = (myhead + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
elements++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to DDR: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet received");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("77777777777777777777777777777\n");
}
}
int isValidIpAddress(char *ipAddress) {
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
if (result != 0) {
return 0;
} else {
return 1;
}
}
int main(int argc, char *argv[]) {
if (argc < 3 || argc > 5) {
fprintf(stderr, "\nUsage: DAQTest [IP address] [fifo size]\nExample: DAQTest 192.168.1.81 64\n\n");
fprintf(stderr, "Optional flags: -v Verbose (print operations)\n");
fprintf(stderr, " -vv Very verbose (also print data content)\n");
fprintf(stderr, " -vvv Extremely verbose (also print DMA info)\n\n");
exit(0);
}
if (isValidIpAddress(argv[1]) == 1) {
fprintf(stderr, "[-] Invalid ip address\n");
exit(0);
}
int fifosize = atoi(argv[2]);
if (fifosize < 0 || fifosize > 8192) {
fprintf(stderr, "[-] Invalid fifo size\n");
exit(0);
}
char verbose = 0;
if (argc == 4) {
if (strcmp(argv[3], "-v") == 0) {
verbose = 1;
} else if (strcmp(argv[3], "-vv") == 0) {
verbose = 2;
} else if (strcmp(argv[3], "-vvv") == 0) {
verbose = 3;
} else {
fprintf(stderr, "[-] Unwanted parameter\n");
exit(0);
}
}
struct sockaddr_in servaddr, cli;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
fprintf(stderr, "[-] Socket creation failed\n");
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(PORT);
/*
struct timeval tv;
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
*/
if (connect(sockfd, (SA * ) & servaddr, sizeof(servaddr)) != 0) {
fprintf(stderr, "[-] Connection failed\n");
exit(0);
}
fprintf(stderr, "[+] Connected to the server\n");
int buffsize = 0;
char* recv_buffer = (char*)&buffsize;
int remaining = sizeof(int);
int received = 0;
int result = 0;
while (remaining > 0) {
result = recv(sockfd, recv_buffer + received, remaining, 0);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
//fprintf(stderr, "[*] Page size: %ld\n", sysconf(_SC_PAGE_SIZE));
int dh = open("/dev/mem", O_RDWR | O_SYNC);
unsigned int *virtual_address = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, dh, VIRT_ADDR);
unsigned int *virtual_sendbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, SEND_ADDR);
unsigned int *virtual_recvbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, RECV_ADDR);
unsigned int *virtual_fifo = mmap(NULL, (fifosize + 1) * buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, FIFO_ADDR);
if (virtual_address == MAP_FAILED) {
fprintf(stderr, "[-] AXI DMA registers mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_recvbuff == MAP_FAILED) {
fprintf(stderr, "[-] Receiver buffer mmap failed\n");
}
if (virtual_fifo == MAP_FAILED) {
fprintf(stderr, "[-] Fifo mmap failed\n");
}
memset(virtual_address, 0, buffsize);
memset(virtual_sendbuff, 0, buffsize);
memset(virtual_recvbuff, 0, buffsize);
memset(virtual_fifo, 0, buffsize);
int head = 0, tail = 0;
pthread_t sendth, recvth;
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
arguments send_args;
send_args.virtual_address = virtual_address;
send_args.virtual_buffer = virtual_sendbuff;
send_args.head = &head;
send_args.tail = &tail;
send_args.buffsize = buffsize;
send_args.fifosize = fifosize;
send_args.sockfd = sockfd;
send_args.lock = &lock;
send_args.verbose = verbose;
arguments recv_args;
recv_args.virtual_address = virtual_address;
recv_args.virtual_buffer = virtual_recvbuff;
recv_args.head = &head;
recv_args.tail = &tail;
recv_args.buffsize = buffsize;
recv_args.fifosize = fifosize;
recv_args.sockfd = sockfd;
recv_args.lock = &lock;
recv_args.verbose = verbose;
start_time = clock();
if (pthread_create(&sendth, NULL, sender, &send_args)) {
fprintf(stderr, "[-] Error creating sender thread\n");
exit(0);
}
if (pthread_create(&recvth, NULL, receiver, &recv_args)) {
fprintf(stderr, "[-] Error creating receiver thread\n");
exit(0);
}
if (pthread_join(sendth, NULL)) {
fprintf(stderr, "[-] Error joining sender thread\n");
exit(0);
}
if (pthread_join(recvth, NULL)) {
fprintf(stderr, "[-] Error joining receiver thread\n");
exit(0);
}
pthread_mutex_destroy(&lock);
close(sockfd);
fprintf(stderr, "[+] Exit\n");
return 0;
}
Try replacing the print statements with delays.
As you're doing networking, you're speed constrained by your network connection. If you do not take this into considerations, your transfer buffers may overflow. The print statements add a certain delay, which might prevent this. Replacing them with actual delays would check for this.
A better solution - if this were indeed the problem - would then be to check for buffer availability before writing.
I am trying to implement something that will give me a solution for:
| --> cmd3 --> cmd4 -->
cmd2-->|
| --> cmd5 --> cmd6 -->
and so on...
This is multiple executions of processes and pipe the results via chains of other's processes with threads, each commands chain should run in different thread.
I choose socketpair for the implementation of IPC, because pipe has a a bottleneck with the buffer size limit 64K.
When I test the program with single chain - it's work as expected, but when I am running master command and the output of it I send via socketpair to read end of multiple processes in each thread - the program stuck (look like a deadlock)
Whats I am doing wrong:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>
typedef struct command {
char** argv;
int num_children;
struct command* master_cmd;
struct command** chains;
struct command* next;
int fd;
} command;
void be_child(command* cmd);
int execute_master_command_and_pipe_to_childs(command* cmd, int input);
int run_pipeline_sockets(command *cmd, int input);
void waitfor(int fd);
int main(int argc, char* argv[]) {
handle_segfault();
command* cmd1 = (command*) malloc(sizeof(command));
command* cmd2 = (command*) malloc(sizeof(command));
command* cmd3 = (command*) malloc(sizeof(command));
command* cmd4 = (command*) malloc(sizeof(command));
command* cmd5 = (command*) malloc(sizeof(command));
command* cmd6 = (command*) malloc(sizeof(command));
command* chains1[2];
chains1[0] = cmd3;
chains1[1] = cmd5;
char* args1[] = { "cat", "/tmp/test.log", NULL };
char* args3[] = { "sort", NULL, NULL };
char* args4[] = { "wc", "-l", NULL };
char* args5[] = { "wc", "-l", NULL };
char* args6[] = { "wc", "-l", NULL };
cmd1->argv = args1;
cmd2->argv = NULL;
cmd3->argv = args3;
cmd4->argv = args4;
cmd5->argv = args5;
cmd6->argv = args6;
cmd1->master_cmd = NULL;
cmd1->next = NULL;
cmd1->chains = NULL;
cmd1->num_children = -1;
cmd2->master_cmd = cmd1;
cmd2->chains = chains1;
cmd2->next = NULL;
cmd2->num_children = 2;
cmd3->master_cmd = NULL;
cmd3->next = cmd4;
cmd3->chains = NULL;
cmd3->num_children = -1;
cmd4->master_cmd = NULL;
cmd4->next = NULL;
cmd4->chains = NULL;
cmd4->num_children = -1;
cmd5->master_cmd = NULL;
cmd5->next = cmd6;
cmd5->chains = NULL;
cmd5->num_children = -1;
cmd6->master_cmd = NULL;
cmd6->next = NULL;
cmd6->chains = NULL;
cmd6->num_children = -1;
int rc = execute_master_command_and_pipe_to_childs(cmd2, -1);
return 0;
}
int execute_master_command_and_pipe_to_childs(command* cmd, int input) {
int num_children = cmd->num_children;
int write_pipes[num_children];
pthread_t threads[num_children];
command* master_cmd = cmd->master_cmd;
pid_t pid;
int i;
for (i = 0; i < num_children; i++) {
int new_pipe[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, new_pipe) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "ERROR (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if (cmd->chains[i] != NULL) {
cmd->chains[i]->fd = new_pipe[0];
if (pthread_create(&threads[i], NULL, (void *) be_child,
cmd->chains[i]) != 0) {
perror("pthread_create"), exit(1);
}
write_pipes[i] = new_pipe[1];
} else {
perror("ERROR\n");
}
}
if (input != -1) {
waitfor(input);
}
int pipefd = run_pipeline_sockets(master_cmd, input);
int buffer[1024];
int len = 0;
while ((len = read(pipefd, buffer, sizeof(buffer))) != 0) {
int j;
for (j = 0; j < num_children; j++) {
if (write(write_pipes[j], &buffer, len) != len) {
fprintf(STDERR_FILENO, "Write failed (child %d)\n", j);
exit(1);
}
}
}
close(pipefd);
for (i = 0; i < num_children; i++) {
close(write_pipes[i]);
}
for (i = 0; i < num_children; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("pthread_join"), exit(1);
}
}
}
void waitfor(int fd) {
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 500000;
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else if (retval) {
printf("Data is available now on: %d\n", fd);
} else {
printf("No data on: %d\n", fd);
///waitfor(fd);
}
}
void be_child(command* cmd) {
printf(
"fd = %d , argv = %s , args = %s , next = %d , master_cmd = %d , next_chain = %d\n",
cmd->fd, cmd->argv[0], cmd->argv[1], cmd->next, cmd->master_cmd,
cmd->chains);
waitfor(cmd->fd);
int fd = run_pipeline_sockets(cmd, cmd->fd);
waitfor(fd);
int buffer[1024];
int len = 0;
while ((len = read(fd, buffer, sizeof(buffer))) != 0) {
write(STDERR_FILENO, &buffer, len);
}
close(cmd->fd);
close(fd);
}
int run_pipeline_sockets(command *cmd, int input) {
int pfds[2] = { -1, -1 };
int pid = -1;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pfds) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "socketpair failed (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if ((pid = fork()) == 0) { /* child */
if (input != -1) {
dup2(input, STDIN_FILENO);
close(input);
}
if (pfds[1] != -1) {
dup2(pfds[1], STDOUT_FILENO);
close(pfds[1]);
}
if (pfds[0] != -1) {
close(pfds[0]);
}
execvp(cmd->argv[0], cmd->argv);
exit(1);
} else { /* parent */
if (input != -1) {
close(input);
}
if (pfds[1] != -1) {
close(pfds[1]);
}
if (cmd->next != NULL) {
run_pipeline_sockets(cmd->next, pfds[0]);
} else {
return pfds[0];
}
}
}
void segfault_sigaction(int signal, siginfo_t *si, void *arg) {
printf("Caught segfault at address %p\n", si->si_addr);
printf("Caught segfault errno %p\n", si->si_errno);
exit(0);
}
void handle_segfault(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = segfault_sigaction;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
}
I would come at this problem from a very different angle: rather than coming up with a large data structure to manage the pipe tree, and using threads (where an io blockage in a process may block in its threads) I would use only processes.
I also fail to see how a 64K buffer is your bottleneck when you're only using a 1K buffer.
2 simple functions should guide this: (error handling omitted for brevity, and using a pseudocodey parsecmd() function which turns a space separated string into an argument vector)
int mkproc(char *cmd, int outfd)
{
Command c = parsecmd(cmd);
int pipeleft[2];
pipe(pipeleft);
if(!fork()){
close(pipeleft[1]);
dup2(pipeleft[0], 0);
dup2(outfd, 1);
execvp(c.name, c.argv);
}
close(pipeleft[0]);
return pipeleft[1];
}
Mkproc takes the fd it will write to, and returns what it will read from. This way chains are really easy to initalize:
int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
the next is:
int mktree(char *cmd, int ofd0, ...)
{
int piperight[2];
pipe(piperight);
int cmdin = mkproc(cmd, piperight[1]);
close(piperight[1]);
if(!fork()){
uchar buf[4096];
int n;
while((n=read(piperight[0], buf, sizeof buf))>0){
va_list ap;
int fd;
va_start(ap, ofd0);
for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
write(fd, buf, n);
}
va_end(ap);
}
}
return cmdin;
}
Between the two of these, it is very easy to construct trees of arbitrary complexity, as so:
int tree_in = mktree("cat foo.txt",
mktree("rot13",
mkproc("uniq", mkproc("wc -l", 1)),
mkproc("wc -l", open("out.txt", O_WRONLY)), -1),
mkproc("sort", 2), -1);
This would output a sorted foo.txt to stderr, the number of lines in rot13'd foo.txt to out.txt, and the number of non-duplicate lines of rot13'd foo.txt to stdout.