mirror of
https://github.com/ksherlock/TwoTerm.git
synced 2024-12-31 03:30:53 +00:00
use gcd to read child data and monitor if child is still alive.
git-svn-id: svn://qnap.local/TwoTerm/branches/gcd_dispatch@3105 5590a31f-7b70-45f8-8c82-aa3a8e5f4507
This commit is contained in:
parent
5c4b05a4cc
commit
58499dda23
@ -30,6 +30,12 @@
|
|||||||
|
|
||||||
int _child;
|
int _child;
|
||||||
|
|
||||||
|
int _fd;
|
||||||
|
pid_t _pid;
|
||||||
|
|
||||||
|
dispatch_source_t _read_source;
|
||||||
|
dispatch_source_t _wait_source;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) NSDictionary *parameters;
|
@property (nonatomic, retain) NSDictionary *parameters;
|
||||||
|
@ -70,11 +70,8 @@
|
|||||||
|
|
||||||
-(void)initPTY
|
-(void)initPTY
|
||||||
{
|
{
|
||||||
int pid;
|
|
||||||
int fd;
|
|
||||||
struct termios term;
|
struct termios term;
|
||||||
struct winsize ws = [_emulator defaultSize];
|
struct winsize ws = [_emulator defaultSize];
|
||||||
int flags;
|
|
||||||
|
|
||||||
memset(&term, 0, sizeof(term));
|
memset(&term, 0, sizeof(term));
|
||||||
|
|
||||||
@ -95,16 +92,16 @@
|
|||||||
[_emulator initTerm: &term];
|
[_emulator initTerm: &term];
|
||||||
|
|
||||||
|
|
||||||
pid = forkpty(&fd, NULL, &term, &ws);
|
_pid = forkpty(&_fd, NULL, &term, &ws);
|
||||||
|
|
||||||
if (pid < 0)
|
if (_pid < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "forkpty failed\n");
|
fprintf(stderr, "forkpty failed\n");
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pid == 0)
|
if (_pid == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::vector<const char *> environ;
|
std::vector<const char *> environ;
|
||||||
@ -153,19 +150,16 @@
|
|||||||
// child
|
// child
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// non-blocking io.
|
|
||||||
if (fcntl(fd, F_GETFL, &flags) < 0) flags = 0;
|
|
||||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
|
|
||||||
[_emulatorView resizeTo: iSize(ws.ws_col, ws.ws_row) animated: NO];
|
[_emulatorView resizeTo: iSize(ws.ws_col, ws.ws_row) animated: NO];
|
||||||
|
|
||||||
|
|
||||||
|
NSWindow *window = [self window];
|
||||||
|
|
||||||
if (![_emulator resizable])
|
if (![_emulator resizable])
|
||||||
{
|
{
|
||||||
|
|
||||||
NSWindow *window = [self window];
|
|
||||||
NSUInteger mask = [window styleMask];
|
NSUInteger mask = [window styleMask];
|
||||||
|
|
||||||
|
|
||||||
@ -173,24 +167,108 @@
|
|||||||
|
|
||||||
[window setStyleMask: mask & ~NSResizableWindowMask];
|
[window setStyleMask: mask & ~NSResizableWindowMask];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[window setMinSize: [window frame].size];
|
||||||
|
|
||||||
|
[_emulatorView setFd: _fd];
|
||||||
|
[self monitor];
|
||||||
|
|
||||||
|
/*
|
||||||
if (!_childMonitor)
|
if (!_childMonitor)
|
||||||
{
|
{
|
||||||
_childMonitor = [ChildMonitor new];
|
_childMonitor = [ChildMonitor new];
|
||||||
[_childMonitor setDelegate: _emulatorView];
|
[_childMonitor setDelegate: _emulatorView];
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
[_childMonitor setChildPID: pid];
|
|
||||||
[_childMonitor setFd: fd];
|
|
||||||
|
|
||||||
_child = pid;
|
|
||||||
|
|
||||||
[_emulatorView setFd: fd];
|
|
||||||
//[_emulatorView startBackgroundReader];
|
|
||||||
[_childMonitor start];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)monitor {
|
||||||
|
|
||||||
|
int fd = _fd;
|
||||||
|
int pid = _pid;
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
// non-blocking io.
|
||||||
|
if (fcntl(_fd, F_GETFL, &flags) < 0) flags = 0;
|
||||||
|
fcntl(_fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
|
||||||
|
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||||
|
|
||||||
|
_wait_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC,
|
||||||
|
pid, DISPATCH_PROC_EXIT, queue);
|
||||||
|
if (_wait_source)
|
||||||
|
{
|
||||||
|
|
||||||
|
dispatch_source_set_event_handler(_wait_source, ^{
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
int ok = waitpid(pid, &status, WNOHANG);
|
||||||
|
|
||||||
|
_pid = 0;
|
||||||
|
//dispatch_async(dispatch_get_main_queue(), ^(){
|
||||||
|
[_emulatorView childFinished: status];
|
||||||
|
//});
|
||||||
|
|
||||||
|
dispatch_source_cancel(_wait_source);
|
||||||
|
dispatch_release(_wait_source);
|
||||||
|
_wait_source = nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch_resume(_wait_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_read_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
|
||||||
|
fd, 0, queue);
|
||||||
|
if (_read_source)
|
||||||
|
{
|
||||||
|
// Install the event handler
|
||||||
|
dispatch_source_set_event_handler(_read_source, ^{
|
||||||
|
|
||||||
|
static uint8_t sbuffer[1024];
|
||||||
|
size_t estimated = dispatch_source_get_data(_read_source) + 1;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t *buffer = estimated > sizeof(sbuffer) ? (uint8_t *)malloc(estimated) : sbuffer;
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
ssize_t actual;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
actual = read(fd, buffer, (estimated));
|
||||||
|
if (actual < 0) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN) return;
|
||||||
|
NSLog(@"read: %s", strerror(errno));
|
||||||
|
dispatch_source_cancel(_read_source);
|
||||||
|
dispatch_release(_read_source);
|
||||||
|
_read_source = nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actual > 0) [_emulatorView processData: buffer size: actual];
|
||||||
|
|
||||||
|
if (buffer != sbuffer) free(buffer);
|
||||||
|
|
||||||
|
if (actual == 0 && _pid == 0) {
|
||||||
|
dispatch_source_cancel(_read_source);
|
||||||
|
dispatch_release(_read_source);
|
||||||
|
_read_source = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
dispatch_source_set_cancel_handler(_read_source, ^{
|
||||||
|
_fd = -1;
|
||||||
|
[_emulatorView setFd: -1];
|
||||||
|
close(fd);
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch_resume(_read_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark NSWindowDelegate
|
#pragma mark NSWindowDelegate
|
||||||
@ -305,15 +383,26 @@
|
|||||||
|
|
||||||
[self initPTY];
|
[self initPTY];
|
||||||
|
|
||||||
[window setMinSize: [window frame].size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)windowWillClose:(NSNotification *)notification
|
-(void)windowWillClose:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
[_childMonitor setDelegate: nil];
|
if (_wait_source) {
|
||||||
[_childMonitor cancel];
|
dispatch_source_cancel(_wait_source);
|
||||||
|
dispatch_release(_wait_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_read_source) {
|
||||||
|
dispatch_source_cancel(_read_source);
|
||||||
|
dispatch_release(_read_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pid) kill(_pid, 9);
|
||||||
|
|
||||||
[self autorelease];
|
[self autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, assign) BOOL scanLines;
|
@property (nonatomic, assign) BOOL scanLines;
|
||||||
@property (nonatomic, assign) int fd;
|
@property (atomic, assign) int fd;
|
||||||
@property (nonatomic, assign) unsigned cursorType;
|
@property (nonatomic, assign) unsigned cursorType;
|
||||||
|
|
||||||
@property (nonatomic, retain) NSColor *foregroundColor;
|
@property (nonatomic, retain) NSColor *foregroundColor;
|
||||||
@ -103,12 +103,11 @@ private:
|
|||||||
-(IBAction)copy: (id)sender;
|
-(IBAction)copy: (id)sender;
|
||||||
|
|
||||||
|
|
||||||
|
-(void)processData: (const uint8_t *)data size: (size_t)size;
|
||||||
|
-(void)childFinished: (int)status;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@interface EmulatorView (ChildMonitor) <ChildMonitorDelegate>
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@interface EmulatorView (Cursor)
|
@interface EmulatorView (Cursor)
|
||||||
|
@ -448,10 +448,12 @@
|
|||||||
-(void)keyDown:(NSEvent *)theEvent
|
-(void)keyDown:(NSEvent *)theEvent
|
||||||
{
|
{
|
||||||
//NSLog(@"keyDown:");
|
//NSLog(@"keyDown:");
|
||||||
|
if (_fd < 0) return;
|
||||||
|
|
||||||
OutputChannel channel(_fd);
|
OutputChannel channel(_fd);
|
||||||
iRect updateRect; // should be nil but whatever...
|
iRect updateRect; // should be nil but whatever...
|
||||||
|
|
||||||
|
// todo -- after _fd closes, need to block further activity.
|
||||||
|
|
||||||
|
|
||||||
[NSCursor setHiddenUntilMouseMoves: YES];
|
[NSCursor setHiddenUntilMouseMoves: YES];
|
||||||
@ -484,8 +486,76 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(void)childFinished:(int)status {
|
||||||
|
|
||||||
|
// called from other thread.
|
||||||
|
|
||||||
|
NSLog(@"[process complete]");
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^(){
|
||||||
|
|
||||||
|
iRect updateRect;
|
||||||
|
|
||||||
|
[self setCursorType: Screen::CursorTypeNone];
|
||||||
|
//[self stopCursorTimer];
|
||||||
|
//_screen.setCursorType(Screen::CursorTypeNone);
|
||||||
|
|
||||||
|
_screen.beginUpdate();
|
||||||
|
|
||||||
|
_screen.setX(0);
|
||||||
|
_screen.incrementY();
|
||||||
|
|
||||||
|
for (const char *cp = "[Process completed]"; *cp; ++cp)
|
||||||
|
{
|
||||||
|
_screen.putc(*cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateRect = _screen.endUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
[self invalidateIRect: updateRect];
|
||||||
|
|
||||||
|
//[_emulator writeLine: @"[Process completed]"];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)processData:(const uint8_t *)buffer size:(size_t)size {
|
||||||
|
|
||||||
|
typedef void (*ProcessCharFX)(id, SEL, uint8_t, Screen *, OutputChannel *);
|
||||||
|
|
||||||
|
ProcessCharFX fx;
|
||||||
|
SEL cmd;
|
||||||
|
OutputChannel channel(_fd);
|
||||||
|
iRect updateRect;
|
||||||
|
|
||||||
|
cmd = @selector(processCharacter: screen: output:);
|
||||||
|
fx = (ProcessCharFX)[_emulator methodForSelector: cmd];
|
||||||
|
|
||||||
|
NSAutoreleasePool *pool;
|
||||||
|
pool = [NSAutoreleasePool new];
|
||||||
|
_screen.beginUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
fx(_emulator,cmd, buffer[i], &_screen, &channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRect = _screen.endUpdate();
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^(){
|
||||||
|
|
||||||
|
[self invalidateIRect: updateRect];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
-(void)dataAvailable
|
-(void)dataAvailable
|
||||||
@ -794,6 +864,7 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
@implementation EmulatorView (ChildMonitor)
|
@implementation EmulatorView (ChildMonitor)
|
||||||
|
|
||||||
-(void)childDataAvailable: (ChildMonitor *)monitor
|
-(void)childDataAvailable: (ChildMonitor *)monitor
|
||||||
@ -841,7 +912,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void ViewScreen::setSize(unsigned width, unsigned height)
|
void ViewScreen::setSize(unsigned width, unsigned height)
|
||||||
|
Loading…
Reference in New Issue
Block a user