multiplexing using poll() or select

Hi there,
I am to write a program with the following specifications:

1. Parent process creates 2 new processes and establishes a pipe with each of the children.
The child is the writer and the parent is the reader.

1.1 Child1 does some calculations to estimate the value of pi
1.2 Child2 does some calculations to estimate the value of e

2. The estimates are given to some number of decimals. The decimal part of
the calculations is piped() to the parent.

3. The parent manages the incomming values using select or poll
and stores the respective values in pi.dat and e.dat respectively.

4. The parent waits for the children and closes their file descriptors when
they (children) finishes.

Here is my genuine attempt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <iostream>
#include <poll.h>
#include <cstdlib>
#include <cerrno>
#include <stropts.h>
#include <unistd.h>
#include "Restart.h"
#include "PiCalculator.h" // calculates pi
#include "eCalculator.h" // calculates e
#include "CommandLineHandler.h" // process cli

using std::cout;
using std::endl;
int createFile(const char *path);

#define DEFAULT_NUMBERS 50000
#define PI_FILE "pi.dat" // file to hold the pi values
#define E_FILE "e.dat" // file to hold the e values
#define NUM_OF_FDS 2
#define BUFFSIZE  1024

int main(int args, char **argv)
{
    pid_t child1, child2;


    auto command = CommandLineHandler(args, argv); // process cli 
    IntegerPair values{}; // std::pair<int, int>
    
    int decimalPlaces{}, // number of decimal places for the calculation
    numberOfValues{}; // number of times calculations will occur

    if(command.isGoodParameters()){ // cli gave us values as expected
        values= command.getValues();  // get pair<int, int>
        decimalPlaces = values.first;
        numberOfValues = (values.second == 0? DEFAULT_NUMBERS: values.second);


        cout << "Decimals " << decimalPlaces << " Number of iterations "
             << numberOfValues << endl;

        int piFile = createFile(PI_FILE);
        int eFile = createFile(E_FILE);
        int fds[NUM_OF_FDS] = {piFile, eFile};

        char buf[BUFFSIZE];
        int bytesread{};
        int numnow{};
        int i;
        
        // initialize the polling
        for(i = 0; i < NUM_OF_FDS; i++){
            if(fds[i] >= 0){
                numnow++;
            }
        }

        if(pipe(fds) == -1){
            cerr << "Failed to create the pipe" << endl;
            return 1;
        }
        cout << "Current file descriptors: " << numnow << endl;
        struct pollfd *pfd = nullptr;
        for(i = 0; i < NUM_OF_FDS; i++){
            (pfd +i)->fd = *(fds + i);
            (pfd + i)->events = POLLRDNORM;
        }
        if(pfd == nullptr){
            cerr << "Error initializing poll" << endl;
            return 1;
        }

        
        // create the children
        child1 = fork();
        if(child1){ // parent stuff

        }else{
            PiCalculator piCalulator(decimalPlaces, pfd[0].fd);
            piCalulator.doCalc();
        }
        child2 = fork();
        if(child2){ // parent stuff

        }else{
            eCalculator eCalculator(decimalPlaces, pfd[1].fd);
            eCalculator.doCalc();
        }

        // Trying to mimic Textbook exmaple 
        // Unix systems programming: Communication, Concurrency, 
        // and Threads by Kay A. R and Steven R (2003)
        // Program 4.17: monitorpool.c 
        //==>  http://usp.cs.utsa.edu/usp/programs/chapter04/monitorpoll.c
        // continue monitorying until descriptors are done
       /* int numready{};
        while(numnow > 0){
            cout << "yes inside here" << endl;
            numready = poll(pfd, NUM_OF_FDS, -1);
            if((numready == -1) && (errno == EINTR)){
                continue; // continue running if here is signal interrupt
            }else if(numready == -1){
                cerr << "An unexpected polling error occured" << endl;
            }
            bytesread = r_read(pfd[0].fd, buf, BUFFSIZE);
            cout << "Bytes read " << bytesread << endl;

        }
        */
        // free poll
        if(pfd != nullptr){
            for(i = 0; i < NUM_OF_FDS; i++){
                r_close(fds[i]);
            }
            free(pfd);
        }
    }

    //cout << "This compiles and works" << endl;

    return 0;
}

int createFile(const char *path){
    return open(path, O_WRONLY|O_CREAT|O_APPEND, S_IRWXU);
}

Any form of help will be highly appreciated.
Last edited on
To use poll, you pass it an array of poll_items. Each poll item describes what you want to wait for and contains:
1. the file descriptor
2. the event you want to wait for (input or output)
3. the output event should be initialized to zero

You pass in the array along with a timeout. When pool fires, you check the output event field of each poll item to decide what to do. Typically you're interested in input, so you'd use POLLITEM_IN (from memory).

Select does the same thing, but in a different way. As select is passed a larger array, it's a little less efficient.
There are some FD_ macros to help out. You pass in a array of file descriptors, the size of the array is the largest file descriptor you're interested in. FD_ZERO initializes the array, FD_SET is used register your interest in read, write or error, then it's kinda the same as poll after that.
Thanks @kbw for the input. This is giving real headache but from your tips and more reading, i am sure i will reach there soon.
I kinda forgot. All this talk of file descriptors, what FDs do we use?

You have to create a pipe between the parent and the child and fixup the ends of the pipe such that writing in the child is readable by the parent. There's an example here:
https://github.com/skuhl/sys-prog-examples/blob/master/simple-examples/pipe-dup2.c

and here:
https://bitbucket.org/kbw/wb-samples/src/master/os/posix/ipc/chain/main.cc
Last edited on
Thanks @kbw. The example at bitbucket helped me complete the task.
Here we describe the code briefly for multiplexing using poll() or select method.
This makes us think that we can just #define FD_SETSIZE to some larger value before including this header to increase the size of the descriptor sets used by select.

#include "unp.h"

void
str_cli(FILE *fp, int sockfd)
{
int maxfdp1;
fd_set rset;
char sendline[MAXLINE], recvline[MAXLINE];

FD_ZERO(&rset);
for ( ; ; ) {
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);

if (FD_ISSET(sockfd, &rset)) { /* socket is readable */
if (Readline(sockfd, recvline, MAXLINE) == 0)
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);
}

if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */
if (Fgets(sendline, MAXLINE, fp) == NULL)
return; /* all done */
Writen(sockfd, sendline, strlen(sendline));
}
}
}

For more info visit:- http://www.cetpainfotech.com/technology/unix-training
Topic archived. No new replies allowed.