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