oskit/oskit-20020317/unix/threaded_stdio.c

180 lines
4.1 KiB
C
Executable File

/*
* Copyright (c) 1997-1998, 2000, 2001 University of Utah and the Flux Group.
* All rights reserved.
*
* This file is part of the Flux OSKit. The OSKit is free software, also known
* as "open source;" you can redistribute it and/or modify it under the terms
* of the GNU General Public License (GPL), version 2, as published by the Free
* Software Foundation (FSF). To explore alternate licensing terms, contact
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
*
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
* received a copy of the GPL along with the OSKit; see the file COPYING. If
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
*/
#include <oskit/console.h>
#include <oskit/dev/dev.h>
#include "native.h"
#include "support.h"
extern int threads_initialized; /* from threads/pthread_init.c */
/*
* On normal exit, turn off NBIO/ASYNC mode so that the emacs shell does
* not go nuts.
*/
void
oskitunix_stdio_exit()
{
/*
* Ignore any error on fixing up fd 0. We're already
* exiting at this point.
*/
oskitunix_unset_async_fd(0);
}
/*
* Why is there a SIGINT catcher? Well, interrupting a process with an
* NBIO and/or ASYNC stdin/stdout while running inside an emacs shell
* buffer causes that shell to go nuts. This is almost certainly a feature
* of FreeBSD emacs or the shell, but I'm not inclined to go find out why ...
*/
void
oskitunix_stdio_interrupt()
{
oskitunix_stdio_exit();
_exit(1);
}
/*
* Put stdin in NBIO/ASYNC mode so that console input does not block
* in the kernel. We want to use the threaded_fd stuff, but that uses
* osenv_sleep, which requires that the process lock is taken. Well,
* the stdio functions are not provided as a COM object that can be
* wrapped like other device drivers, so the process lock *might not*
* be taken when we get here. So, take and release the lock as
* necessary so that we can use the already existing threaded_fd
* stuff. What a hack!
*
* stdout is left in blocking mode since printf is called from interrupt
* level all over the place, so we cannot allow a context switch to happen.
*/
void
oskitunix_stdio_init()
{
struct sigaction sa;
sigset_t set;
NATIVEOS(sigemptyset)(&set);
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sa.sa_mask = set;
if (NATIVEOS(sigaction)(SIGIO, &sa, 0) < 0) {
oskitunix_perror("installing SIGIO handler");
exit(0);
}
/*
* Ignore any errors on making fd 0 async. Such errors merely
* indicate that the native OS guarantees that fd 0 will never
* block a read (e.g., its been re-directed from /dev/null).
*/
oskitunix_set_async_fd(0);
oskitunix_set_signal_handler(SIGINT,
(void (*)(int,int,struct sigcontext*))oskitunix_stdio_interrupt);
}
/* Supply console routines normally pulled out of libkern. */
int
console_puts(const char *str)
{
int rc;
int len = strlen(str);
if ((rc = console_putbytes(str, len)) == EOF)
return EOF;
else
return console_putchar('\n');
}
int
console_putchar(int c)
{
unsigned char foo = (unsigned char) c;
return console_putbytes(&foo, 1);
}
int
console_getchar()
{
int rc;
unsigned char foo;
if (! threads_initialized) {
rc = NATIVEOS(read)(0, &foo, 1);
}
else {
int locked = osenv_process_locked();
if (! locked)
osenv_process_lock();
rc = oskitunix_threaded_read(0, &foo, 1);
if (! locked)
osenv_process_unlock();
}
if (rc <= 0)
return EOF;
else
return (int) foo;
}
/*
* Added to improve console output performance.
*/
int
console_putbytes(const char *str, int len)
{
int rc = 0;
int enabled;
enabled = osenv_intr_save_disable();
while (len) {
rc = NATIVEOS(write)(1, str, len);
if (rc < 0) {
if (errno == EAGAIN)
continue;
break;
}
len -= rc;
str += rc;
}
if (enabled)
osenv_intr_enable();
if (rc < 0)
return EOF;
else
return 0;
}
void
base_console_init(int argc, char **argv)
{
console_putbytes("base_console_init called!",
strlen("base_console_init called!"));
}