22
22
Boston, MA 02111 USA.
24
24
<title>NSTask class reference</title>
25
$Date: 2008-11-17 13:45:32 +0000 (Mon, 17 Nov 2008) $ $Revision: 27080 $
25
$Date: 2010-04-23 10:05:55 -0600 (Fri, 23 Apr 2010) $ $Revision: 30224 $
29
#include "GNUstepBase/preface.h"
30
#include "Foundation/NSObject.h"
31
#include "Foundation/NSAutoreleasePool.h"
32
#include "Foundation/NSBundle.h"
33
#include "Foundation/NSCharacterSet.h"
34
#include "Foundation/NSData.h"
35
#include "Foundation/NSDate.h"
36
#include "Foundation/NSEnumerator.h"
37
#include "Foundation/NSString.h"
38
#include "Foundation/NSException.h"
39
#include "Foundation/NSFileHandle.h"
40
#include "Foundation/NSFileManager.h"
41
#include "Foundation/NSMapTable.h"
42
#include "Foundation/NSProcessInfo.h"
43
#include "Foundation/NSRunLoop.h"
44
#include "Foundation/NSNotification.h"
45
#include "Foundation/NSNotificationQueue.h"
46
#include "Foundation/NSTask.h"
47
#include "Foundation/NSTimer.h"
48
#include "Foundation/NSLock.h"
49
#include "Foundation/NSDebug.h"
50
#include "GSPrivate.h"
29
#define EXPOSE_NSTask_IVARS 1
30
#import "Foundation/NSAutoreleasePool.h"
31
#import "Foundation/NSBundle.h"
32
#import "Foundation/NSCharacterSet.h"
33
#import "Foundation/NSData.h"
34
#import "Foundation/NSDate.h"
35
#import "Foundation/NSEnumerator.h"
36
#import "Foundation/NSException.h"
37
#import "Foundation/NSFileHandle.h"
38
#import "Foundation/NSFileManager.h"
39
#import "Foundation/NSMapTable.h"
40
#import "Foundation/NSProcessInfo.h"
41
#import "Foundation/NSRunLoop.h"
42
#import "Foundation/NSNotification.h"
43
#import "Foundation/NSNotificationQueue.h"
44
#import "Foundation/NSTask.h"
45
#import "Foundation/NSTimer.h"
46
#import "Foundation/NSLock.h"
47
#import "GNUstepBase/NSString+GNUstepBase.h"
48
#import "GNUstepBase/NSObject+GNUstepBase.h"
52
51
#include <string.h>
53
52
#ifdef HAVE_UNISTD_H
1163
1168
start_info.dwFlags |= STARTF_USESTDHANDLES;
1165
1170
toClose = [NSMutableArray arrayWithCapacity: 3];
1166
hdl = [self standardInput];
1167
if ([hdl isKindOfClass: [NSPipe class]])
1169
hdl = [(NSPipe*)hdl fileHandleForReading];
1170
[toClose addObject: hdl];
1172
start_info.hStdInput = [hdl nativeHandle];
1174
hdl = [self standardOutput];
1175
if ([hdl isKindOfClass: [NSPipe class]])
1177
hdl = [(NSPipe*)hdl fileHandleForWriting];
1178
[toClose addObject: hdl];
1180
start_info.hStdOutput = [hdl nativeHandle];
1182
hdl = [self standardError];
1183
if ([hdl isKindOfClass: [NSPipe class]])
1185
hdl = [(NSPipe*)hdl fileHandleForWriting];
1187
* If we have the same pipe twice we don't want to close it twice
1189
if ([toClose indexOfObjectIdenticalTo: hdl] == NSNotFound)
1191
[toClose addObject: hdl];
1194
start_info.hStdError = [hdl nativeHandle];
1172
if (_standardInput == nil)
1174
start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1178
hdl = [self standardInput];
1179
if ([hdl isKindOfClass: [NSPipe class]])
1181
hdl = [(NSPipe*)hdl fileHandleForReading];
1182
[toClose addObject: hdl];
1184
start_info.hStdInput = [hdl nativeHandle];
1186
hIn = start_info.hStdInput;
1188
if (_standardOutput == nil)
1190
start_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1194
hdl = [self standardOutput];
1195
if ([hdl isKindOfClass: [NSPipe class]])
1197
hdl = [(NSPipe*)hdl fileHandleForWriting];
1198
[toClose addObject: hdl];
1200
start_info.hStdOutput = [hdl nativeHandle];
1202
hOut = start_info.hStdOutput;
1204
if (_standardError == nil)
1206
start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1210
hdl = [self standardError];
1211
if ([hdl isKindOfClass: [NSPipe class]])
1213
hdl = [(NSPipe*)hdl fileHandleForWriting];
1215
* If we have the same pipe twice we don't want to close it twice
1217
if ([toClose indexOfObjectIdenticalTo: hdl] == NSNotFound)
1219
[toClose addObject: hdl];
1222
start_info.hStdError = [hdl nativeHandle];
1224
hErr = start_info.hStdError;
1226
/* Tell the system not to show a window for the subtask.
1228
start_info.wShowWindow = SW_HIDE;
1229
start_info.dwFlags |= STARTF_USESHOWWINDOW;
1231
/* Make the handles inheritable only temporarily while launching the
1232
* child task. This section must be lock protected so we don't have
1233
* another thread trying to launch at the same time and get handles
1234
* inherited by the wrong threads.
1237
SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
1238
SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
1239
SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
1196
1241
result = CreateProcessW(wexecutable,
1198
1243
NULL, /* proc attrs */
1199
1244
NULL, /* thread attrs */
1200
1245
1, /* inherit handles */
1201
// CREATE_NO_WINDOW|DETACHED_PROCESS|CREATE_UNICODE_ENVIRONMENT,
1202
CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT,
1248
/* One would have thought the the CREATE_NO_WINDOW flag should be used,
1249
* but apparently this breaks for old 16bit applications/tools on XP.
1250
* So maybe we want to leave it out?
1252
// |DETACHED_PROCESS
1253
/* We don't set the DETACHED_PROCESS flag as it actually means that the
1254
* child task should get a new Console allocated ... and that means it
1255
* will pop up a console window ... which looks really bad.
1257
|CREATE_UNICODE_ENVIRONMENT,
1203
1258
envp, /* env block */
1204
1259
(const unichar*)[[self currentDirectoryPath] fileSystemRepresentation],
1264
last = [NSError _last];
1207
1266
NSZoneFree(NSDefaultMallocZone(), w_args);
1267
SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, 0);
1268
SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, 0);
1269
SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, 0);
1208
1272
if (result == 0)
1210
NSLog(@"Error launching task: %@", lpath);
1274
NSLog(@"Error launching task: %@ ... %@", lpath, last);
1274
1341
result = waitpid(-1, &status, WNOHANG);
1280
t = (NSTask*)NSMapGet(activeTasks, (void*)(intptr_t)result);
1281
AUTORELEASE(RETAIN(t));
1344
#if defined(WAITDEBUG)
1346
t = (NSTask*)NSMapGet(activeTasks, (void*)(intptr_t)result);
1350
NSLog(@"waitpid result %d, error %@",
1351
result, [NSError _last]);
1355
else if (result > 0)
1358
t = (NSTask*)NSMapGet(activeTasks, (void*)(intptr_t)result);
1359
IF_NO_GC(AUTORELEASE(RETAIN(t));)
1282
1360
[tasksLock unlock];
1285
1363
if (WIFEXITED(status))
1365
#if defined(WAITDEBUG)
1366
NSLog(@"waitpid %d, exit status = %d",
1287
1369
[t _terminatedChild: WEXITSTATUS(status)];
1290
1372
else if (WIFSIGNALED(status))
1374
#if defined(WAITDEBUG)
1375
NSLog(@"waitpid %d, termination status = %d",
1292
1378
[t _terminatedChild: WTERMSIG(status)];
1406
* Make sure the task gets default signal setup.
1497
/* Make sure the task gets default signal setup.
1408
1499
for (i = 0; i < 32; i++)
1410
1501
signal(i, SIG_DFL);
1414
* Make sure task is run in it's own process group.
1504
/* Make sure task is session leader in it's own process group
1505
* and with no controlling terminal.
1506
* This allows us to use killpg() to put the task to sleep etc,
1507
* and have the signal effect forked children of the subtask.
1509
#if defined(HAVE_SETSID)
1512
#if defined(HAVE_SETPGRP)
1513
#if defined(SETPGRP_VOID)
1420
1516
setpgrp(getpid(), getpid());
1423
#if defined(__MINGW32__)
1519
#if defined(HAVE_SETPGID)
1520
#if defined(__MINGW__)
1424
1521
pid = (int)GetCurrentProcessId(),
1426
1523
pid = (int)getpid();
1429
1525
setpgid(pid, pid);
1526
#endif /* HAVE_SETPGID */
1527
#endif /* HAVE_SETPGRP */
1528
/* Detach from controlling terminal.
1530
#if defined(TIOCNOTTY)
1531
i = open("/dev/tty", O_RDWR);
1534
(void)ioctl(i, TIOCNOTTY, 0);
1537
#endif /* TIOCNOTTY */
1538
#endif /* HAVE_SETSID */
1433
1540
if (_usePseudoTerminal == YES)
1557
1651
- (void) _collectChild
1559
if (_hasCollected == NO)
1564
result = waitpid(_taskId, &_terminationStatus, WNOHANG);
1567
NSLog(@"waitpid %d, result %d, error %@",
1568
_taskId, result, [NSError _last]);
1569
[self _terminatedChild: -1];
1571
else if (result == _taskId || (result > 0 && errno == 0))
1573
if (WIFEXITED(_terminationStatus))
1576
NSLog(@"waitpid %d, termination status = %d",
1577
_taskId, _terminationStatus);
1579
[self _terminatedChild: WEXITSTATUS(_terminationStatus)];
1581
else if (WIFSIGNALED(_terminationStatus))
1584
NSLog(@"waitpid %d, termination status = %d",
1585
_taskId, _terminationStatus);
1587
[self _terminatedChild: WTERMSIG(_terminationStatus)];
1592
NSLog(@"waitpid %d, event status = %d",
1593
_taskId, _terminationStatus);
1600
NSLog(@"waitpid %d, result %d, error %@",
1601
_taskId, result, [NSError _last]);
1653
GSPrivateCheckTasks();
1607
1656
- (BOOL) usePseudoTerminal