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
127
128
129
130
131
132
133
134
135
136
137
|
#include "PreProcessFilter.h"
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <csignal>
#include "Fdstream.h"
using namespace std;
#define CHILD_STDIN_READ pipefds_input[0]
#define CHILD_STDIN_WRITE pipefds_input[1]
#define CHILD_STDOUT_READ pipefds_output[0]
#define CHILD_STDOUT_WRITE pipefds_output[1]
#define CHILD_STDERR_READ pipefds_error[0]
#define CHILD_STDERR_WRITE pipefds_error[1]
// Child exec error signal
void exec_failed (int sig)
{
cerr << "Exec failed. Child process couldn't be launched." << endl;
exit (EXIT_FAILURE);
}
PreProcessFilter::PreProcessFilter(const string& filterCommand)
: m_toFilter(NULL),
m_fromFilter(NULL)
{
// Child error signal install
// sigaction is the replacement for the traditional signal() method
struct sigaction action;
action.sa_handler = exec_failed;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGUSR1, &action, NULL) < 0)
{
perror("SIGUSR1 install error");
exit(EXIT_FAILURE);
}
int pipe_status;
int pipefds_input[2];
int pipefds_output[2];
// int pipefds_error[2];
// Create the pipes
// We do this before the fork so both processes will know about
// the same pipe and they can communicate.
pipe_status = pipe(pipefds_input);
if (pipe_status == -1)
{
perror("Error creating the pipe");
exit(EXIT_FAILURE);
}
pipe_status = pipe(pipefds_output);
if (pipe_status == -1)
{
perror("Error creating the pipe");
exit(EXIT_FAILURE);
}
/*
pipe_status = pipe(pipefds_error);
if (pipe_status == -1)
{
perror("Error creating the pipe");
exit(EXIT_FAILURE);
}
*/
pid_t pid;
// Create child process; both processes continue from here
pid = fork();
if (pid == pid_t(0))
{
// Child process
// When the child process finishes sends a SIGCHLD signal
// to the parent
// Tie the standard input, output and error streams to the
// appropiate pipe ends
// The file descriptor 0 is the standard input
// We tie it to the read end of the pipe as we will use
// this end of the pipe to read from it
dup2 (CHILD_STDIN_READ,0);
dup2 (CHILD_STDOUT_WRITE,1);
// dup2 (CHILD_STDERR_WRITE,2);
// Close in the child the unused ends of the pipes
close(CHILD_STDIN_WRITE);
close(CHILD_STDOUT_READ);
//close(CHILD_STDERR_READ);
// Execute the program
execl("/bin/bash", "bash", "-c", filterCommand.c_str() , (char*)NULL);
// We should never reach this point
// Tell the parent the exec failed
kill(getppid(), SIGUSR1);
exit(EXIT_FAILURE);
}
else if (pid > pid_t(0))
{
// Parent
// Close in the parent the unused ends of the pipes
close(CHILD_STDIN_READ);
close(CHILD_STDOUT_WRITE);
// close(CHILD_STDERR_WRITE);
m_toFilter = new ofdstream(CHILD_STDIN_WRITE);
m_fromFilter = new ifdstream(CHILD_STDOUT_READ);
}
else
{
perror("Error: fork failed");
exit(EXIT_FAILURE);
}
}
string PreProcessFilter::ProcessSentence(const string& sentence)
{
*m_toFilter << sentence << "\n";
string processedSentence;
m_fromFilter->getline(processedSentence);
return processedSentence;
}
PreProcessFilter::~PreProcessFilter()
{
delete m_toFilter;
delete m_fromFilter;
}
|