1 /********************************************************************/
2 /*                                                                  */
3 /*  pcs_rtl.c     Platform idependent process handling functions.   */
4 /*  Copyright (C) 1989 - 2014  Thomas Mertes                        */
5 /*                                                                  */
6 /*  This file is part of the Seed7 Runtime Library.                 */
7 /*                                                                  */
8 /*  The Seed7 Runtime Library is free software; you can             */
9 /*  redistribute it and/or modify it under the terms of the GNU     */
10 /*  Lesser General Public License as published by the Free Software */
11 /*  Foundation; either version 2.1 of the License, or (at your      */
12 /*  option) any later version.                                      */
13 /*                                                                  */
14 /*  The Seed7 Runtime Library is distributed in the hope that it    */
15 /*  will be useful, but WITHOUT ANY WARRANTY; without even the      */
16 /*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /*  PURPOSE.  See the GNU Lesser General Public License for more    */
18 /*  details.                                                        */
19 /*                                                                  */
20 /*  You should have received a copy of the GNU Lesser General       */
21 /*  Public License along with this program; if not, write to the    */
22 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
23 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
24 /*                                                                  */
25 /*  Module: Seed7 Runtime Library                                   */
26 /*  File: seed7/src/pcs_rtl.c                                       */
27 /*  Changes: 2014  Thomas Mertes                                    */
28 /*  Content: Platform idependent process handling functions.        */
29 /*                                                                  */
30 /********************************************************************/
31 
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34 
35 #include "version.h"
36 
37 #include "stdio.h"
38 
39 #include "common.h"
40 #include "data_rtl.h"
41 #include "fil_rtl.h"
42 #include "rtl_err.h"
43 #include "pcs_drv.h"
44 
45 
46 
47 /**
48  *  Returns the error output file (stderr) of the given child process.
49  *  If the standard error file of the subprocess has been redirected
50  *  then this function will return NULL.
51  *  @return the error output file of 'process' or
52  *          CLIB_NULL_FILE, if stderr has been redirected.
53  */
pcsChildStdErr(const const_processType process)54 fileType pcsChildStdErr (const const_processType process)
55 
56   {
57     fileType stdErr;
58 
59   /* pcsChildStdErr */
60     if (unlikely(process == NULL)) {
61       logError(printf("pcsChildStdErr: process == NULL\n"););
62       raise_error(FILE_ERROR);
63       stdErr = NULL;
64     } else if (process->stdErr == NULL) {
65       stdErr = &nullFileRecord;
66     } else {
67       stdErr = process->stdErr;
68       stdErr->usage_count++;
69     } /* if */
70     return stdErr;
71   } /* pcsChildStdErr */
72 
73 
74 
75 /**
76  *  Returns the standard input file (stdin) of the given child process.
77  *  If the standard input file of the subprocess has been redirected
78  *  then this function will return NULL.
79  *  @return the standard input file of 'process' or
80  *          CLIB_NULL_FILE, if stdin has been redirected.
81  */
pcsChildStdIn(const const_processType process)82 fileType pcsChildStdIn (const const_processType process)
83 
84   {
85     fileType stdIn;
86 
87   /* pcsChildStdIn */
88     if (unlikely(process == NULL)) {
89       logError(printf("pcsChildStdIn: process == NULL\n"););
90       raise_error(FILE_ERROR);
91       stdIn = NULL;
92     } else if (process->stdIn == NULL) {
93       stdIn = &nullFileRecord;
94     } else {
95       stdIn = process->stdIn;
96       stdIn->usage_count++;
97     } /* if */
98     return stdIn;
99   } /* pcsChildStdIn */
100 
101 
102 
103 /**
104  *  Returns the standard output file (stdout) of the given child process.
105  *  If the standard output file of the subprocess has been redirected
106  *  then this function will return NULL.
107  *  @return the standard output file of 'process' or
108  *          CLIB_NULL_FILE, if stdout has been redirected.
109  */
pcsChildStdOut(const const_processType process)110 fileType pcsChildStdOut (const const_processType process)
111 
112   {
113     fileType stdOut;
114 
115   /* pcsChildStdOut */
116     if (unlikely(process == NULL)) {
117       logError(printf("pcsChildStdOut: process == NULL\n"););
118       raise_error(FILE_ERROR);
119       stdOut = NULL;
120     } else if (process->stdOut == NULL) {
121       stdOut = &nullFileRecord;
122     } else {
123       stdOut = process->stdOut;
124       stdOut->usage_count++;
125     } /* if */
126     return stdOut;
127   } /* pcsChildStdOut */
128 
129 
130 
131 /**
132  *  Reinterpret the generic parameters as processType and call pcsCmp.
133  *  Function pointers in C programs generated by the Seed7 compiler
134  *  may point to this function. This assures correct behaviour even
135  *  if sizeof(genericType) != sizeof(processType).
136  *  @return -1, 0 or 1 if the first argument is considered to be
137  *          respectively less than, equal to, or greater than the
138  *          second.
139  */
pcsCmpGeneric(const genericType value1,const genericType value2)140 intType pcsCmpGeneric (const genericType value1, const genericType value2)
141 
142   { /* pcsCmpGeneric */
143     return pcsCmp(((const_rtlObjectType *) &value1)->value.processValue,
144                   ((const_rtlObjectType *) &value2)->value.processValue);
145   } /* pcsCmpGeneric */
146 
147 
148 
149 /**
150  *  Assign source to *dest.
151  *  A copy function assumes that *dest contains a legal value.
152  */
pcsCpy(processType * const dest,const processType source)153 void pcsCpy (processType *const dest, const processType source)
154 
155   { /* pcsCpy */
156     logFunction(printf("pcsCpy(" FMT_U_MEM " (usage=" FMT_U "), "
157                        FMT_U_MEM " (usage=" FMT_U "))\n",
158                        (memSizeType) *dest,
159                        *dest != NULL ? (*dest)->usage_count : (uintType) 0,
160                        (memSizeType) source,
161                        source != NULL ? source->usage_count : (uintType) 0););
162     if (source != NULL) {
163       source->usage_count++;
164     } /* if */
165     if (*dest != NULL) {
166       (*dest)->usage_count--;
167       if ((*dest)->usage_count == 0) {
168         pcsFree(*dest);
169       } /* if */
170     } /* if */
171     *dest = source;
172     logFunction(printf("pcsCpy(" FMT_U_MEM " (usage=" FMT_U "), "
173                        FMT_U_MEM " (usage=" FMT_U ")) -->\n",
174                        (memSizeType) *dest,
175                        *dest != NULL ? (*dest)->usage_count : (uintType) 0,
176                        (memSizeType) source,
177                        source != NULL ? source->usage_count : (uintType) 0););
178   } /* pcsCpy */
179 
180 
181 
182 /**
183  *  Reinterpret the generic parameters as processType and call pcsCpy.
184  *  Function pointers in C programs generated by the Seed7 compiler
185  *  may point to this function. This assures correct behaviour even
186  *  if sizeof(genericType) != sizeof(processType).
187  */
pcsCpyGeneric(genericType * const dest,const genericType source)188 void pcsCpyGeneric (genericType *const dest, const genericType source)
189 
190   { /* pcsCpyGeneric */
191     pcsCpy(&((rtlObjectType *) dest)->value.processValue,
192            ((const_rtlObjectType *) &source)->value.processValue);
193   } /* pcsCpyGeneric */
194 
195 
196 
197 /**
198  *  Return a copy of source, that can be assigned to a new destination.
199  *  It is assumed that the destination of the assignment is undefined.
200  *  Create functions can be used to initialize Seed7 constants.
201  *  @return a copy of source.
202  */
pcsCreate(const processType source)203 processType pcsCreate (const processType source)
204 
205   { /* pcsCreate */
206     logFunction(printf("pcsCreate(" FMT_U_MEM ") (usage=" FMT_U ")\n",
207                        (memSizeType) source,
208                        source != NULL ? source->usage_count : (uintType) 0););
209     if (source != NULL) {
210       source->usage_count++;
211     } /* if */
212     logFunction(printf("pcsCreate --> " FMT_U_MEM " (usage=" FMT_U ")\n",
213                        (memSizeType) source,
214                        source != NULL ? source->usage_count : (uintType) 0););
215     return source;
216   } /* pcsCreate */
217 
218 
219 
220 /**
221  *  Generic Create function to be used via function pointers.
222  *  Function pointers in C programs generated by the Seed7 compiler
223  *  may point to this function. This assures correct behaviour even
224  *  if sizeof(genericType) != sizeof(processType).
225  */
pcsCreateGeneric(const genericType from_value)226 genericType pcsCreateGeneric (const genericType from_value)
227 
228   {
229     rtlObjectType result;
230 
231   /* pcsCreateGeneric */
232     INIT_GENERIC_PTR(result.value.genericValue);
233     result.value.processValue =
234         pcsCreate(((const_rtlObjectType *) &from_value)->value.processValue);
235     return result.value.genericValue;
236   } /* pcsCreateGeneric */
237 
238 
239 
240 /**
241  *  Free the memory referred by 'oldProcess'.
242  *  After pcsDestr is left 'oldProcess' refers to not existing memory.
243  *  The memory where 'oldProcess' is stored can be freed afterwards.
244  */
pcsDestr(const processType oldProcess)245 void pcsDestr (const processType oldProcess)
246 
247   { /* pcsDestr */
248     logFunction(printf("pcsDestr(" FMT_U_MEM ") (usage=" FMT_U ")\n",
249                        (memSizeType) oldProcess,
250                        oldProcess != NULL ? oldProcess->usage_count : (uintType) 0););
251     if (oldProcess != NULL) {
252       oldProcess->usage_count--;
253       if (oldProcess->usage_count == 0) {
254         if (oldProcess->stdIn != NULL) {
255           filClose(oldProcess->stdIn);
256           filDestr(oldProcess->stdIn);
257         } /* if */
258         if (oldProcess->stdOut != NULL) {
259           filClose(oldProcess->stdOut);
260           filDestr(oldProcess->stdOut);
261         } /* if */
262         if (oldProcess->stdErr != NULL) {
263           filClose(oldProcess->stdErr);
264           filDestr(oldProcess->stdErr);
265         } /* if */
266         pcsFree(oldProcess);
267       } /* if */
268     } /* if */
269   } /* pcsDestr */
270 
271 
272 
273 /**
274  *  Generic Destr function to be used via function pointers.
275  *  Function pointers in C programs generated by the Seed7 compiler
276  *  may point to this function. This assures correct behaviour even
277  *  if sizeof(genericType) != sizeof(processType).
278  */
pcsDestrGeneric(const genericType old_value)279 void pcsDestrGeneric (const genericType old_value)
280 
281   { /* pcsDestrGeneric */
282     pcsDestr(((const_rtlObjectType *) &old_value)->value.processValue);
283   } /* pcsDestrGeneric */
284