Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/execunix.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 6.5 KB
Line 
1/*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7# include "jam.h"
8# include "lists.h"
9# include "execcmd.h"
10# include <errno.h>
11# include <time.h>
12# include <unistd.h> /* needed for vfork(), _exit() prototypes */
13
14#if defined(sun) || defined(__sun) || defined(linux)
15#include <wait.h>
16#endif
17
18# ifdef USE_EXECUNIX
19# include <sys/times.h>
20
21# ifdef NO_VFORK
22# define vfork() fork()
23# endif
24
25/*
26 * execunix.c - execute a shell script on UNIX/WinNT/OS2/AmigaOS
27 *
28 * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
29 * The default is:
30 *
31 *      /bin/sh -c %            [ on UNIX/AmigaOS ]
32 *      cmd.exe /c %            [ on OS2/WinNT ]
33 *
34 * Each word must be an individual element in a jam variable value.
35 *
36 * In $(JAMSHELL), % expands to the command string and ! expands to
37 * the slot number (starting at 1) for multiprocess (-j) invocations.
38 * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
39 * argument.
40 *
41 * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
42 *
43 * External routines:
44 *      execcmd() - launch an async command execution
45 *      execwait() - wait and drive at most one execution completion
46 *
47 * Internal routines:
48 *      onintr() - bump intr to note command interruption
49 *
50 * 04/08/94 (seiwald) - Coherent/386 support added.
51 * 05/04/94 (seiwald) - async multiprocess interface
52 * 01/22/95 (seiwald) - $(JAMSHELL) support
53 * 06/02/97 (gsar)    - full async multiprocess support for Win32
54 */
55
56static int intr = 0;
57static int cmdsrunning = 0;
58static void (*istat)( int );
59
60static struct
61{
62        int     pid; /* on win32, a real process handle */
63        void    (*func)( void *closure, int status, timing_info* );
64        void    *closure;
65} cmdtab[ MAXJOBS ] = {{0}};
66
67/*
68 * onintr() - bump intr to note command interruption
69 */
70
71void
72onintr( int disp )
73{
74        intr++;
75        printf( "...interrupted\n" );
76}
77
78/*
79 * execcmd() - launch an async command execution
80 */
81
82void
83execcmd( 
84        char *string,
85        void (*func)( void *closure, int status, timing_info* ),
86        void *closure,
87        LIST *shell )
88{
89        int pid;
90        int slot;
91        char *argv[ MAXARGC + 1 ];      /* +1 for NULL */
92
93        /* Find a slot in the running commands table for this one. */
94
95        for( slot = 0; slot < MAXJOBS; slot++ )
96            if( !cmdtab[ slot ].pid )
97                break;
98
99        if( slot == MAXJOBS )
100        {
101            printf( "no slots for child!\n" );
102            exit( EXITBAD );
103        }
104
105
106        /* Forumulate argv */
107        /* If shell was defined, be prepared for % and ! subs. */
108        /* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
109
110        if( shell )
111        {
112            int i;
113            char jobno[4];
114            int gotpercent = 0;
115
116            sprintf( jobno, "%d", slot + 1 );
117
118            for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
119            {
120                switch( shell->string[0] )
121                {
122                case '%':       argv[i] = string; gotpercent++; break;
123                case '!':       argv[i] = jobno; break;
124                default:        argv[i] = shell->string;
125                }
126                if( DEBUG_EXECCMD )
127                    printf( "argv[%d] = '%s'\n", i, argv[i] );
128            }
129
130            if( !gotpercent )
131                argv[i++] = string;
132
133            argv[i] = 0;
134        }
135        else
136        {
137            argv[0] = "/bin/sh";
138            argv[1] = "-c";
139            argv[2] = string;
140            argv[3] = 0;
141        }
142
143        /* Catch interrupts whenever commands are running. */
144
145        if( !cmdsrunning++ )
146            istat = signal( SIGINT, onintr );
147
148        /* Start the command */
149
150        if ((pid = vfork()) == 0) 
151        {
152                execvp( argv[0], argv );
153                _exit(127);
154        }
155
156        if( pid == -1 )
157        {
158            perror( "vfork" );
159            exit( EXITBAD );
160        }
161
162        /* Save the operation for execwait() to find. */
163
164        cmdtab[ slot ].pid = pid;
165        cmdtab[ slot ].func = func;
166        cmdtab[ slot ].closure = closure;
167
168        /* Wait until we're under the limit of concurrent commands. */
169        /* Don't trust globs.jobs alone. */
170
171        while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
172            if( !execwait() )
173                break;
174}
175
176/*
177 * execwait() - wait and drive at most one execution completion
178 */
179
180int
181execwait()
182{
183        int i;
184        int status, w;
185        int rstat;
186    timing_info time;
187    struct tms old_time, new_time;
188   
189        /* Handle naive make1() which doesn't know if cmds are running. */
190
191        if( !cmdsrunning )
192            return 0;
193
194    times(&old_time);
195   
196        /* Pick up process pid and status */
197        while( ( w = wait( &status ) ) == -1 && errno == EINTR )
198                ;
199
200        if( w == -1 )
201        {
202            printf( "child process(es) lost!\n" );
203            perror("wait");
204            exit( EXITBAD );
205        }
206
207    times(&new_time);
208
209    time.system = (double)(new_time.tms_cstime - old_time.tms_cstime) / CLOCKS_PER_SEC;
210    time.user = (double)(new_time.tms_cutime - old_time.tms_cutime) / CLOCKS_PER_SEC;
211   
212        /* Find the process in the cmdtab. */
213
214        for( i = 0; i < MAXJOBS; i++ )
215            if( w == cmdtab[ i ].pid )
216                break;
217
218        if( i == MAXJOBS )
219        {
220            printf( "waif child found!\n" );
221            exit( EXITBAD );
222        }
223
224   
225        /* Drive the completion */
226
227        if( !--cmdsrunning )
228            signal( SIGINT, istat );
229
230        if( intr )
231            rstat = EXEC_CMD_INTR;
232        else if( w == -1 || status != 0 )
233            rstat = EXEC_CMD_FAIL;
234        else
235            rstat = EXEC_CMD_OK;
236
237        cmdtab[ i ].pid = 0;
238
239        (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time );
240
241        return 1;
242}
243
244# if defined( OS_NT ) && !defined( __BORLANDC__ )
245
246# define WIN32_LEAN_AND_MEAN
247
248# include <windows.h>           /* do the ugly deed */
249
250static int
251my_wait( int *status )
252{
253        int i, num_active = 0;
254        DWORD exitcode, waitcode;
255        static HANDLE *active_handles = 0;
256
257        if (!active_handles)
258    {
259            active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
260        if ( DEBUG_PROFILE )
261            profile_memory( globs.jobs * sizeof(HANDLE) );
262    }
263
264        /* first see if any non-waited-for processes are dead,
265         * and return if so.
266         */
267        for ( i = 0; i < globs.jobs; i++ ) {
268            if ( cmdtab[i].pid ) {
269                if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
270                    if ( exitcode == STILL_ACTIVE )
271                        active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
272                    else {
273                        CloseHandle((HANDLE)cmdtab[i].pid);
274                        *status = (int)((exitcode & 0xff) << 8);
275                        return cmdtab[i].pid;
276                    }
277                }
278                else
279                    goto FAILED;
280            }
281        }
282
283        /* if a child exists, wait for it to die */
284        if ( !num_active ) {
285            errno = ECHILD;
286            return -1;
287        }
288        waitcode = WaitForMultipleObjects( num_active,
289                                           active_handles,
290                                           FALSE,
291                                           INFINITE );
292        if ( waitcode != WAIT_FAILED ) {
293            if ( waitcode >= WAIT_ABANDONED_0
294                && waitcode < WAIT_ABANDONED_0 + num_active )
295                i = waitcode - WAIT_ABANDONED_0;
296            else
297                i = waitcode - WAIT_OBJECT_0;
298            if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
299                CloseHandle(active_handles[i]);
300                *status = (int)((exitcode & 0xff) << 8);
301                return (int)active_handles[i];
302            }
303        }
304
305FAILED:
306        errno = GetLastError();
307        return -1;
308   
309}
310
311# endif /* NT && !__BORLANDC__ */
312
313# endif /* USE_EXECUNIX */
Note: See TracBrowser for help on using the repository browser.