1: #include "global.h"
2:
3:
4: /*
5: * io_progInit() - Init program pool
6: *
7: * @progName = program name for execution
8: * @initNum = initial started programs
9: * @maxNum = maximum started programs
10: * return: NULL error or !=NULL allocated pool (must destroied with io_progDestroy())
11: */
12: prog_t *
13: io_progInit(const char *progName, u_int initNum, u_int maxNum)
14: {
15: prog_t *prg = NULL;
16:
17: if (initNum > maxNum)
18: return NULL;
19:
20: prg = e_malloc(sizeof(prog_t));
21: if (!prg) {
22: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
23: return NULL;
24: } else
25: memset(prg, 0, sizeof(prog_t));
26:
27: prg->prog_inin = initNum;
28: prg->prog_maxn = maxNum;
29: strlcpy(prg->prog_name, progName, sizeof prg->prog_name);
30:
31: prg->prog_used = e_malloc(E_ALIGN(prg->prog_maxn, sizeof *prg->prog_used) /
32: sizeof *prg->prog_used);
33: if (!prg->prog_used) {
34: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
35: e_free(prg);
36: return NULL;
37: }
38:
39: prg->prog_fds = array_Init(prg->prog_maxn);
40: if (!prg->prog_fds) {
41: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
42: e_free(prg->prog_used);
43: e_free(prg);
44: return NULL;
45: }
46:
47: pthread_mutex_init(&prg->prog_mtx, NULL);
48: signal(SIGPIPE, SIG_IGN);
49:
50: if (io_progOpen(prg, prg->prog_inin) < 0) {
51: io_progDestroy(&prg);
52: prg = NULL;
53: }
54: return prg;
55: }
56:
57: /*
58: * io_progDestroy() - Destroy entire program pool
59: *
60: * @pprg = program pool
61: * return: none
62: */
63: void
64: io_progDestroy(prog_t ** __restrict pprg)
65: {
66: if (!pprg || !*pprg)
67: return;
68:
69: io_progClose(*pprg, 0);
70:
71: e_free((*pprg)->prog_used);
72: array_Destroy(&(*pprg)->prog_fds);
73: pthread_mutex_destroy(&(*pprg)->prog_mtx);
74: signal(SIGPIPE, SIG_DFL);
75:
76: e_free(*pprg);
77: *pprg = NULL;
78: }
79:
80: /*
81: * io_progClose() - Close all programs in pool
82: *
83: * @prg = program pool
84: * @closeNum = close program(s) (0 all)
85: * return: 0 error, >0 closed programs
86: */
87: int
88: io_progClose(prog_t * __restrict prg, u_int closeNum)
89: {
90: register int i;
91: int ret = 0;
92:
93: if (!prg)
94: return 0;
95: if (closeNum > prg->prog_maxn) {
96: io_SetErr(EINVAL, "Requested number for close program is over pool's limit");
97: return 0;
98: }
99:
100: pthread_mutex_lock(&prg->prog_mtx);
101: for (i = array_Size(prg->prog_fds) - 1;
102: (closeNum ? ret < closeNum : 42) && i > -1; i--)
103: if (array_Get(prg->prog_fds, i)) {
104: #ifdef POPEN_STREAM
105: e_pclose(array(prg->prog_fds, i, FILE*));
106: #else
107: e_pclose((int) array(prg->prog_fds, i, intptr_t));
108: #endif
109: array_Del(prg->prog_fds, i, 0);
110: clrbit(prg->prog_used, i);
111: prg->prog_cnum--;
112: ret++;
113: }
114: pthread_mutex_unlock(&prg->prog_mtx);
115:
116: return ret;
117: }
118:
119: /*
120: * io_progOpen() - Execute number of program(s)
121: *
122: * @prg = program pool
123: * @execNum = execute program(s) (0 max)
124: * return: 0 error, >0 executed programs and abs(<0) executed programs with logged error
125: */
126: int
127: io_progOpen(prog_t * __restrict prg, u_int execNum)
128: {
129: #ifdef POPEN_STREAM
130: FILE *f;
131: #else
132: int f;
133: #endif
134: int stat, ret = 0;
135: register int i;
136: pid_t pid;
137:
138: if (!prg)
139: return 0;
140: if (prg->prog_cnum + execNum > prg->prog_maxn) {
141: io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
142: return 0;
143: }
144:
145: pthread_mutex_lock(&prg->prog_mtx);
146: for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++)
147: if (!array_Get(prg->prog_fds, i)) {
148: f = e_popen(prg->prog_name, "r+", &pid);
149: #ifdef POPEN_STREAM
150: if (!f) {
151: #else
152: if (f == -1) {
153: #endif
154: LOGERR;
155: ret = -1;
156: break;
157: } else if (waitpid(pid, &stat, WNOHANG)) {
158: io_SetErr(ECHILD, "Program with pid=%d exit with status %d",
159: pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1);
160: ret = -1;
161: break;
162: } else
163: array_Set(prg->prog_fds, i, f);
164: prg->prog_cnum++;
165: ret++;
166: }
167: pthread_mutex_unlock(&prg->prog_mtx);
168:
169: return ret;
170: }
171:
172: /*
173: * io_progGrow() - Execute to number of programs in pool
174: *
175: * @prg = program pool
176: * @toNum = execute to number of programs (0 max)
177: * return: 0 error, >0 executed programs and abs(<0) executed programs with logged error
178: */
179: int
180: io_progGrow(prog_t * __restrict prg, u_int toNum)
181: {
182: if (!prg)
183: return 0;
184: if (toNum > prg->prog_maxn) {
185: io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
186: return 0;
187: }
188: if (!toNum)
189: toNum = prg->prog_maxn;
190:
191: return io_progOpen(prg, toNum - prg->prog_cnum);
192: }
193:
194: /*
195: * io_progVacuum() - Vacuum pool to running number of programs
196: *
197: * @prg = program pool
198: * @toNum = vacuum to number of programs (0 to init number)
199: * return: 0 error or >0 closed programs
200: */
201: int
202: io_progVacuum(prog_t * __restrict prg, u_int toNum)
203: {
204: register int i;
205: int ret = 0;
206:
207: if (!prg)
208: return 0;
209: if (toNum > prg->prog_maxn) {
210: io_SetErr(EINVAL, "Requested number for close program is over pool's limit");
211: return 0;
212: }
213: if (!toNum)
214: toNum = prg->prog_inin;
215:
216: pthread_mutex_lock(&prg->prog_mtx);
217: for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--)
218: if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) {
219: #ifdef POPEN_STREAM
220: e_pclose(array(prg->prog_fds, i, FILE*));
221: #else
222: e_pclose((int) array(prg->prog_fds, i, intptr_t));
223: #endif
224: array_Del(prg->prog_fds, i, 0);
225: prg->prog_cnum--;
226: ret++;
227: }
228: pthread_mutex_unlock(&prg->prog_mtx);
229:
230: return ret;
231: }
232:
233: /*
234: * io_progCheck() - Check exit status of program pool
235: *
236: * @prg = program pool
237: * return: -1 error or >-1 exited programs
238: */
239: int
240: io_progCheck(prog_t * __restrict prg)
241: {
242: int ret = 0;
243: struct tagPIOPID *p;
244: register int i;
245:
246: if (!prg)
247: return -1;
248:
249: pthread_mutex_lock(&prg->prog_mtx);
250: for (i = 0; i < array_Size(prg->prog_fds); i++)
251: if (array_Get(prg->prog_fds, i) &&
252: #ifdef POPEN_STREAM
253: (p = pio_pgetpid(array(prg->prog_fds, i, FILE*))))
254: #else
255: (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t))))
256: #endif
257: if (waitpid(p->pid, &p->stat, WNOHANG) > 0) {
258: clrbit(prg->prog_used, i);
259: ret++;
260: }
261: pthread_mutex_unlock(&prg->prog_mtx);
262:
263: return ret;
264: }
265:
266: /*
267: * io_progAttach() - Attach to open program
268: *
269: * @prg = program pool
270: * return: NULL error or !=NULL attached program handle
271: */
272: #ifdef POPEN_STREAM
273: FILE *
274: #else
275: int
276: #endif
277: io_progAttach(prog_t * __restrict prg)
278: {
279: #ifdef POPEN_STREAM
280: FILE *f = NULL;
281: #else
282: int f = -1;
283: #endif
284: register int i;
285:
286: if (!prg)
287: #ifdef POPEN_STREAM
288: return NULL;
289: #else
290: return -1;
291: #endif
292:
293: pthread_mutex_lock(&prg->prog_mtx);
294: for (i = 0; i < array_Size(prg->prog_fds); i++)
295: if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) {
296: setbit(prg->prog_used, i);
297: #ifdef POPEN_STREAM
298: f = array(prg->prog_fds, i, FILE*);
299: #else
300: f = array(prg->prog_fds, i, intptr_t);
301: #endif
302: break;
303: }
304: pthread_mutex_unlock(&prg->prog_mtx);
305:
306: return f;
307: }
308:
309: /*
310: * io_progDetach() - Detch from open program
311: *
312: * @prg= program pool
313: * @pfd = attached program handle
314: * return: none
315: */
316: void
317: #ifdef POPEN_STREAM
318: io_progDetach(prog_t * __restrict prg, FILE *pfd)
319: #else
320: io_progDetach(prog_t * __restrict prg, int pfd)
321: #endif
322: {
323: register int i;
324:
325: if (!prg || !pfd)
326: return;
327:
328: pthread_mutex_lock(&prg->prog_mtx);
329: for (i = 0; i < array_Size(prg->prog_fds); i++)
330: #ifdef POPEN_STREAM
331: if (array(prg->prog_fds, i, FILE*) == pfd) {
332: #else
333: if (array(prg->prog_fds, i, intptr_t) == pfd) {
334: #endif
335: clrbit(prg->prog_used, i);
336: break;
337: }
338: pthread_mutex_unlock(&prg->prog_mtx);
339: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>