Annotation of libaitio/src/exec.c, revision 1.4
1.3 misho 1: /*************************************************************************
2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.4 ! misho 6: * $Id: exec.c,v 1.3.2.1 2014/02/05 02:24:28 misho Exp $
1.3 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.4 ! misho 15: Copyright 2004 - 2014
1.3 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.2 misho 46: #include "global.h"
47:
48:
49: /*
50: * io_progInit() - Init program pool
51: *
52: * @progName = program name for execution
53: * @initNum = initial started programs
54: * @maxNum = maximum started programs
55: * return: NULL error or !=NULL allocated pool (must destroied with io_progDestroy())
56: */
57: prog_t *
58: io_progInit(const char *progName, u_int initNum, u_int maxNum)
59: {
60: prog_t *prg = NULL;
61:
62: if (initNum > maxNum)
63: return NULL;
64:
65: prg = e_malloc(sizeof(prog_t));
66: if (!prg) {
67: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
68: return NULL;
69: } else
70: memset(prg, 0, sizeof(prog_t));
71:
72: prg->prog_inin = initNum;
73: prg->prog_maxn = maxNum;
74: strlcpy(prg->prog_name, progName, sizeof prg->prog_name);
75:
76: prg->prog_used = e_malloc(E_ALIGN(prg->prog_maxn, sizeof *prg->prog_used) /
77: sizeof *prg->prog_used);
78: if (!prg->prog_used) {
79: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
80: e_free(prg);
81: return NULL;
82: }
83:
84: prg->prog_fds = array_Init(prg->prog_maxn);
85: if (!prg->prog_fds) {
86: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
87: e_free(prg->prog_used);
88: e_free(prg);
89: return NULL;
90: }
91:
92: pthread_mutex_init(&prg->prog_mtx, NULL);
93: signal(SIGPIPE, SIG_IGN);
94:
95: if (io_progOpen(prg, prg->prog_inin) < 0) {
96: io_progDestroy(&prg);
97: prg = NULL;
98: }
99: return prg;
100: }
101:
102: /*
103: * io_progDestroy() - Destroy entire program pool
104: *
105: * @pprg = program pool
106: * return: none
107: */
108: void
109: io_progDestroy(prog_t ** __restrict pprg)
110: {
111: if (!pprg || !*pprg)
112: return;
113:
114: io_progClose(*pprg, 0);
115:
116: e_free((*pprg)->prog_used);
117: array_Destroy(&(*pprg)->prog_fds);
118: pthread_mutex_destroy(&(*pprg)->prog_mtx);
119: signal(SIGPIPE, SIG_DFL);
120:
121: e_free(*pprg);
122: *pprg = NULL;
123: }
124:
125: /*
126: * io_progClose() - Close all programs in pool
127: *
128: * @prg = program pool
129: * @closeNum = close program(s) (0 all)
130: * return: 0 error, >0 closed programs
131: */
132: int
133: io_progClose(prog_t * __restrict prg, u_int closeNum)
134: {
135: register int i;
136: int ret = 0;
137: struct tagPIOPID *p;
138:
139: if (!prg)
140: return 0;
141: if (closeNum > prg->prog_maxn) {
142: io_SetErr(EINVAL, "Requested number for close program is over pool's limit");
143: return 0;
144: }
145:
146: pthread_mutex_lock(&prg->prog_mtx);
147: for (i = array_Size(prg->prog_fds) - 1;
148: (closeNum ? ret < closeNum : 42) && i > -1; i--)
149: if (array_Get(prg->prog_fds, i) &&
150: #ifdef POPEN_STREAM
151: (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) {
152: #else
153: (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t)))) {
154: #endif
155: kill(p->pid, SIGTERM);
156: usleep(1000);
157: if (waitpid(p->pid, &p->stat, WNOHANG) > 0)
158: kill(p->pid, SIGKILL);
159: #ifdef POPEN_STREAM
160: e_pclose(array(prg->prog_fds, i, FILE*));
161: #else
162: e_pclose((int) array(prg->prog_fds, i, intptr_t));
163: #endif
164: array_Del(prg->prog_fds, i, 0);
165: clrbit(prg->prog_used, i);
166: prg->prog_cnum--;
167: ret++;
168: }
169: pthread_mutex_unlock(&prg->prog_mtx);
170:
171: return ret;
172: }
173:
174: /*
175: * io_progCloseAt() - Close program at pool of certain position
176: *
177: * @prg = program pool
178: * @idx = index at pool
179: * return: 0 error or !=0 closed program
180: */
181: int
182: io_progCloseAt(prog_t * __restrict prg, u_int idx)
183: {
184: int ret = 0;
185: struct tagPIOPID *p;
186:
187: if (!prg)
188: return 0;
189: if (idx > prg->prog_maxn) {
190: io_SetErr(EINVAL, "Requested number for close program is over pool's limit");
191: return 0;
192: }
193:
194: pthread_mutex_lock(&prg->prog_mtx);
195: if (array_Get(prg->prog_fds, idx) &&
196: #ifdef POPEN_STREAM
197: (p = pio_pgetpid(array(prg->prog_fds, idx, FILE*)))) {
198: #else
199: (p = pio_pgetpid((int) array(prg->prog_fds, idx, intptr_t)))) {
200: #endif
201: kill(p->pid, SIGTERM);
202: usleep(1000);
203: if (waitpid(p->pid, &p->stat, WNOHANG) > 0)
204: kill(p->pid, SIGKILL);
205: #ifdef POPEN_STREAM
206: e_pclose(array(prg->prog_fds, idx, FILE*));
207: #else
208: e_pclose((int) array(prg->prog_fds, idx, intptr_t));
209: #endif
210: array_Del(prg->prog_fds, idx, 0);
211: clrbit(prg->prog_used, idx);
212: prg->prog_cnum--;
213: ret++;
214: }
215: pthread_mutex_unlock(&prg->prog_mtx);
216:
217: return ret;
218: }
219:
220: /*
221: * io_progCloseOf() - Close program at pool with certain handle
222: *
223: * @prg = program pool
224: * @h = handle of program
225: * return: 0 error, >0 closed programs
226: */
227: int
228: #ifdef POPEN_STREAM
229: io_progCloseOf(prog_t * __restrict prg, FILE *h)
230: #else
231: io_progCloseOf(prog_t * __restrict prg, int h)
232: #endif
233: {
234: register int i;
235: int ret = 0;
236: struct tagPIOPID *p;
237: #ifdef POPEN_STREAM
238: FILE *f;
239: #else
240: int f;
241: #endif
242:
243: if (!prg)
244: return 0;
245:
246: pthread_mutex_lock(&prg->prog_mtx);
247: for (i = 0; i < array_Size(prg->prog_fds); i++)
248: if (array_Get(prg->prog_fds, i)) {
249: #ifdef POPEN_STREAM
250: f = array(prg->prog_fds, i, FILE*);
251: if (f == h && (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) {
252: #else
253: f = (int) array(prg->prog_fds, i, intptr_t);
254: if (f == h && (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t)))) {
255: #endif
256: kill(p->pid, SIGTERM);
257: usleep(1000);
258: if (waitpid(p->pid, &p->stat, WNOHANG) > 0)
259: kill(p->pid, SIGKILL);
260: #ifdef POPEN_STREAM
261: e_pclose(array(prg->prog_fds, i, FILE*));
262: #else
263: e_pclose((int) array(prg->prog_fds, i, intptr_t));
264: #endif
265: array_Del(prg->prog_fds, i, 0);
266: clrbit(prg->prog_used, i);
267: prg->prog_cnum--;
268: ret++;
269: break;
270: }
271: }
272: pthread_mutex_unlock(&prg->prog_mtx);
273:
274: return ret;
275: }
276:
277: /*
278: * io_progOpen2() - Start program from pool on first unused slot
279: *
280: * @prg = program pool
281: * return: -1 error, >-1 reside at slot
282: */
283: int
284: io_progOpen2(prog_t * __restrict prg)
285: {
286: #ifdef POPEN_STREAM
287: FILE *f = NULL;
288: #else
289: int f = -1;
290: #endif
291: int stat, ret = -1;
292: register int i;
293: pid_t pid;
294:
295: if (!prg)
296: return -1;
297: if (prg->prog_cnum + 1 > prg->prog_maxn) {
298: io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
299: return -1;
300: }
301:
302: pthread_mutex_lock(&prg->prog_mtx);
303: for (i = 0; i < array_Size(prg->prog_fds); i++)
304: if (!array_Get(prg->prog_fds, i)) {
305: f = e_popen(prg->prog_name, "r+", &pid);
306: #ifdef POPEN_STREAM
307: if (!f) {
308: #else
309: if (f == -1) {
310: #endif
311: LOGERR;
312: break;
313: } else if (waitpid(pid, &stat, WNOHANG)) {
314: io_SetErr(ECHILD, "Program with pid=%d exit with status %d",
315: pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1);
316: e_pclose(f);
317: break;
318: } else
1.3 misho 319: array_Set(prg->prog_fds, i, (intptr_t) f);
1.2 misho 320: clrbit(prg->prog_used, i);
321: prg->prog_cnum++;
322: ret = i;
323: break;
324: }
325: pthread_mutex_unlock(&prg->prog_mtx);
326:
327: return ret;
328: }
329:
330: /*
331: * io_progOpen() - Execute number of program(s)
332: *
333: * @prg = program pool
334: * @execNum = execute program(s) (0 max)
335: * return: -1 error, >0 executed programs
336: */
337: int
338: io_progOpen(prog_t * __restrict prg, u_int execNum)
339: {
340: #ifdef POPEN_STREAM
341: FILE *f;
342: #else
343: int f;
344: #endif
345: int stat, ret = 0;
346: register int i;
347: pid_t pid;
348:
349: if (!prg)
350: return -1;
351: if (prg->prog_cnum + execNum > prg->prog_maxn) {
352: io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
353: return -1;
354: }
355:
356: pthread_mutex_lock(&prg->prog_mtx);
357: for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++)
358: if (!array_Get(prg->prog_fds, i)) {
359: f = e_popen(prg->prog_name, "r+", &pid);
360: #ifdef POPEN_STREAM
361: if (!f) {
362: #else
363: if (f == -1) {
364: #endif
365: LOGERR;
366: ret = -1;
367: break;
368: } else if (waitpid(pid, &stat, WNOHANG)) {
369: io_SetErr(ECHILD, "Program with pid=%d exit with status %d",
370: pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1);
371: e_pclose(f);
372: ret = -1;
373: break;
374: } else
1.3 misho 375: array_Set(prg->prog_fds, i, (intptr_t) f);
1.2 misho 376: clrbit(prg->prog_used, i);
377: prg->prog_cnum++;
378: ret++;
379: }
380: pthread_mutex_unlock(&prg->prog_mtx);
381:
382: return ret;
383: }
384:
385: /*
386: * io_progGrow() - Execute to number of programs in pool
387: *
388: * @prg = program pool
389: * @toNum = execute to number of programs (0 max)
390: * return: 0 error or nothing to do,
391: * >0 executed programs and abs(<0) executed programs with logged error
392: */
393: int
394: io_progGrow(prog_t * __restrict prg, u_int toNum)
395: {
396: if (!prg)
397: return 0;
398: if (toNum > prg->prog_maxn) {
399: io_SetErr(EINVAL, "Requested number for program execution is over pool's limit");
400: return 0;
401: }
402: if (!toNum)
403: toNum = prg->prog_maxn;
404: if (toNum < prg->prog_inin)
405: toNum = prg->prog_inin;
406:
407: if ((int) (toNum - prg->prog_cnum) < 1)
408: return 0;
409:
410: return io_progOpen(prg, toNum - prg->prog_cnum);
411: }
412:
413: /*
414: * io_progVacuum() - Vacuum pool to running number of programs
415: *
416: * @prg = program pool
417: * @toNum = vacuum to number of programs (0 to init number)
418: * return: 0 error or >0 closed programs
419: */
420: int
421: io_progVacuum(prog_t * __restrict prg, u_int toNum)
422: {
423: register int i;
424: int ret = 0;
425: struct tagPIOPID *p;
426:
427: if (!prg)
428: return 0;
429: if (toNum > prg->prog_maxn) {
430: io_SetErr(EINVAL, "Requested number for close program is over pool's limit");
431: return 0;
432: }
433: if (!toNum)
434: toNum = prg->prog_inin;
435:
436: pthread_mutex_lock(&prg->prog_mtx);
437: for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--)
438: if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i) &&
439: #ifdef POPEN_STREAM
440: (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) {
441: kill(p->pid, SIGTERM);
442: usleep(1000);
443: if (waitpid(p->pid, &p->stat, WNOHANG) > 0)
444: kill(p->pid, SIGKILL);
445: e_pclose(array(prg->prog_fds, i, FILE*));
446: #else
447: (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t)))) {
448: kill(p->pid, SIGTERM);
449: usleep(1000);
450: if (waitpid(p->pid, &p->stat, WNOHANG) > 0)
451: kill(p->pid, SIGKILL);
452: e_pclose((int) array(prg->prog_fds, i, intptr_t));
453: #endif
454: array_Del(prg->prog_fds, i, 0);
455: prg->prog_cnum--;
456: ret++;
457: }
458: pthread_mutex_unlock(&prg->prog_mtx);
459:
460: return ret;
461: }
462:
463: /*
464: * io_progCheck() - Check exit status of program pool
465: *
466: * @prg = program pool
467: * @re = resurrect program to init number
468: * return: -1 error or >-1 exited programs
469: */
470: int
471: io_progCheck(prog_t * __restrict prg, int re)
472: {
473: int ret = 0;
474: struct tagPIOPID *p;
475: register int i;
476:
477: if (!prg)
478: return -1;
479:
480: pthread_mutex_lock(&prg->prog_mtx);
481: for (i = 0; i < array_Size(prg->prog_fds); i++)
482: if (array_Get(prg->prog_fds, i) &&
483: #ifdef POPEN_STREAM
484: (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) {
485: #else
486: (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t)))) {
487: #endif
488: if (waitpid(p->pid, &p->stat, WNOHANG)) {
489: clrbit(prg->prog_used, i);
490: #ifdef POPEN_STREAM
491: e_pclose(array(prg->prog_fds, i, FILE*));
492: #else
493: e_pclose((int) array(prg->prog_fds, i, intptr_t));
494: #endif
495: array_Del(prg->prog_fds, i, 0);
496: prg->prog_cnum--;
497: ret++;
498: }
499: }
500: pthread_mutex_unlock(&prg->prog_mtx);
501:
502: /* resurrect to init number */
503: if (re && ((int) (prg->prog_inin - prg->prog_cnum) > 0))
504: io_progOpen(prg, prg->prog_inin - prg->prog_cnum);
505:
506: return ret;
507: }
508:
509: /*
510: * io_progAttach() - Attach to open program
511: *
512: * @prg = program pool
513: * @newOne = Execute new one program after attach
514: * return: NULL error or !=NULL attached program handle
515: */
516: #ifdef POPEN_STREAM
517: FILE *
518: #else
519: int
520: #endif
521: io_progAttach(prog_t * __restrict prg, int newOne)
522: {
523: #ifdef POPEN_STREAM
524: FILE *f = NULL;
525: #else
526: int f = -1;
527: #endif
528: register int i;
529:
530: if (!prg)
531: #ifdef POPEN_STREAM
532: return NULL;
533: #else
534: return -1;
535: #endif
536:
537: pthread_mutex_lock(&prg->prog_mtx);
538: for (i = 0; i < array_Size(prg->prog_fds); i++)
539: if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) {
540: setbit(prg->prog_used, i);
541: #ifdef POPEN_STREAM
542: f = array(prg->prog_fds, i, FILE*);
543: #else
544: f = array(prg->prog_fds, i, intptr_t);
545: #endif
546: break;
547: }
548: pthread_mutex_unlock(&prg->prog_mtx);
549:
550: /* execute new one program */
551: if (newOne) {
552: if (f)
553: io_progOpen(prg, 1);
554: else if ((i = io_progOpen2(prg)) > -1)
555: /* not found free program */
556: #ifdef POPEN_STREAM
557: f = array(prg->prog_fds, i, FILE*);
558: #else
559: f = array(prg->prog_fds, i, intptr_t);
560: #endif
561: }
562:
563: return f;
564: }
565:
566: /*
567: * io_progDetach() - Detch from open program
568: *
569: * @prg= program pool
570: * @pfd = attached program handle
571: * return: none
572: */
573: void
574: #ifdef POPEN_STREAM
575: io_progDetach(prog_t * __restrict prg, FILE *pfd)
576: #else
577: io_progDetach(prog_t * __restrict prg, int pfd)
578: #endif
579: {
580: register int i;
581:
582: if (!prg || !pfd)
583: return;
584:
585: pthread_mutex_lock(&prg->prog_mtx);
586: for (i = 0; i < array_Size(prg->prog_fds); i++)
587: #ifdef POPEN_STREAM
588: if (array(prg->prog_fds, i, FILE*) == pfd) {
589: #else
590: if (array(prg->prog_fds, i, intptr_t) == pfd) {
591: #endif
592: clrbit(prg->prog_used, i);
593: break;
594: }
595: pthread_mutex_unlock(&prg->prog_mtx);
596: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>