flagday-chardev WIP, jenkins testing only, #2
Squashed commit of the following:
commit 57ad74f37cf5f4cfe9196478d726ac8492333ddc
Author: David van Moolenbroek <david@minix3.org>
Date: Sat Aug 31 16:13:37 2013 +0200
tests: add test77 for opening/closing PTYs
Change-Id: I30e3418f75137aa08037fa6581ff3d4cce32a114
commit 6b685b18cfbadf04a5c072a1be5e523a3603624f
Author: David van Moolenbroek <david@minix3.org>
Date: Sat Aug 31 16:08:25 2013 +0200
TTY: fix for PTY open/close logic
Opening and closing the master side of a pseudo terminal without
opening the slave side would result in the pseudo terminal becoming
permanently unavailable. In addition, reopening the slave side
would be possible but not allow for I/O. Finally, attempting to
open an in-use master would wipe its I/O state. These issues have
been resolved.
Change-Id: I9235e3d9aba321803f9280b86b6b5e3646ad5ef3
commit 124e23e33a0242d34f53dbe1763c7e7e12c3b609
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 18:48:56 2013 +0200
tests: remove select subdirectory
This test set has been obsoleted by test40.
Change-Id: I55439152824906778ad07d409dfb327ac10bea70
commit 78759bbb817772deafb57f2d19d4bf622f49674e
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 18:43:23 2013 +0200
tests: add test76 for interrupting VFS operations
Change-Id: Ic436cac61de8c42e0c7ee2d442c647528654cde9
commit 3b1a7b0b2e8a69e04d1fbfe94931f8fa19f5f590
Author: David van Moolenbroek <david@minix3.org>
Date: Wed Aug 28 13:08:16 2013 +0200
VFS: fix interruption of blocking pipe operations
POSIX states that when interrupted, partially successful pipe
operations should return the partial result rather than EINTR. VFS
previously wouldn't look at the partial result, and not clear it
either, which would result in a panic upon the next pipe operation.
Change-Id: Ia1eb72b4b77394051444e63a1390d49bb315eb04
commit 2f24105efbcf9d9ae19befea22d6d07cd26315ba
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 00:57:16 2013 +0200
libmthread: do not dump stack for free threads
Change-Id: Ic438a252f5bddaf1513f554c71173e6fffb0c674
commit 4a1b503d6223554274d8357559ffe5eaaa53d266
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 14:00:50 2013 +0200
VFS: worker thread model overhaul
The main purpose of this patch is to fix handling of unpause calls
from PM while another call is ongoing. The solution to this problem
sparked a full revision of the threading model, consisting of a large
number of related changes:
- all active worker threads are now always associated with a process,
and every process has at most one active thread working for it;
- the process lock is always held by a process's worker thread;
- a process can now have both normal work and postponed PM work
associated to it;
- timer expiry and non-postponed PM work is done from the main thread;
- filp garbage collection is done from a thread associated with VFS;
- reboot calls from PM are now done from a thread associated with PM;
- the DS events handler is protected from starting multiple threads;
- support for a system worker thread has been removed;
- the deadlock recovery thread has been replaced by a parameter to the
worker_start() function; the number of worker threads has
consequently been increased by one;
- saving and restoring of global but per-thread variables is now
centralized in worker_suspend() and worker_resume(); err_code is now
saved and restored in all cases;
- the concept of jobs has been removed, and job_m_in now points to a
message stored in the worker thread structure instead;
- the PM lock has been removed;
- the separate exec lock has been replaced by a lock on the VM
process, which was already being locked for exec calls anyway;
- PM_UNPAUSE is now processed as a postponed PM request, from a thread
associated with the target process;
- the FP_DROP_WORK flag has been removed, since it is no longer more
than just an optimization and only applied to processes operating on
a pipe when getting killed;
- assignment to "fp" now takes place only when obtaining new work in
the main thread or a worker thread, when resuming execution of a
thread, and in the special case of exiting processes during reboot;
- there are no longer special cases where the yield() call is used to
force a thread to run.
Change-Id: I7a97b9b95c2450454a9b5318dfa0e6150d4e6858
commit 41bdfef9ff26f6ef4e597409d9289e0c607ac597
Author: David van Moolenbroek <david@minix3.org>
Date: Wed Aug 28 15:58:30 2013 +0200
Retire ptrace(T_DUMPCORE), dumpcore(1), gcore(1)
The T_DUMPCORE implementation was not only broken - it would currently
produce a coredump of the tracer process rather than the traced
process - but also deeply flawed, and fixing it would require serious
alteration of PM's internal state machine. It should be possible to
implement the same functionality in userland, and that is now the
suggested way forward. For now, also remove the (identical) utilities
using T_DUMPCORE: dumpcore(1) and gcore(1).
Change-Id: I1d51be19c739362b8a5833de949b76382a1edbcc
commit a4d9359e197b08076cf7f9105ca3079645cf3f08
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 13:42:51 2013 +0200
VFS: process char driver replies from main thread
Previously, processing of some replies coming from character drivers
could block on locks, and therefore, such processing was done from
threads that were associated to the character driver process. The
hidden consequence of this was that if all threads were in use, VFS
could drop replies coming from the driver. This patch returns VFS to
a situation where the replies from character drivers are processed
instantly from the main thread, by removing the situations that may
cause VFS to block while handling those replies.
- change the locking model for select, so that it will never block
on any processing that happens after the select call has been set
up, in particular processing of character driver select replies;
- clearly mark all select routines that may never block;
- protect against race conditions in do_select as result of the
locking that still does happen there (as is required for pipes);
- also handle select timers from the main thread;
- move processing of character driver replies into device.c.
Change-Id: I4dc8e69f265cbd178de0fbf321d35f58f067cc57
commit f37ea0aa87eccbda3ea3afb981fe9b6a7fdfcfb1
Author: David van Moolenbroek <david@minix3.org>
Date: Sun Aug 25 00:26:38 2013 +0200
VFS: properly cancel select queries on unpause
Change-Id: I16e71db3f5c1bcc7ba6045bc9f02b13d71dc31eb
commit adc1f49617a5f8b55dd4d8f99826b0023a428adb
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 13:33:56 2013 +0200
VFS: remove support for sync char driver protocol
Change-Id: I57cc870a053b813b3a3fc45da46606ea84fe4cb1
commit b0ed817443fc7bace794e624db17dfe1009639a6
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 13:00:44 2013 +0200
VFS: remove FP_BLOCKED_ON_DOPEN
These days, DEV_OPEN calls to character drivers block the calling
thread until completion or failure, and thus never return SUSPEND to
the caller. The same already applied to BDEV_OPEN calls to block
drivers. It has thus become impossible for a process to enter a state
of being blocked on a device open call.
There is currently no support for restarting device open calls to
restarted character drivers. This support was present in the _DOPEN
logic, but was already no longer triggering. In the future, this case
should be handled by the thread performing the open request.
Change-Id: I6cc1e7b4c9ed116c6ce160b315e6e060124dce00
commit 6a4f163effde86b12c9ed33ee75ac242d2b93d49
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 12:18:27 2013 +0200
PFS: remember request information for IOCTLs
Not doing so caused PFS to commit protocol violations by relying on
stale information when sending replies. This stale information always
happened to be correct, which is why the problem went unnoticed.
Change-Id: Ia42ca670718d6e731193cd2c34a3ff455f8a94d3
commit 670d1b653c6ec193b46128e43e46f5c3d3e7c075
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 11:14:03 2013 +0200
Retire the synchronous character driver protocol
- change all sync char drivers into async drivers;
- retire support for the sync protocol in libchardev;
- remove async dev style, as this is now the default;
- remove dev_status from VFS;
- clean up now-unused protocol messages.
Change-Id: I6aacff712292f6b29f2ccd51bc1e7d7003723e87
commit 98df6d244aa20c1df8bb92238b604c36433a86d8
Author: David van Moolenbroek <david@minix3.org>
Date: Fri Aug 30 10:48:34 2013 +0200
Sync char protocol: add nonblocking transfer flag
The async char protocol already has this, so this patch closes the
gap between the two protocols a bit. Support for this flag has been
added to all sync char drivers that support CANCEL at all.
The LOG driver was already using the asynchronous protocol, but it
did not support the nonblocking transfer flag. This has been fixed
as well.
Change-Id: Ia55432c9f102765b59ad3feb45a8bd47a782c93f
commit 76faed46459809e7a3b880968777044c1abb7a92
Author: David van Moolenbroek <david@minix3.org>
Date: Sat Aug 24 12:29:39 2013 +0200
VFS: set w_drv_sendrec only when needed
As with w_task, this ensures that the field remains cleared if it is
not used. Without this, worker_stop could mistakenly identify a thread
as talking to a device driver rather than a (crashed) file server.
Change-Id: I7d3ebed3efc3cd4f5c891f61c67a6463109b6376
commit c4863009b5171164f5d8124002f91d5536ca400e
Author: Thomas Veerman <thomas@minix3.org>
Date: Sat Aug 24 12:23:41 2013 +0200
VFS: set w_task only when needed
It was always set, but not always cleared, when talking to asynchronous
drivers. This could cause erratic behavior upon a driver crash.
Normally, a worker thread's w_task field is set when it's about to
communicate with a driver or FS. Then upon receiving a reply we can
do sanity checks (that the thread we want to wake up was actually
waiting for a reply). Also, when a driver/FS crashes, we can identify
which worker threads were talking to the crashed endpoint and handle
the error gracefully.
Asynchronous drivers are a bit special, though. In most cases, the
sender of the request is not interested in the reply (the sender was
suspended and only wants to know whether the request was successfully
caried out or not). However, the open request is special, as the reply
carries information needed by the sender. This is the only request
where a worker thread actually yields and waits for the result. This is
also the only case where we're interested in setting w_task for
asynchronous drivers.
Change-Id: Ia1ce2747937df376122b5e13b6a069de27fcc379
Change-Id: I7c9cab02ac73e4eaef1ed9fb4ce7b060911df02a
This commit is contained in:
parent
4593804bf0
commit
3c9855d318
|
|
@ -7,10 +7,10 @@ SUBDIR= add_route arp ash at backup btrace \
|
|||
chmod chown ci cleantmp cmp co \
|
||||
comm compress cp crc cron crontab cut \
|
||||
dd decomp16 DESCRIBE devmand devsize df dhcpd \
|
||||
dhrystone diff diskctl dumpcore \
|
||||
dhrystone diff diskctl \
|
||||
eject env factor fbdctl \
|
||||
find fix fold format fortune fsck.mfs \
|
||||
gcore gcov-pull getty grep hexdump host \
|
||||
gcov-pull getty grep hexdump host \
|
||||
hostaddr id ifconfig ifdef \
|
||||
intr ipcrm ipcs irdpd isoread last \
|
||||
less loadkeys loadramdisk logger look lp \
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
PROG= dumpcore
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/* dumpcore - create core file of running process */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/ipc.h>
|
||||
#include <minix/const.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <timers.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <machine/archtypes.h>
|
||||
#include "kernel/proc.h"
|
||||
|
||||
#define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long))
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
int r, status;
|
||||
|
||||
if(argc != 2) {
|
||||
printf("usage: %s <pid>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = atoi(argv[1]);
|
||||
|
||||
if (ptrace(T_ATTACH, pid, 0, 0) != 0) {
|
||||
perror("ptrace(T_ATTACH)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
perror("waitpid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
|
||||
/* whatever happens here is fine */
|
||||
ptrace(T_RESUME, pid, 0, WSTOPSIG(status));
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
perror("waitpid");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
fprintf(stderr, "process died while attaching\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ptrace(T_DUMPCORE, pid, 0, 0) != 0) {
|
||||
fprintf(stderr, "warning, dumpcore failed (%s)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
if (ptrace(T_DETACH, pid, 0, 0)) {
|
||||
fprintf(stderr, "warning, detaching failed (%s)\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
PROG= gcore
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* gcore - create core file of running process */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
if(argc != 2) {
|
||||
printf("usage: %s <pid>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = atoi(argv[1]);
|
||||
|
||||
if (ptrace(T_ATTACH, pid, 0, 0) != 0) {
|
||||
perror("ptrace(T_ATTACH)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
perror("waitpid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
|
||||
/* whatever happens here is fine */
|
||||
ptrace(T_RESUME, pid, 0, WSTOPSIG(status));
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid) {
|
||||
perror("waitpid");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WIFSTOPPED(status)) {
|
||||
fprintf(stderr, "process died while attaching\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ptrace(T_DUMPCORE, pid, 0, 0)) {
|
||||
fprintf(stderr, "warning, dumpcore failed (%s)\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (ptrace(T_DETACH, pid, 0, 0)) {
|
||||
fprintf(stderr, "warning, detaching failed (%s)\n", strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -203,7 +203,6 @@ static char *prrecv(struct pstat *ps)
|
|||
case FSTATE_LOCK: blkstr = "flock"; break;
|
||||
case FSTATE_POPEN: blkstr = "popen"; break;
|
||||
case FSTATE_SELECT: blkstr = "select"; break;
|
||||
case FSTATE_DOPEN: blkstr = "dopen"; break;
|
||||
case FSTATE_TASK: blkstr = taskname(ps->ps_ftask); break;
|
||||
default: blkstr = "??"; break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,10 +334,10 @@ static int parse_arguments(int argc, char **argv, u32_t *rss_flags)
|
|||
}
|
||||
}
|
||||
else if (strcmp(argv[i], ARG_DEVSTYLE)==0) {
|
||||
char* dev_style_keys[] = { "STYLE_DEV", "STYLE_DEVA", "STYLE_TTY",
|
||||
"STYLE_CTTY", "STYLE_CLONE", "STYLE_CLONE_A", NULL };
|
||||
int dev_style_values[] = { STYLE_DEV, STYLE_DEVA, STYLE_TTY,
|
||||
STYLE_CTTY, STYLE_CLONE, STYLE_CLONE_A };
|
||||
char* dev_style_keys[] = { "STYLE_DEV", "STYLE_TTY",
|
||||
"STYLE_CTTY", "STYLE_CLONE", NULL };
|
||||
int dev_style_values[] = { STYLE_DEV, STYLE_TTY,
|
||||
STYLE_CTTY, STYLE_CLONE };
|
||||
for(j=0;dev_style_keys[j]!=NULL;j++) {
|
||||
if(!strcmp(dev_style_keys[j], argv[i+1])) {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@
|
|||
./usr/bin/dirname minix-sys
|
||||
./usr/bin/diskctl minix-sys
|
||||
./usr/bin/du minix-sys
|
||||
./usr/bin/dumpcore minix-sys
|
||||
./usr/bin/dumpcore minix-sys obsolete
|
||||
./usr/bin/egrep minix-sys
|
||||
./usr/bin/eject minix-sys
|
||||
./usr/bin/elfedit minix-sys binutils
|
||||
|
|
@ -314,7 +314,7 @@
|
|||
./usr/bin/ftp minix-sys
|
||||
./usr/bin/g++ minix-sys gcccmds
|
||||
./usr/bin/gcc minix-sys gcccmds
|
||||
./usr/bin/gcore minix-sys
|
||||
./usr/bin/gcore minix-sys obsolete
|
||||
./usr/bin/gcov minix-sys gcccmds
|
||||
./usr/bin/gcov-pull minix-sys
|
||||
./usr/bin/gcpp minix-sys gcccmds
|
||||
|
|
@ -1828,7 +1828,7 @@
|
|||
./usr/man/man1/dosread.1 minix-sys
|
||||
./usr/man/man1/doswrite.1 minix-sys
|
||||
./usr/man/man1/du.1 minix-sys
|
||||
./usr/man/man1/dumpcore.1 minix-sys
|
||||
./usr/man/man1/dumpcore.1 minix-sys obsolete
|
||||
./usr/man/man1/echo.1 minix-sys
|
||||
./usr/man/man1/ed.1 minix-sys
|
||||
./usr/man/man1/egrep.1 minix-sys
|
||||
|
|
@ -5364,6 +5364,8 @@
|
|||
./usr/tests/minix-posix/test73 minix-sys
|
||||
./usr/tests/minix-posix/test74 minix-sys
|
||||
./usr/tests/minix-posix/test75 minix-sys
|
||||
./usr/tests/minix-posix/test76 minix-sys
|
||||
./usr/tests/minix-posix/test77 minix-sys
|
||||
./usr/tests/minix-posix/test8 minix-sys
|
||||
./usr/tests/minix-posix/test9 minix-sys
|
||||
./usr/tests/minix-posix/testinterp minix-sys
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ main(int argc, char *argv[])
|
|||
|
||||
sef_local_startup();
|
||||
|
||||
chardriver_task(&bmp085_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&bmp085_tab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ main(int argc, char *argv[])
|
|||
fb_edid_args_parse();
|
||||
|
||||
sef_local_startup();
|
||||
chardriver_task(&fb_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&fb_tab);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ int main(void)
|
|||
/*
|
||||
* Run the main loop.
|
||||
*/
|
||||
chardriver_task(&hello_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&hello_tab);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@ main(int argc, char *argv[])
|
|||
|
||||
memset(i2cdev, '\0', sizeof(i2cdev));
|
||||
sef_local_startup();
|
||||
chardriver_task(&i2c_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&i2c_tab);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ static int log_transfer(endpoint_t endpt, int opcode, u64_t position,
|
|||
static int log_do_open(message *m_ptr);
|
||||
static int log_cancel(message *m_ptr);
|
||||
static int log_select(message *m_ptr);
|
||||
static int log_other(message *m_ptr);
|
||||
static int subread(struct logdevice *log, int count, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t);
|
||||
|
||||
|
|
@ -44,7 +43,7 @@ static struct chardriver log_dtab = {
|
|||
nop_alarm, /* no alarm */
|
||||
log_cancel, /* CANCEL request */
|
||||
log_select, /* DEV_SELECT request */
|
||||
log_other /* Unrecognized messages */
|
||||
NULL /* Unrecognized messages */
|
||||
};
|
||||
|
||||
/* SEF functions and variables. */
|
||||
|
|
@ -64,7 +63,7 @@ int main(void)
|
|||
sef_local_startup();
|
||||
|
||||
/* Call the generic receive loop. */
|
||||
chardriver_task(&log_dtab, CHARDRIVER_ASYNC);
|
||||
chardriver_task(&log_dtab);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -282,7 +281,7 @@ static int log_transfer(
|
|||
iovec_t *iov, /* pointer to read or write request vector */
|
||||
unsigned int nr_req, /* length of request vector */
|
||||
endpoint_t user_endpt, /* endpoint of user process */
|
||||
unsigned int UNUSED(flags)
|
||||
unsigned int flags
|
||||
)
|
||||
{
|
||||
/* Read or write one the driver's minor devices. */
|
||||
|
|
@ -317,6 +316,8 @@ static int log_transfer(
|
|||
if (!log->log_size) {
|
||||
if(accumulated_read)
|
||||
return OK;
|
||||
if (flags & FLG_OP_NONBLOCK)
|
||||
return EAGAIN;
|
||||
/* No data available; let caller block. */
|
||||
log->log_source = endpt;
|
||||
log->log_iosize = count;
|
||||
|
|
@ -368,48 +369,25 @@ static int log_do_open(message *m_ptr)
|
|||
static int log_cancel(message *m_ptr)
|
||||
{
|
||||
int d;
|
||||
d = m_ptr->TTY_LINE;
|
||||
d = m_ptr->DEVICE;
|
||||
if(d < 0 || d >= NR_DEVS)
|
||||
return EINVAL;
|
||||
if (m_ptr->USER_ENDPT != logdevices[d].log_proc_nr)
|
||||
return EDONTREPLY;
|
||||
if ((cp_grant_id_t) m_ptr->IO_GRANT != logdevices[d].log_user_grant)
|
||||
return EDONTREPLY;
|
||||
logdevices[d].log_proc_nr = NONE;
|
||||
logdevices[d].log_revive_alerted = 0;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* log_other *
|
||||
*============================================================================*/
|
||||
static int log_other(message *m_ptr)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* This function gets messages that the generic driver doesn't
|
||||
* understand.
|
||||
*/
|
||||
if (is_notify(m_ptr->m_type)) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
switch(m_ptr->m_type) {
|
||||
case DEV_STATUS: {
|
||||
printf("log_other: unexpected DEV_STATUS request\n");
|
||||
r = EDONTREPLY;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r = EINVAL;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*============================================================================*
|
||||
* log_select *
|
||||
*============================================================================*/
|
||||
static int log_select(message *m_ptr)
|
||||
{
|
||||
int d, ready_ops = 0, ops = 0;
|
||||
d = m_ptr->TTY_LINE;
|
||||
d = m_ptr->DEV_MINOR;
|
||||
if(d < 0 || d >= NR_DEVS) {
|
||||
#if LOG_DEBUG
|
||||
printf("line %d? EINVAL\n", d);
|
||||
|
|
@ -417,10 +395,10 @@ static int log_select(message *m_ptr)
|
|||
return EINVAL;
|
||||
}
|
||||
|
||||
ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
|
||||
/* Read blocks when there is no log. */
|
||||
if((m_ptr->USER_ENDPT & SEL_RD) && logdevices[d].log_size > 0) {
|
||||
if((m_ptr->DEV_SEL_OPS & SEL_RD) && logdevices[d].log_size > 0) {
|
||||
#if LOG_DEBUG
|
||||
printf("log can read; size %d\n", logdevices[d].log_size);
|
||||
#endif
|
||||
|
|
@ -428,13 +406,13 @@ static int log_select(message *m_ptr)
|
|||
}
|
||||
|
||||
/* Write never blocks. */
|
||||
if(m_ptr->USER_ENDPT & SEL_WR) ready_ops |= SEL_WR;
|
||||
if(m_ptr->DEV_SEL_OPS & SEL_WR) ready_ops |= SEL_WR;
|
||||
|
||||
/* Enable select calback if no operations were
|
||||
* ready to go, but operations were requested,
|
||||
* and notify was enabled.
|
||||
*/
|
||||
if((m_ptr->USER_ENDPT & SEL_NOTIFY) && ops && !ready_ops) {
|
||||
if((m_ptr->DEV_SEL_OPS & SEL_NOTIFY) && ops && !ready_ops) {
|
||||
logdevices[d].log_selected |= ops;
|
||||
logdevices[d].log_select_proc = m_ptr->m_source;
|
||||
#if LOG_DEBUG
|
||||
|
|
|
|||
|
|
@ -117,8 +117,7 @@ int main(void)
|
|||
if (IS_BDEV_RQ(msg.m_type))
|
||||
blockdriver_process(&m_bdtab, &msg, ipc_status);
|
||||
else
|
||||
chardriver_process(&m_cdtab, CHARDRIVER_SYNC, &msg,
|
||||
ipc_status);
|
||||
chardriver_process(&m_cdtab, &msg, ipc_status);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
/* State management variables. */
|
||||
EXTERN int writing;
|
||||
EXTERN int is_status_msg_expected;
|
||||
|
||||
/* Custom states definition. */
|
||||
#define PR_STATE_WRITE_PROTOCOL_FREE (SEF_LU_STATE_CUSTOM_BASE + 0)
|
||||
|
|
@ -24,7 +23,7 @@ int sef_cb_lu_prepare(int state)
|
|||
break;
|
||||
|
||||
case SEF_LU_STATE_PROTOCOL_FREE:
|
||||
is_ready = (!writing && !is_status_msg_expected);
|
||||
is_ready = (!writing);
|
||||
break;
|
||||
|
||||
/* Custom states. */
|
||||
|
|
@ -52,15 +51,13 @@ void sef_cb_lu_state_dump(int state)
|
|||
{
|
||||
sef_lu_dprint("printer: live update state = %d\n", state);
|
||||
sef_lu_dprint("printer: writing = %d\n", writing);
|
||||
sef_lu_dprint("printer: is_status_msg_expected = %d\n",
|
||||
is_status_msg_expected);
|
||||
|
||||
sef_lu_dprint("printer: SEF_LU_STATE_WORK_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_WORK_FREE, TRUE);
|
||||
sef_lu_dprint("printer: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_REQUEST_FREE, TRUE);
|
||||
sef_lu_dprint("printer: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_PROTOCOL_FREE, (!writing && !is_status_msg_expected));
|
||||
SEF_LU_STATE_PROTOCOL_FREE, (!writing));
|
||||
sef_lu_dprint("printer: PR_STATE_WRITE_PROTOCOL_FREE(%d) reached = %d\n",
|
||||
PR_STATE_WRITE_PROTOCOL_FREE, (!writing));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,13 @@
|
|||
* DEV_WRITE: a process wants to write on a terminal
|
||||
* CANCEL: terminate a previous incomplete system call immediately
|
||||
*
|
||||
* m_type TTY_LINE USER_ENDPT COUNT ADDRESS
|
||||
* m_type DEVICE USER_ENDPT COUNT ADDRESS
|
||||
* |-------------+---------+---------+---------+---------|
|
||||
* | DEV_OPEN | | | | |
|
||||
* |-------------+---------+---------+---------+---------|
|
||||
* | DEV_CLOSE | | proc nr | | |
|
||||
* -------------------------------------------------------
|
||||
* | HARD_INT | | | | |
|
||||
* |-------------+---------+---------+---------+---------|
|
||||
* | SYS_EVENT | | | | |
|
||||
* | HARD_INT | | | | |
|
||||
* |-------------+---------+---------+---------+---------|
|
||||
* | DEV_WRITE |minor dev| proc nr | count | buf ptr |
|
||||
* |-------------+---------+---------+---------+---------|
|
||||
|
|
@ -87,8 +85,6 @@
|
|||
*/
|
||||
|
||||
static endpoint_t caller; /* process to tell when printing done (FS) */
|
||||
static int revive_pending; /* set to true if revive is pending */
|
||||
static int revive_status; /* revive status */
|
||||
static int done_status; /* status of last output completion */
|
||||
static int oleft; /* bytes of output left in obuf */
|
||||
static unsigned char obuf[128]; /* output buffer */
|
||||
|
|
@ -105,11 +101,11 @@ static int irq_hook_id; /* id of irq hook at kernel */
|
|||
static void do_cancel(message *m_ptr);
|
||||
static void output_done(void);
|
||||
static void do_write(message *m_ptr);
|
||||
static void do_status(message *m_ptr);
|
||||
static void prepare_output(void);
|
||||
static int do_probe(void);
|
||||
static void do_initialize(void);
|
||||
static void reply(int code,int replyee,int proc,int status);
|
||||
static void reply(int code, endpoint_t replyee, endpoint_t proc,
|
||||
cp_grant_id_t grant, int status);
|
||||
static void do_printer_output(void);
|
||||
|
||||
/* SEF functions and variables. */
|
||||
|
|
@ -118,7 +114,6 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
|||
EXTERN int sef_cb_lu_prepare(int state);
|
||||
EXTERN int sef_cb_lu_state_isvalid(int state);
|
||||
EXTERN void sef_cb_lu_state_dump(int state);
|
||||
int is_status_msg_expected = FALSE;
|
||||
|
||||
/*===========================================================================*
|
||||
* printer_task *
|
||||
|
|
@ -142,26 +137,25 @@ int main(void)
|
|||
case HARDWARE:
|
||||
do_printer_output();
|
||||
break;
|
||||
default:
|
||||
reply(TASK_REPLY, pr_mess.m_source,
|
||||
pr_mess.USER_ENDPT, EINVAL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(pr_mess.m_type) {
|
||||
case DEV_OPEN:
|
||||
do_initialize(); /* initialize */
|
||||
/* fall through */
|
||||
do_initialize(); /* initialize */
|
||||
reply(DEV_OPEN_REPL, pr_mess.m_source, pr_mess.USER_ENDPT,
|
||||
(cp_grant_id_t) pr_mess.IO_GRANT, OK);
|
||||
break;
|
||||
case DEV_CLOSE:
|
||||
reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT, OK);
|
||||
reply(DEV_CLOSE_REPL, pr_mess.m_source, pr_mess.USER_ENDPT,
|
||||
(cp_grant_id_t) pr_mess.IO_GRANT, OK);
|
||||
break;
|
||||
case DEV_WRITE_S: do_write(&pr_mess); break;
|
||||
case DEV_STATUS: do_status(&pr_mess); break;
|
||||
case CANCEL: do_cancel(&pr_mess); break;
|
||||
default:
|
||||
reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT,
|
||||
EINVAL);
|
||||
reply(DEV_REVIVE, pr_mess.m_source, pr_mess.USER_ENDPT,
|
||||
(cp_grant_id_t) pr_mess.IO_GRANT, EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -213,23 +207,21 @@ register message *m_ptr; /* pointer to the newly arrived message */
|
|||
{
|
||||
/* The printer is used by sending DEV_WRITE messages to it. Process one. */
|
||||
|
||||
register int r = SUSPEND;
|
||||
int r = OK;
|
||||
int retries;
|
||||
u32_t status;
|
||||
|
||||
/* Reject command if last write is not yet finished, the count is not
|
||||
* positive, or the user address is bad.
|
||||
*/
|
||||
if (writing) r = EIO;
|
||||
else if (m_ptr->COUNT <= 0) r = EINVAL;
|
||||
if (writing) r = EIO;
|
||||
else if (m_ptr->COUNT <= 0) r = EINVAL;
|
||||
else if (m_ptr->FLAGS & FLG_OP_NONBLOCK) r = EAGAIN; /* not supported */
|
||||
|
||||
/* Reply to FS, no matter what happened, possible SUSPEND caller. */
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
|
||||
/* If no errors occurred, continue printing with SUSPENDED caller.
|
||||
/* If no errors occurred, continue printing with the caller.
|
||||
* First wait until the printer is online to prevent stupid errors.
|
||||
*/
|
||||
if (SUSPEND == r) {
|
||||
if (r == OK) {
|
||||
caller = m_ptr->m_source;
|
||||
proc_nr = m_ptr->USER_ENDPT;
|
||||
user_left = m_ptr->COUNT;
|
||||
|
|
@ -254,6 +246,9 @@ register message *m_ptr; /* pointer to the newly arrived message */
|
|||
/* If we reach this point, the printer was not online in time. */
|
||||
done_status = status;
|
||||
output_done();
|
||||
} else {
|
||||
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,6 +261,7 @@ static void output_done()
|
|||
* Otherwise, reply to caller (FS).
|
||||
*/
|
||||
register int status;
|
||||
message m;
|
||||
|
||||
if (!writing) return; /* probably leftover interrupt */
|
||||
if (done_status != OK) { /* printer error occurred */
|
||||
|
|
@ -291,32 +287,15 @@ static void output_done()
|
|||
else { /* done! report back to FS */
|
||||
status = orig_count;
|
||||
}
|
||||
is_status_msg_expected = TRUE;
|
||||
revive_pending = TRUE;
|
||||
revive_status = status;
|
||||
notify(caller);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_status *
|
||||
*===========================================================================*/
|
||||
static void do_status(m_ptr)
|
||||
register message *m_ptr; /* pointer to the newly arrived message */
|
||||
{
|
||||
if (revive_pending) {
|
||||
m_ptr->m_type = DEV_REVIVE; /* build message */
|
||||
m_ptr->REP_ENDPT = proc_nr;
|
||||
m_ptr->REP_STATUS = revive_status;
|
||||
m_ptr->REP_IO_GRANT = grant_nr;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.m_type = DEV_REVIVE; /* build message */
|
||||
m.REP_ENDPT = proc_nr;
|
||||
m.REP_STATUS = status;
|
||||
m.REP_IO_GRANT = grant_nr;
|
||||
send(caller, &m);
|
||||
|
||||
writing = FALSE; /* unmark event */
|
||||
revive_pending = FALSE; /* unmark event */
|
||||
} else {
|
||||
m_ptr->m_type = DEV_NO_STATUS;
|
||||
|
||||
is_status_msg_expected = FALSE;
|
||||
}
|
||||
send(m_ptr->m_source, m_ptr); /* send the message */
|
||||
writing = FALSE; /* unmark event */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -331,30 +310,32 @@ register message *m_ptr; /* pointer to the newly arrived message */
|
|||
* but rely on FS to handle the EINTR reply and de-suspension properly.
|
||||
*/
|
||||
|
||||
if (writing && m_ptr->USER_ENDPT == proc_nr) {
|
||||
if (writing && m_ptr->USER_ENDPT == proc_nr &&
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT == grant_nr) {
|
||||
oleft = 0; /* cancel output by interrupt handler */
|
||||
writing = FALSE;
|
||||
revive_pending = FALSE;
|
||||
reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant_nr, EINTR);
|
||||
}
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, EINTR);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* reply *
|
||||
*===========================================================================*/
|
||||
static void reply(code, replyee, process, status)
|
||||
int code; /* TASK_REPLY or REVIVE */
|
||||
int replyee; /* destination for message (normally FS) */
|
||||
int process; /* which user requested the printing */
|
||||
static void reply(code, replyee, process, grant, status)
|
||||
int code; /* DEV_OPEN_REPL, DEV_CLOSE_REPL, DEV_REVIVE */
|
||||
endpoint_t replyee; /* destination for message (normally FS) */
|
||||
endpoint_t process; /* which user requested the printing */
|
||||
cp_grant_id_t grant; /* which grant was involved */
|
||||
int status; /* number of chars printed or error code */
|
||||
{
|
||||
/* Send a reply telling FS that printing has started or stopped. */
|
||||
|
||||
message pr_mess;
|
||||
|
||||
pr_mess.m_type = code; /* TASK_REPLY or REVIVE */
|
||||
pr_mess.m_type = code; /* reply code */
|
||||
pr_mess.REP_STATUS = status; /* count or EIO */
|
||||
pr_mess.REP_ENDPT = process; /* which user does this pertain to */
|
||||
pr_mess.REP_ENDPT = process; /* which user does this pertain to */
|
||||
pr_mess.REP_IO_GRANT = grant; /* the grant */
|
||||
send(replyee, &pr_mess); /* send the message */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ int main(void)
|
|||
sef_local_startup();
|
||||
|
||||
/* Call the generic receive loop. */
|
||||
chardriver_task(&r_dtab, CHARDRIVER_ASYNC);
|
||||
chardriver_task(&r_dtab);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ main(int argc, char *argv[])
|
|||
|
||||
sef_local_startup();
|
||||
|
||||
chardriver_task(&sht21_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&sht21_tab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,7 +434,6 @@ int
|
|||
main(int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
endpoint_t user, caller;
|
||||
message m;
|
||||
int ipc_status;
|
||||
|
||||
|
|
@ -485,26 +484,8 @@ main(int argc, char *argv[])
|
|||
continue;
|
||||
}
|
||||
|
||||
caller = m.m_source;
|
||||
user = m.USER_ENDPT;
|
||||
|
||||
/*
|
||||
* Handle Message
|
||||
*
|
||||
* So far this driver only deals with notifications
|
||||
* so it always replies to non-notifications with EINVAL.
|
||||
*/
|
||||
|
||||
/* Send Reply */
|
||||
m.m_type = TASK_REPLY;
|
||||
m.REP_ENDPT = user;
|
||||
m.REP_STATUS = EINVAL;
|
||||
|
||||
r = sendnb(caller, &m);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "sendnb() failed\n");
|
||||
continue;
|
||||
}
|
||||
log_warn(&log, "Ignoring message 0x%x from 0x%x\n", m.m_type,
|
||||
m.m_source);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ main(int argc, char *argv[])
|
|||
|
||||
sef_local_startup();
|
||||
|
||||
chardriver_task(&tsl2550_tab, CHARDRIVER_SYNC);
|
||||
chardriver_task(&tsl2550_tab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@ kb_init_once(void)
|
|||
{
|
||||
}
|
||||
|
||||
int
|
||||
kbd_status(message *m)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
kbd_loadmap(message *m)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -268,27 +268,20 @@ rs_write(register tty_t *tp, int try)
|
|||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outgrant,
|
||||
tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -215,14 +215,10 @@ int try;
|
|||
|
||||
/* Reply to the writer if all output is finished or if an error occured. */
|
||||
if (tp->tty_outleft == 0 || result != OK) {
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, result != OK ? result : tp->tty_outcum);
|
||||
tp->tty_outcum = tp->tty_outleft = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -825,14 +821,16 @@ void do_video(message *m)
|
|||
case DEV_OPEN:
|
||||
/* Should grant IOPL */
|
||||
disable_console();
|
||||
r= OK;
|
||||
break;
|
||||
tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
||||
return;
|
||||
case DEV_CLOSE:
|
||||
reenable_console();
|
||||
r= OK;
|
||||
break;
|
||||
tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
||||
return;
|
||||
case DEV_IOCTL_S:
|
||||
switch(m->TTY_REQUEST) {
|
||||
switch(m->REQUEST) {
|
||||
case TIOCMAPMEM:
|
||||
case TIOCUNMAPMEM: {
|
||||
int r, do_map;
|
||||
|
|
@ -847,9 +845,7 @@ void do_video(message *m)
|
|||
if (r != OK)
|
||||
{
|
||||
printf("tty: sys_safecopyfrom failed\n");
|
||||
tty_reply(TASK_REPLY, m->m_source,
|
||||
m->USER_ENDPT, r);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/* In safe ioctl mode, the POSITION field contains
|
||||
|
|
@ -870,20 +866,22 @@ void do_video(message *m)
|
|||
r = vm_unmap_phys(m->POSITION,
|
||||
mapreqvm.vaddr, mapreqvm.size);
|
||||
}
|
||||
tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r= ENOTTY;
|
||||
break;
|
||||
}
|
||||
r= ENOTTY;
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
printf(
|
||||
"Warning, TTY(video) got unexpected request %d from %d\n",
|
||||
m->m_type, m->m_source);
|
||||
r= EINVAL;
|
||||
}
|
||||
tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
|
||||
tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, r);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <minix/input.h>
|
||||
#include <minix/keymap.h>
|
||||
#include <minix/reboot.h>
|
||||
#include <assert.h>
|
||||
#include "tty.h"
|
||||
#include "kernel/const.h"
|
||||
#include "kernel/config.h"
|
||||
|
|
@ -134,6 +135,7 @@ static struct kbd
|
|||
int incaller;
|
||||
int select_ops;
|
||||
int select_proc;
|
||||
int select_minor; /* sanity check only, can be removed */
|
||||
} kbd, kbdaux;
|
||||
|
||||
/* Data that is to be sent to the keyboard. Each byte is ACKed by the
|
||||
|
|
@ -154,7 +156,6 @@ static long debug_fkeys = 1;
|
|||
static timer_t tmr_kbd_wd;
|
||||
|
||||
static void handle_req(struct kbd *kbdp, message *m);
|
||||
static int handle_status(struct kbd *kbdp, message *m);
|
||||
static void kbc_cmd0(int cmd);
|
||||
static void kbc_cmd1(int cmd, int data);
|
||||
static int kbc_read(void);
|
||||
|
|
@ -186,20 +187,6 @@ void do_kbd(message *m)
|
|||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* kbd_status *
|
||||
*===========================================================================*/
|
||||
int kbd_status(message *m)
|
||||
{
|
||||
int r;
|
||||
|
||||
r= handle_status(&kbd, m);
|
||||
if (r)
|
||||
return r;
|
||||
return handle_status(&kbdaux, m);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* do_kbdaux *
|
||||
*===========================================================================*/
|
||||
|
|
@ -224,8 +211,9 @@ message *m;
|
|||
switch (m->m_type) {
|
||||
case DEV_OPEN:
|
||||
kbdp->nr_open++;
|
||||
r= OK;
|
||||
break;
|
||||
tty_reply(DEV_OPEN_REPL, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
||||
return;
|
||||
case DEV_CLOSE:
|
||||
kbdp->nr_open--;
|
||||
if (kbdp->nr_open < 0)
|
||||
|
|
@ -235,8 +223,9 @@ message *m;
|
|||
}
|
||||
if (kbdp->nr_open == 0)
|
||||
kbdp->avail= 0;
|
||||
r= OK;
|
||||
break;
|
||||
tty_reply(DEV_CLOSE_REPL, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, OK);
|
||||
return;
|
||||
case DEV_READ_S:
|
||||
if (kbdp->req_size)
|
||||
{
|
||||
|
|
@ -246,14 +235,17 @@ message *m;
|
|||
}
|
||||
if (kbdp->avail == 0)
|
||||
{
|
||||
if (m->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = EAGAIN;
|
||||
break;
|
||||
}
|
||||
/* Should record proc */
|
||||
kbdp->req_size= m->COUNT;
|
||||
kbdp->req_proc= m->USER_ENDPT;
|
||||
kbdp->req_grant= (cp_grant_id_t) m->IO_GRANT;
|
||||
kbdp->req_addr_offset= 0;
|
||||
kbdp->incaller= m->m_source;
|
||||
r= SUSPEND;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle read request */
|
||||
|
|
@ -302,11 +294,11 @@ message *m;
|
|||
|
||||
case CANCEL:
|
||||
kbdp->req_size= 0;
|
||||
r= OK;
|
||||
r= EAGAIN;
|
||||
break;
|
||||
case DEV_SELECT:
|
||||
ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0;
|
||||
ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0;
|
||||
|
||||
r= 0;
|
||||
if (kbdp->avail && (ops & SEL_RD))
|
||||
|
|
@ -319,10 +311,13 @@ message *m;
|
|||
{
|
||||
kbdp->select_ops |= ops;
|
||||
kbdp->select_proc= m->m_source;
|
||||
kbdp->select_minor= m->DEV_MINOR;
|
||||
}
|
||||
break;
|
||||
assert(kbdp->minor == m->DEV_MINOR);
|
||||
select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, r);
|
||||
return;
|
||||
case DEV_IOCTL_S:
|
||||
if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS)
|
||||
if (kbdp == &kbd && m->REQUEST == KIOCSLEDS)
|
||||
{
|
||||
kio_leds_t leds;
|
||||
unsigned char b;
|
||||
|
|
@ -358,7 +353,7 @@ message *m;
|
|||
r= OK;
|
||||
break;
|
||||
}
|
||||
if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL)
|
||||
if (kbdp == &kbd && m->REQUEST == KIOCBELL)
|
||||
{
|
||||
kio_bell_t bell;
|
||||
clock_t ticks;
|
||||
|
|
@ -386,59 +381,8 @@ message *m;
|
|||
m->m_type, m->m_source);
|
||||
r= EINVAL;
|
||||
}
|
||||
tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* handle_status *
|
||||
*===========================================================================*/
|
||||
static int handle_status(kbdp, m)
|
||||
struct kbd *kbdp;
|
||||
message *m;
|
||||
{
|
||||
int n, r;
|
||||
|
||||
if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller &&
|
||||
kbdp->req_grant != GRANT_INVALID)
|
||||
{
|
||||
/* Handle read request */
|
||||
n= kbdp->avail;
|
||||
if (n > kbdp->req_size)
|
||||
n= kbdp->req_size;
|
||||
if (kbdp->offset + n > KBD_BUFSZ)
|
||||
n= KBD_BUFSZ-kbdp->offset;
|
||||
if (n <= 0)
|
||||
panic("kbd_status: bad n: %d", n);
|
||||
kbdp->req_size= 0;
|
||||
r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0,
|
||||
(vir_bytes)&kbdp->buf[kbdp->offset], n);
|
||||
if (r == OK)
|
||||
{
|
||||
kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
|
||||
kbdp->avail -= n;
|
||||
r= n;
|
||||
} else printf("copy in revive kbd failed: %d\n", r);
|
||||
|
||||
m->m_type = DEV_REVIVE;
|
||||
m->REP_ENDPT= kbdp->req_proc;
|
||||
m->REP_IO_GRANT= kbdp->req_grant;
|
||||
m->REP_STATUS= r;
|
||||
kbdp->req_grant = GRANT_INVALID;
|
||||
return 1;
|
||||
}
|
||||
if (kbdp->avail && (kbdp->select_ops & SEL_RD) &&
|
||||
m->m_source == kbdp->select_proc)
|
||||
{
|
||||
m->m_type = DEV_IO_READY;
|
||||
m->DEV_MINOR = kbdp->minor;
|
||||
m->DEV_SEL_OPS = SEL_RD;
|
||||
|
||||
kbdp->select_ops &= ~SEL_RD;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
tty_reply(DEV_REVIVE, m->m_source, m->USER_ENDPT,
|
||||
(cp_grant_id_t) m->IO_GRANT, r);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -486,7 +430,7 @@ int scode;
|
|||
void kbd_interrupt(message *UNUSED(m_ptr))
|
||||
{
|
||||
/* A keyboard interrupt has occurred. Process it. */
|
||||
int o, isaux;
|
||||
int n, r, o, isaux;
|
||||
unsigned char scode;
|
||||
struct kbd *kbdp;
|
||||
|
||||
|
|
@ -512,15 +456,40 @@ void kbd_interrupt(message *UNUSED(m_ptr))
|
|||
#endif
|
||||
return; /* Buffer is full */
|
||||
}
|
||||
o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
|
||||
kbdp->buf[o]= scode;
|
||||
kbdp->avail++;
|
||||
if (kbdp->req_size) {
|
||||
notify(kbdp->incaller);
|
||||
}
|
||||
if (kbdp->select_ops & SEL_RD)
|
||||
notify(kbdp->select_proc);
|
||||
return;
|
||||
o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ;
|
||||
kbdp->buf[o]= scode;
|
||||
kbdp->avail++;
|
||||
if (kbdp->req_size) {
|
||||
/* Reply to read request */
|
||||
n= kbdp->avail;
|
||||
if (n > kbdp->req_size)
|
||||
n= kbdp->req_size;
|
||||
if (kbdp->offset + n > KBD_BUFSZ)
|
||||
n= KBD_BUFSZ-kbdp->offset;
|
||||
if (n <= 0)
|
||||
panic("kbd_interrupt: bad n: %d", n);
|
||||
kbdp->req_size= 0;
|
||||
r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0,
|
||||
(vir_bytes)&kbdp->buf[kbdp->offset], n);
|
||||
if (r == OK)
|
||||
{
|
||||
kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ;
|
||||
kbdp->avail -= n;
|
||||
r= n;
|
||||
} else printf("copy in revive kbd failed: %d\n", r);
|
||||
|
||||
tty_reply(DEV_REVIVE, kbdp->incaller, kbdp->req_proc,
|
||||
kbdp->req_grant, r);
|
||||
kbdp->req_grant = GRANT_INVALID;
|
||||
}
|
||||
/* Only satisfy pending select if characters weren't just read. */
|
||||
if (kbdp->avail && (kbdp->select_ops & SEL_RD)) {
|
||||
assert(kbdp->select_minor == kbdp->minor);
|
||||
select_reply(DEV_SEL_REPL2, kbdp->select_proc, kbdp->minor,
|
||||
SEL_RD);
|
||||
kbdp->select_ops &= ~SEL_RD;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the scancode in memory so the task can get at it later. */
|
||||
|
|
|
|||
|
|
@ -269,26 +269,18 @@ static int rs_write(register tty_t *tp, int try)
|
|||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ typedef struct pty {
|
|||
char state; /* flags: busy, closed, ... */
|
||||
|
||||
/* Read call on /dev/ptypX. */
|
||||
char rdsendreply; /* send a reply (instead of notify) */
|
||||
int rdcaller; /* process making the call (usually FS) */
|
||||
int rdproc; /* process that wants to read from the pty */
|
||||
cp_grant_id_t rdgrant; /* grant for readers address space */
|
||||
|
|
@ -42,7 +41,6 @@ typedef struct pty {
|
|||
int rdcum; /* # bytes written so far */
|
||||
|
||||
/* Write call to /dev/ptypX. */
|
||||
char wrsendreply; /* send a reply (instead of notify) */
|
||||
int wrcaller; /* process making the call (usually FS) */
|
||||
int wrproc; /* process that wants to write to the pty */
|
||||
cp_grant_id_t wrgrant; /* grant for writers address space */
|
||||
|
|
@ -56,14 +54,15 @@ typedef struct pty {
|
|||
char obuf[2048]; /* buffer for bytes going to the pty reader */
|
||||
|
||||
/* select() data. */
|
||||
int select_ops, /* Which operations do we want to know about? */
|
||||
select_proc, /* Who wants to know about it? */
|
||||
select_ready_ops; /* For callback. */
|
||||
int select_ops; /* Which operations do we want to know about? */
|
||||
int select_proc; /* Who wants to know about it? */
|
||||
dev_t select_minor; /* sanity check only, can be removed */
|
||||
} pty_t;
|
||||
|
||||
#define PTY_ACTIVE 0x01 /* pty is open/active */
|
||||
#define TTY_CLOSED 0x02 /* tty side has closed down */
|
||||
#define PTY_CLOSED 0x04 /* pty side has closed down */
|
||||
#define TTY_ACTIVE 0x01 /* tty is open/active */
|
||||
#define PTY_ACTIVE 0x02 /* pty is open/active */
|
||||
#define TTY_CLOSED 0x04 /* tty side has closed down */
|
||||
#define PTY_CLOSED 0x08 /* pty side has closed down */
|
||||
|
||||
static pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */
|
||||
|
||||
|
|
@ -75,7 +74,7 @@ static int pty_read(tty_t *tp, int try);
|
|||
static int pty_close(tty_t *tp, int try);
|
||||
static int pty_icancel(tty_t *tp, int try);
|
||||
static int pty_ocancel(tty_t *tp, int try);
|
||||
static int pty_select(tty_t *tp, message *m);
|
||||
static void pty_select(tty_t *tp, message *m);
|
||||
|
||||
/*===========================================================================*
|
||||
* do_pty *
|
||||
|
|
@ -105,7 +104,6 @@ void do_pty(tty_t *tp, message *m_ptr)
|
|||
r = ENOBUFS;
|
||||
break;
|
||||
}
|
||||
pp->rdsendreply = TRUE;
|
||||
pp->rdcaller = m_ptr->m_source;
|
||||
pp->rdproc = m_ptr->USER_ENDPT;
|
||||
pp->rdgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
|
|
@ -118,9 +116,12 @@ void do_pty(tty_t *tp, message *m_ptr)
|
|||
return; /* already done */
|
||||
}
|
||||
|
||||
{
|
||||
r = SUSPEND; /* do suspend */
|
||||
pp->rdsendreply = FALSE;
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
} else {
|
||||
return; /* do suspend */
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -142,7 +143,6 @@ void do_pty(tty_t *tp, message *m_ptr)
|
|||
r = ENOBUFS;
|
||||
break;
|
||||
}
|
||||
pp->wrsendreply = TRUE;
|
||||
pp->wrcaller = m_ptr->m_source;
|
||||
pp->wrproc = m_ptr->USER_ENDPT;
|
||||
pp->wrgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
|
|
@ -154,32 +154,43 @@ void do_pty(tty_t *tp, message *m_ptr)
|
|||
return; /* already done */
|
||||
}
|
||||
|
||||
{
|
||||
pp->wrsendreply = FALSE; /* do suspend */
|
||||
r = SUSPEND;
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
|
||||
pp->wrleft = pp->wrcum = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
r = EAGAIN;
|
||||
} else {
|
||||
return; /* do suspend */
|
||||
}
|
||||
break;
|
||||
|
||||
case DEV_OPEN:
|
||||
r = pp->state != 0 ? EIO : OK;
|
||||
pp->state |= PTY_ACTIVE;
|
||||
pp->rdcum = 0;
|
||||
pp->wrcum = 0;
|
||||
break;
|
||||
if (!(pp->state & PTY_ACTIVE)) {
|
||||
pp->state |= PTY_ACTIVE;
|
||||
pp->rdcum = 0;
|
||||
pp->wrcum = 0;
|
||||
r = OK;
|
||||
} else {
|
||||
r = EIO;
|
||||
}
|
||||
tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
return;
|
||||
|
||||
case DEV_CLOSE:
|
||||
r = OK;
|
||||
if (pp->state & TTY_CLOSED) {
|
||||
if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) {
|
||||
pp->state = 0;
|
||||
} else {
|
||||
pp->state |= PTY_CLOSED;
|
||||
sigchar(tp, SIGHUP, 1);
|
||||
}
|
||||
break;
|
||||
tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, OK);
|
||||
return;
|
||||
|
||||
case DEV_SELECT:
|
||||
r = pty_select(tp, m_ptr);
|
||||
break;
|
||||
pty_select(tp, m_ptr);
|
||||
return;
|
||||
|
||||
case CANCEL:
|
||||
r = EINTR;
|
||||
|
|
@ -200,7 +211,8 @@ void do_pty(tty_t *tp, message *m_ptr)
|
|||
default:
|
||||
r = EINVAL;
|
||||
}
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -219,14 +231,10 @@ static int pty_write(tty_t *tp, int try)
|
|||
if (pp->state & PTY_CLOSED) {
|
||||
if (try) return 1;
|
||||
if (tp->tty_outleft > 0) {
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -272,14 +280,10 @@ static int pty_write(tty_t *tp, int try)
|
|||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
if(tp->tty_outrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_outcaller);
|
||||
tp->tty_outrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
|
||||
tp->tty_outproc, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_outcaller, tp->tty_outproc,
|
||||
tp->tty_outgrant, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
}
|
||||
pty_finish(pp);
|
||||
|
|
@ -349,12 +353,10 @@ static void pty_finish(pty_t *pp)
|
|||
* transferred.
|
||||
*/
|
||||
if (pp->rdcum > 0) {
|
||||
if (pp->rdsendreply) {
|
||||
tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum);
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
}
|
||||
else
|
||||
notify(pp->rdcaller);
|
||||
tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant,
|
||||
pp->rdcum);
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -373,14 +375,10 @@ static int pty_read(tty_t *tp, int try)
|
|||
if (pp->state & PTY_CLOSED) {
|
||||
if (try) return 1;
|
||||
if (tp->tty_inleft > 0) {
|
||||
if(tp->tty_inrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_incaller);
|
||||
tp->tty_inrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
|
||||
tp->tty_inproc, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -408,19 +406,34 @@ static int pty_read(tty_t *tp, int try)
|
|||
/* PTY writer bookkeeping. */
|
||||
pp->wrcum++;
|
||||
if (--pp->wrleft == 0) {
|
||||
if (pp->wrsendreply) {
|
||||
tty_reply(TASK_REPLY, pp->wrcaller, pp->wrproc,
|
||||
pp->wrcum);
|
||||
pp->wrcum = 0;
|
||||
}
|
||||
else
|
||||
notify(pp->wrcaller);
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum);
|
||||
pp->wrcum = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_open *
|
||||
*===========================================================================*/
|
||||
static int pty_open(tty_t *tp, int UNUSED(try))
|
||||
{
|
||||
/* The tty side has been opened. */
|
||||
pty_t *pp = tp->tty_priv;
|
||||
|
||||
/* TTY_ACTIVE may already be set, which would indicate that the slave is
|
||||
* reopened after being fully closed while the master is still open. In that
|
||||
* case TTY_CLOSED will also be set, so clear that one.
|
||||
*/
|
||||
pp->state |= TTY_ACTIVE;
|
||||
pp->state &= ~TTY_CLOSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_close *
|
||||
*===========================================================================*/
|
||||
|
|
@ -432,16 +445,21 @@ static int pty_close(tty_t *tp, int UNUSED(try))
|
|||
if (!(pp->state & PTY_ACTIVE)) return 0;
|
||||
|
||||
if (pp->rdleft > 0) {
|
||||
assert(!pp->rdsendreply);
|
||||
notify(pp->rdcaller);
|
||||
tty_reply(DEV_REVIVE, pp->rdcaller, pp->rdproc, pp->rdgrant,
|
||||
pp->rdcum);
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
if (pp->wrleft > 0) {
|
||||
assert(!pp->wrsendreply);
|
||||
notify(pp->wrcaller);
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum);
|
||||
pp->wrcum = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED;
|
||||
if (pp->state & PTY_CLOSED) pp->state = 0;
|
||||
else pp->state |= TTY_CLOSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -455,9 +473,10 @@ static int pty_icancel(tty_t *tp, int UNUSED(try))
|
|||
pty_t *pp = tp->tty_priv;
|
||||
|
||||
if (pp->wrleft > 0) {
|
||||
pp->wrcum += pp->wrleft;
|
||||
pp->wrleft= 0;
|
||||
notify(pp->wrcaller);
|
||||
tty_reply(DEV_REVIVE, pp->wrcaller, pp->wrproc, pp->wrgrant,
|
||||
pp->wrcum + pp->wrleft);
|
||||
pp->wrcum = pp->wrleft = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -502,64 +521,11 @@ void pty_init(tty_t *tp)
|
|||
tp->tty_echo = pty_echo;
|
||||
tp->tty_icancel = pty_icancel;
|
||||
tp->tty_ocancel = pty_ocancel;
|
||||
tp->tty_open = pty_open;
|
||||
tp->tty_close = pty_close;
|
||||
tp->tty_select_ops = 0;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_status *
|
||||
*===========================================================================*/
|
||||
int pty_status(message *m_ptr)
|
||||
{
|
||||
int i, event_found;
|
||||
pty_t *pp;
|
||||
|
||||
event_found = 0;
|
||||
for (i= 0, pp = pty_table; i<NR_PTYS; i++, pp++) {
|
||||
if ((((pp->state & TTY_CLOSED) && pp->rdleft > 0) ||
|
||||
pp->rdcum > 0) &&
|
||||
pp->rdcaller == m_ptr->m_source)
|
||||
{
|
||||
m_ptr->m_type = DEV_REVIVE;
|
||||
m_ptr->REP_ENDPT = pp->rdproc;
|
||||
m_ptr->REP_IO_GRANT = pp->rdgrant;
|
||||
m_ptr->REP_STATUS = pp->rdcum;
|
||||
pp->rdleft = pp->rdcum = 0;
|
||||
pp->rdgrant = GRANT_INVALID;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) ||
|
||||
pp->wrcum > 0) &&
|
||||
pp->wrcaller == m_ptr->m_source)
|
||||
{
|
||||
m_ptr->m_type = DEV_REVIVE;
|
||||
m_ptr->REP_ENDPT = pp->wrproc;
|
||||
m_ptr->REP_IO_GRANT = pp->wrgrant;
|
||||
if (pp->wrcum == 0)
|
||||
m_ptr->REP_STATUS = EIO;
|
||||
else
|
||||
m_ptr->REP_STATUS = pp->wrcum;
|
||||
|
||||
pp->wrleft = pp->wrcum = 0;
|
||||
pp->wrgrant = GRANT_INVALID;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pp->select_ready_ops && pp->select_proc == m_ptr->m_source) {
|
||||
m_ptr->m_type = DEV_IO_READY;
|
||||
m_ptr->DEV_MINOR = PTYPX_MINOR + i;
|
||||
m_ptr->DEV_SEL_OPS = pp->select_ready_ops;
|
||||
pp->select_ready_ops = 0;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return event_found;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_try_pty *
|
||||
*===========================================================================*/
|
||||
|
|
@ -591,35 +557,38 @@ static int select_try_pty(tty_t *tp, int ops)
|
|||
void select_retry_pty(tty_t *tp)
|
||||
{
|
||||
pty_t *pp = tp->tty_priv;
|
||||
dev_t minor;
|
||||
int r;
|
||||
|
||||
/* See if the pty side of a pty is ready to return a select. */
|
||||
if (pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) {
|
||||
minor = PTYPX_MINOR + (int) (pp - pty_table);
|
||||
assert(minor == pp->select_minor);
|
||||
select_reply(DEV_SEL_REPL2, pp->select_proc, minor, r);
|
||||
pp->select_ops &= ~r;
|
||||
pp->select_ready_ops |= r;
|
||||
notify(pp->select_proc);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pty_select *
|
||||
*===========================================================================*/
|
||||
static int pty_select(tty_t *tp, message *m)
|
||||
static void pty_select(tty_t *tp, message *m)
|
||||
{
|
||||
pty_t *pp = tp->tty_priv;
|
||||
int ops, ready_ops = 0, watch;
|
||||
|
||||
ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0;
|
||||
ops = m->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0;
|
||||
|
||||
ready_ops = select_try_pty(tp, ops);
|
||||
|
||||
if (!ready_ops && ops && watch) {
|
||||
pp->select_ops |= ops;
|
||||
pp->select_proc = m->m_source;
|
||||
pp->select_minor = m->DEV_MINOR;
|
||||
}
|
||||
|
||||
return ready_ops;
|
||||
select_reply(DEV_SEL_REPL1, m->m_source, m->DEV_MINOR, ready_ops);
|
||||
}
|
||||
|
||||
#endif /* NR_PTYS > 0 */
|
||||
|
|
|
|||
|
|
@ -27,28 +27,25 @@
|
|||
* DEV_OPEN: a tty line has been opened
|
||||
* DEV_CLOSE: a tty line has been closed
|
||||
* DEV_SELECT: start select notification request
|
||||
* DEV_STATUS: FS wants to know status for SELECT or REVIVE
|
||||
* CANCEL: terminate a previous incomplete system call immediately
|
||||
*
|
||||
* m_type TTY_LINE USER_ENDPT COUNT TTY_SPEKS IO_GRANT
|
||||
* m_type DEVICE USER_ENDPT COUNT POSITION IO_GRANT
|
||||
* -----------------------------------------------------------------
|
||||
* | HARD_INT | | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | SYS_SIG | sig set | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_READ |minor dev| proc nr | count | | grant |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_WRITE |minor dev| proc nr | count | | grant |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_IOCTL |minor dev| proc nr |func code|erase etc| |
|
||||
* | DEV_IOCTL |minor dev| proc nr |func code|user proc| |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_CLOSE |minor dev| proc nr | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_STATUS | | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | CANCEL |minor dev| proc nr | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_SELECT |minor dev| sel ops | | | |
|
||||
* -----------------------------------------------------------------
|
||||
*
|
||||
* Changes:
|
||||
|
|
@ -111,7 +108,6 @@ static void do_close(tty_t *tp, message *m_ptr);
|
|||
static void do_read(tty_t *tp, message *m_ptr);
|
||||
static void do_write(tty_t *tp, message *m_ptr);
|
||||
static void do_select(tty_t *tp, message *m_ptr);
|
||||
static void do_status(message *m_ptr);
|
||||
static void in_transfer(tty_t *tp);
|
||||
static int tty_echo(tty_t *tp, int ch);
|
||||
static void rawecho(tty_t *tp, int ch);
|
||||
|
|
@ -164,7 +160,7 @@ int main(void)
|
|||
message tty_mess; /* buffer for all incoming messages */
|
||||
int ipc_status;
|
||||
unsigned line;
|
||||
int r;
|
||||
int r, code;
|
||||
register tty_t *tp;
|
||||
|
||||
/* SEF local startup. */
|
||||
|
|
@ -231,21 +227,16 @@ int main(void)
|
|||
; /* do nothing; end switch */
|
||||
}
|
||||
|
||||
/* Only device requests should get to this point. All requests,
|
||||
* except DEV_STATUS, have a minor device number. Check this
|
||||
* exception and get the minor device number otherwise.
|
||||
/* Only device requests should get to this point.
|
||||
* All requests have a minor device number.
|
||||
*/
|
||||
if (tty_mess.m_type == DEV_STATUS) {
|
||||
do_status(&tty_mess);
|
||||
continue;
|
||||
}
|
||||
line = tty_mess.TTY_LINE;
|
||||
line = tty_mess.DEVICE;
|
||||
if (line == CONS_MINOR || line == LOG_MINOR) {
|
||||
/* /dev/log output goes to /dev/console */
|
||||
if (consoleline != CONS_MINOR) {
|
||||
/* Console output must redirected */
|
||||
line = consoleline;
|
||||
tty_mess.TTY_LINE = line;
|
||||
tty_mess.DEVICE = line;
|
||||
}
|
||||
}
|
||||
if (line == KBD_MINOR) {
|
||||
|
|
@ -274,10 +265,20 @@ int main(void)
|
|||
|
||||
/* If the device doesn't exist or is not configured return ENXIO. */
|
||||
if (tp == NULL || ! tty_active(tp)) {
|
||||
if (tty_mess.m_source != LOG_PROC_NR) {
|
||||
tty_reply(TASK_REPLY, tty_mess.m_source,
|
||||
tty_mess.USER_ENDPT, ENXIO);
|
||||
if (tty_mess.m_source == LOG_PROC_NR)
|
||||
continue;
|
||||
|
||||
/* Can all of these occur? Probably not. We're by far most
|
||||
* likely to see DEV_OPEN, but better safe than sorry..
|
||||
*/
|
||||
switch (tty_mess.m_type) {
|
||||
case DEV_OPEN: code = DEV_OPEN_REPL; break;
|
||||
case DEV_CLOSE: code = DEV_CLOSE_REPL; break;
|
||||
default: code = DEV_REVIVE; break;
|
||||
}
|
||||
|
||||
tty_reply(code, tty_mess.m_source, tty_mess.USER_ENDPT,
|
||||
(cp_grant_id_t) tty_mess.IO_GRANT, ENXIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -293,8 +294,8 @@ int main(void)
|
|||
default:
|
||||
printf("Warning, TTY got unexpected request %d from %d\n",
|
||||
tty_mess.m_type, tty_mess.m_source);
|
||||
tty_reply(TASK_REPLY, tty_mess.m_source,
|
||||
tty_mess.USER_ENDPT, EINVAL);
|
||||
tty_reply(DEV_REVIVE, tty_mess.m_source, tty_mess.USER_ENDPT,
|
||||
(cp_grant_id_t) tty_mess.IO_GRANT, EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +310,7 @@ set_color(tty_t *tp, int color)
|
|||
|
||||
buf[0] = '\033';
|
||||
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.m_source = KERNEL;
|
||||
msg.IO_GRANT = buf;
|
||||
msg.COUNT = sizeof(buf);
|
||||
|
|
@ -324,6 +326,7 @@ reset_color(tty_t *tp)
|
|||
#define SGR_COLOR_RESET 39
|
||||
buf[0] = '\033';
|
||||
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.m_source = KERNEL;
|
||||
msg.IO_GRANT = buf;
|
||||
msg.COUNT = sizeof(buf);
|
||||
|
|
@ -499,6 +502,7 @@ do_new_kmess(void)
|
|||
|
||||
if (kernel_msg_color != 0)
|
||||
set_color(tp, kernel_msg_color);
|
||||
memset(&print_kmsg, 0, sizeof(print_kmsg));
|
||||
print_kmsg.m_source = KERNEL;
|
||||
print_kmsg.IO_GRANT = kernel_buf_copy;
|
||||
print_kmsg.COUNT = bytes;
|
||||
|
|
@ -534,97 +538,6 @@ static void sef_cb_signal_handler(int signo)
|
|||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_status *
|
||||
*===========================================================================*/
|
||||
static void do_status(m_ptr)
|
||||
message *m_ptr;
|
||||
{
|
||||
register struct tty *tp;
|
||||
int event_found;
|
||||
int status;
|
||||
int ops;
|
||||
|
||||
/* Check for select or revive events on any of the ttys. If we found an,
|
||||
* event return a single status message for it. The FS will make another
|
||||
* call to see if there is more.
|
||||
*/
|
||||
event_found = 0;
|
||||
for (tp = FIRST_TTY; tp < END_TTY; tp++) {
|
||||
if ((ops = select_try(tp, tp->tty_select_ops)) &&
|
||||
tp->tty_select_proc == m_ptr->m_source) {
|
||||
|
||||
/* I/O for a selected minor device is ready. */
|
||||
m_ptr->m_type = DEV_IO_READY;
|
||||
m_ptr->DEV_MINOR = tp->tty_minor;
|
||||
m_ptr->DEV_SEL_OPS = ops;
|
||||
|
||||
tp->tty_select_ops &= ~ops; /* unmark select event */
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) {
|
||||
|
||||
/* Suspended request finished. Send a REVIVE. */
|
||||
m_ptr->m_type = DEV_REVIVE;
|
||||
m_ptr->REP_ENDPT = tp->tty_inproc;
|
||||
m_ptr->REP_IO_GRANT = tp->tty_ingrant;
|
||||
m_ptr->REP_STATUS = tp->tty_incum;
|
||||
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_inrevived = 0; /* unmark revive event */
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {
|
||||
|
||||
/* Suspended request finished. Send a REVIVE. */
|
||||
m_ptr->m_type = DEV_REVIVE;
|
||||
m_ptr->REP_ENDPT = tp->tty_outproc;
|
||||
m_ptr->REP_IO_GRANT = tp->tty_outgrant;
|
||||
m_ptr->REP_STATUS = tp->tty_outcum;
|
||||
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outrevived = 0; /* unmark revive event */
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
else if (tp->tty_iorevived && tp->tty_iocaller == m_ptr->m_source) {
|
||||
|
||||
/* Suspended request finished. Send a REVIVE. */
|
||||
m_ptr->m_type = DEV_REVIVE;
|
||||
m_ptr->REP_ENDPT = tp->tty_ioproc;
|
||||
m_ptr->REP_IO_GRANT = tp->tty_iogrant;
|
||||
m_ptr->REP_STATUS = tp->tty_iostatus;
|
||||
tp->tty_iorevived = 0; /* unmark revive event */
|
||||
tp->tty_iogrant = GRANT_INVALID;
|
||||
event_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if NR_PTYS > 0
|
||||
if (!event_found)
|
||||
event_found = pty_status(m_ptr);
|
||||
#endif
|
||||
if (!event_found)
|
||||
event_found= kbd_status(m_ptr);
|
||||
|
||||
if (! event_found) {
|
||||
/* No events of interest were found. Return an empty message. */
|
||||
m_ptr->m_type = DEV_NO_STATUS;
|
||||
}
|
||||
|
||||
/* Almost done. Send back the reply message to the caller. */
|
||||
status = send(m_ptr->m_source, m_ptr);
|
||||
if (status != OK) {
|
||||
printf("tty`do_status: send to %d failed: %d\n",
|
||||
m_ptr->m_source, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_read *
|
||||
*===========================================================================*/
|
||||
|
|
@ -651,7 +564,6 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
r = ENOBUFS;
|
||||
} else {
|
||||
/* Copy information from the message to the tty struct. */
|
||||
tp->tty_inrepcode = TASK_REPLY;
|
||||
tp->tty_incaller = m_ptr->m_source;
|
||||
tp->tty_inproc = m_ptr->USER_ENDPT;
|
||||
tp->tty_ingrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
|
|
@ -685,13 +597,18 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
return; /* already done */
|
||||
}
|
||||
|
||||
/* There were no bytes in the input queue available, so suspend
|
||||
* the caller.
|
||||
*/
|
||||
r = SUSPEND; /* suspend the caller */
|
||||
tp->tty_inrepcode = TTY_REVIVE;
|
||||
/* There were no bytes in the input queue available. */
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
tty_icancel(tp);
|
||||
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
} else {
|
||||
return; /* suspend the caller */
|
||||
}
|
||||
}
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
if (tp->tty_select_ops)
|
||||
select_retry(tp);
|
||||
}
|
||||
|
|
@ -716,7 +633,6 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
r = EINVAL;
|
||||
} else {
|
||||
/* Copy message parameters to the tty structure. */
|
||||
tp->tty_outrepcode = TASK_REPLY;
|
||||
tp->tty_outcaller = m_ptr->m_source;
|
||||
tp->tty_outproc = m_ptr->USER_ENDPT;
|
||||
tp->tty_outgrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
|
|
@ -728,13 +644,17 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
if (tp->tty_outleft == 0)
|
||||
return; /* already done */
|
||||
|
||||
/* None or not all the bytes could be written, so suspend the
|
||||
* caller.
|
||||
*/
|
||||
r = SUSPEND; /* suspend the caller */
|
||||
tp->tty_outrepcode = TTY_REVIVE;
|
||||
/* None or not all the bytes could be written. */
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
} else {
|
||||
return; /* suspend the caller */
|
||||
}
|
||||
}
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -755,7 +675,7 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
size_t size;
|
||||
|
||||
/* Size of the ioctl parameter. */
|
||||
switch (m_ptr->TTY_REQUEST) {
|
||||
switch (m_ptr->REQUEST) {
|
||||
case TCGETS: /* Posix tcgetattr function */
|
||||
case TCSETS: /* Posix tcsetattr function, TCSANOW option */
|
||||
case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
|
||||
|
|
@ -789,7 +709,7 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
}
|
||||
|
||||
r = OK;
|
||||
switch (m_ptr->TTY_REQUEST) {
|
||||
switch (m_ptr->REQUEST) {
|
||||
case TCGETS:
|
||||
/* Get the termios attributes. */
|
||||
r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0,
|
||||
|
|
@ -800,16 +720,20 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
case TCSETSF:
|
||||
case TCDRAIN:
|
||||
if (tp->tty_outleft > 0) {
|
||||
/* Wait for all ongoing output processing to finish. */
|
||||
tp->tty_iocaller = m_ptr->m_source;
|
||||
tp->tty_ioproc = m_ptr->USER_ENDPT;
|
||||
tp->tty_ioreq = m_ptr->REQUEST;
|
||||
tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
r = SUSPEND;
|
||||
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
|
||||
r = EAGAIN;
|
||||
} else {
|
||||
/* Wait for all ongoing output processing to finish. */
|
||||
tp->tty_iocaller = m_ptr->m_source;
|
||||
tp->tty_ioproc = m_ptr->USER_ENDPT;
|
||||
tp->tty_ioreq = m_ptr->REQUEST;
|
||||
tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m_ptr->TTY_REQUEST == TCDRAIN) break;
|
||||
if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
|
||||
if (m_ptr->REQUEST == TCDRAIN) break;
|
||||
if (m_ptr->REQUEST == TCSETSF) tty_icancel(tp);
|
||||
/*FALL THROUGH*/
|
||||
case TCSETS:
|
||||
/* Set the termios attributes. */
|
||||
|
|
@ -890,7 +814,8 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
}
|
||||
|
||||
/* Send the reply. */
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -906,7 +831,7 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
*/
|
||||
int r = OK;
|
||||
|
||||
if (m_ptr->TTY_LINE == LOG_MINOR) {
|
||||
if (m_ptr->DEVICE == LOG_MINOR) {
|
||||
/* The log device is a write-only diagnostics device. */
|
||||
if (m_ptr->COUNT & R_BIT) r = EACCES;
|
||||
} else {
|
||||
|
|
@ -920,7 +845,8 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
(*tp->tty_open)(tp, 0);
|
||||
}
|
||||
}
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
|
||||
tty_reply(DEV_OPEN_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -932,7 +858,7 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
{
|
||||
/* A tty line has been closed. Clean up the line if it is the last close. */
|
||||
|
||||
if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
|
||||
if (m_ptr->DEVICE != LOG_MINOR && --tp->tty_openct == 0) {
|
||||
tp->tty_pgrp = 0;
|
||||
tty_icancel(tp);
|
||||
(*tp->tty_ocancel)(tp, 0);
|
||||
|
|
@ -941,7 +867,8 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
tp->tty_winsize = winsize_defaults;
|
||||
setattr(tp);
|
||||
}
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, OK);
|
||||
tty_reply(DEV_CLOSE_REPL, m_ptr->m_source, m_ptr->USER_ENDPT,
|
||||
(cp_grant_id_t) m_ptr->IO_GRANT, OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -954,35 +881,39 @@ message *m_ptr; /* pointer to message sent to task */
|
|||
/* A signal has been sent to a process that is hanging trying to read or write.
|
||||
* The pending read or write must be finished off immediately.
|
||||
*/
|
||||
|
||||
int proc_nr;
|
||||
endpoint_t proc_nr;
|
||||
cp_grant_id_t grant;
|
||||
int mode;
|
||||
int r = EINTR;
|
||||
int r = EDONTREPLY;
|
||||
|
||||
/* Check the parameters carefully, to avoid cancelling twice. */
|
||||
proc_nr = m_ptr->USER_ENDPT;
|
||||
grant = (cp_grant_id_t) m_ptr->IO_GRANT;
|
||||
mode = m_ptr->COUNT;
|
||||
if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc &&
|
||||
tp->tty_ingrant == (cp_grant_id_t) m_ptr->IO_GRANT) {
|
||||
tp->tty_ingrant == grant) {
|
||||
/* Process was reading when killed. Clean up input. */
|
||||
tty_icancel(tp);
|
||||
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
|
||||
tp->tty_inleft = tp->tty_incum = tp->tty_inrevived = 0;
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc &&
|
||||
tp->tty_outgrant == (cp_grant_id_t) m_ptr->IO_GRANT) {
|
||||
tp->tty_outgrant == grant) {
|
||||
/* Process was writing when killed. Clean up output. */
|
||||
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
|
||||
tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0;
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outgrant = GRANT_INVALID;
|
||||
}
|
||||
if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
|
||||
/* Process was waiting for output to drain. */
|
||||
tp->tty_ioreq = 0;
|
||||
r = EINTR;
|
||||
}
|
||||
tp->tty_events = 1;
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, r);
|
||||
/* Only reply if we found a matching request. */
|
||||
if (r != EDONTREPLY)
|
||||
tty_reply(DEV_REVIVE, m_ptr->m_source, proc_nr, grant, r);
|
||||
}
|
||||
|
||||
int select_try(struct tty *tp, int ops)
|
||||
|
|
@ -1021,8 +952,14 @@ int select_try(struct tty *tp, int ops)
|
|||
|
||||
int select_retry(struct tty *tp)
|
||||
{
|
||||
if (tp->tty_select_ops && select_try(tp, tp->tty_select_ops))
|
||||
notify(tp->tty_select_proc);
|
||||
int ops;
|
||||
|
||||
if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) {
|
||||
assert(tp->tty_select_minor == tp->tty_minor);
|
||||
select_reply(DEV_SEL_REPL2, tp->tty_select_proc, tp->tty_minor,
|
||||
ops);
|
||||
tp->tty_select_ops &= ~ops;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -1064,16 +1001,10 @@ tty_t *tp; /* TTY to check for events. */
|
|||
|
||||
/* Reply if enough bytes are available. */
|
||||
if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
|
||||
if (tp->tty_inrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_incaller);
|
||||
tp->tty_inrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
|
||||
tp->tty_inproc, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_inrevived = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
if (tp->tty_select_ops)
|
||||
{
|
||||
|
|
@ -1146,16 +1077,10 @@ register tty_t *tp; /* pointer to terminal to read from */
|
|||
|
||||
/* Usually reply to the reader, possibly even if incum == 0 (EOF). */
|
||||
if (tp->tty_inleft == 0) {
|
||||
if (tp->tty_inrepcode == TTY_REVIVE) {
|
||||
notify(tp->tty_incaller);
|
||||
tp->tty_inrevived = 1;
|
||||
} else {
|
||||
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
|
||||
tp->tty_inproc, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_inrevived = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
tty_reply(DEV_REVIVE, tp->tty_incaller, tp->tty_inproc,
|
||||
tp->tty_ingrant, tp->tty_incum);
|
||||
tp->tty_inleft = tp->tty_incum = 0;
|
||||
tp->tty_ingrant = GRANT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1585,9 +1510,9 @@ tty_t *tp;
|
|||
if (result == OK) setattr(tp);
|
||||
}
|
||||
tp->tty_ioreq = 0;
|
||||
notify(tp->tty_iocaller);
|
||||
tp->tty_iorevived = 1;
|
||||
tp->tty_iostatus = result;
|
||||
tty_reply(DEV_REVIVE, tp->tty_iocaller, tp->tty_ioproc, tp->tty_iogrant,
|
||||
result);
|
||||
tp->tty_iogrant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -1651,25 +1576,52 @@ tty_t *tp;
|
|||
*===========================================================================*/
|
||||
void
|
||||
tty_reply_f(
|
||||
file, line, code, replyee, proc_nr, status)
|
||||
file, line, code, replyee, proc_nr, grant, status)
|
||||
char *file;
|
||||
int line;
|
||||
int code; /* TASK_REPLY or REVIVE */
|
||||
int replyee; /* destination address for the reply */
|
||||
int proc_nr; /* to whom should the reply go? */
|
||||
int code; /* DEV_OPEN_REPL, DEV_CLOSE_REPL, DEV_REVIVE */
|
||||
endpoint_t replyee; /* destination address for the reply */
|
||||
endpoint_t proc_nr; /* to whom should the reply go? */
|
||||
cp_grant_id_t grant; /* which grant was involved? */
|
||||
int status; /* reply code */
|
||||
{
|
||||
/* Send a reply to a process that wanted to read or write data. */
|
||||
assert(code == TASK_REPLY);
|
||||
message m;
|
||||
|
||||
assert(code == DEV_OPEN_REPL || code == DEV_CLOSE_REPL || code == DEV_REVIVE);
|
||||
|
||||
/* Don't reply to KERNEL (kernel messages) */
|
||||
if (replyee == KERNEL) return;
|
||||
|
||||
status = send_taskreply(replyee, proc_nr, status);
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
m.REP_ENDPT = proc_nr;
|
||||
m.REP_IO_GRANT = grant;
|
||||
m.REP_STATUS = status;
|
||||
|
||||
status = _sendcall(replyee, code, &m);
|
||||
if (status != OK)
|
||||
printf("tty`tty_reply: send to %d failed: %d\n", replyee, status);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_reply *
|
||||
*===========================================================================*/
|
||||
void select_reply(int code, endpoint_t replyee, dev_t minor, int ops)
|
||||
{
|
||||
message m;
|
||||
int status;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
m.DEV_MINOR = minor;
|
||||
m.DEV_SEL_OPS = ops;
|
||||
|
||||
status = _sendcall(replyee, code, &m);
|
||||
if (status != OK)
|
||||
printf("tty`select_reply: send to %d failed: %d\n", replyee, status);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* sigchar *
|
||||
*===========================================================================*/
|
||||
|
|
@ -1808,18 +1760,17 @@ register message *m_ptr; /* pointer to message sent to the task */
|
|||
{
|
||||
int ops, ready_ops = 0, watch;
|
||||
|
||||
ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m_ptr->USER_ENDPT & SEL_NOTIFY) ? 1 : 0;
|
||||
ops = m_ptr->DEV_SEL_OPS & (SEL_RD|SEL_WR|SEL_ERR);
|
||||
watch = (m_ptr->DEV_SEL_OPS & SEL_NOTIFY) ? 1 : 0;
|
||||
|
||||
ready_ops = select_try(tp, ops);
|
||||
|
||||
if (!ready_ops && ops && watch) {
|
||||
tp->tty_select_ops |= ops;
|
||||
tp->tty_select_proc = m_ptr->m_source;
|
||||
tp->tty_select_minor = m_ptr->DEV_MINOR;
|
||||
}
|
||||
|
||||
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, ready_ops);
|
||||
|
||||
return;
|
||||
assert(tp->tty_minor == m_ptr->DEV_MINOR);
|
||||
select_reply(DEV_SEL_REPL1, m_ptr->m_source, tp->tty_minor, ready_ops);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
#undef lock
|
||||
#undef unlock
|
||||
|
||||
#define TTY_REVIVE 6767
|
||||
|
||||
/* First minor numbers for the various classes of TTY devices. */
|
||||
#define CONS_MINOR 0
|
||||
#define LOG_MINOR 15
|
||||
|
|
@ -63,16 +61,12 @@ typedef struct tty {
|
|||
char tty_openct; /* count of number of opens of this tty */
|
||||
|
||||
/* Information about incomplete I/O requests is stored here. */
|
||||
int tty_inrepcode; /* reply code, TASK_REPLY or REVIVE */
|
||||
char tty_inrevived; /* set to 1 if revive callback is pending */
|
||||
endpoint_t tty_incaller; /* process that made the call (usually VFS) */
|
||||
endpoint_t tty_inproc; /* process that wants to read from tty */
|
||||
cp_grant_id_t tty_ingrant; /* grant where data is to go */
|
||||
vir_bytes tty_inoffset; /* offset into grant */
|
||||
int tty_inleft; /* how many chars are still needed */
|
||||
int tty_incum; /* # chars input so far */
|
||||
int tty_outrepcode; /* reply code, TASK_REPLY or REVIVE */
|
||||
int tty_outrevived; /* set to 1 if revive callback is pending */
|
||||
endpoint_t tty_outcaller; /* process that made the call (usually VFS) */
|
||||
endpoint_t tty_outproc; /* process that wants to write to tty */
|
||||
cp_grant_id_t tty_outgrant; /* grant where data comes from */
|
||||
|
|
@ -80,15 +74,14 @@ typedef struct tty {
|
|||
int tty_outleft; /* # chars yet to be output */
|
||||
int tty_outcum; /* # chars output so far */
|
||||
endpoint_t tty_iocaller; /* process that made the call (usually VFS) */
|
||||
int tty_iorevived; /* set to 1 if revive callback is pending */
|
||||
endpoint_t tty_ioproc; /* process that wants to do an ioctl */
|
||||
int tty_iostatus; /* result */
|
||||
int tty_ioreq; /* ioctl request code */
|
||||
cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */
|
||||
|
||||
/* select() data */
|
||||
int tty_select_ops; /* which operations are interesting */
|
||||
endpoint_t tty_select_proc; /* which process wants notification */
|
||||
dev_t tty_select_minor; /* sanity check only, can be removed */
|
||||
|
||||
/* Miscellaneous. */
|
||||
devfun_t tty_ioctl; /* set line speed, etc. at the device level */
|
||||
|
|
@ -146,9 +139,10 @@ int in_process(struct tty *tp, char *buf, int count, int scode);
|
|||
void out_process(struct tty *tp, char *bstart, char *bpos, char *bend,
|
||||
int *icount, int *ocount);
|
||||
void tty_wakeup(clock_t now);
|
||||
#define tty_reply(c, r, p, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (s))
|
||||
void tty_reply_f(char *f, int l, int code, int replyee, int proc_nr, int
|
||||
status);
|
||||
#define tty_reply(c, r, p, g, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (g), (s))
|
||||
void tty_reply_f(char *f, int l, int code, endpoint_t replyee,
|
||||
endpoint_t proc_nr, cp_grant_id_t grant, int status);
|
||||
void select_reply(int code, endpoint_t replyee, dev_t minor, int ops);
|
||||
int select_try(struct tty *tp, int ops);
|
||||
int select_retry(struct tty *tp);
|
||||
|
||||
|
|
@ -175,11 +169,8 @@ void kbd_interrupt(message *m);
|
|||
void do_kbd(message *m);
|
||||
void do_kb_inject(message *m);
|
||||
void do_kbdaux(message *m);
|
||||
int kbd_status(message *m_ptr);
|
||||
|
||||
/* pty.c */
|
||||
void do_pty(struct tty *tp, message *m_ptr);
|
||||
void pty_init(struct tty *tp);
|
||||
void select_retry_pty(struct tty *tp);
|
||||
int pty_status(message *m_ptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ kill_by_name syslogd
|
|||
sleep 3
|
||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||
then
|
||||
service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A
|
||||
service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
|
||||
dhcpd --lwip &
|
||||
else
|
||||
service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ start)
|
|||
|
||||
# Start servers and drivers set at the boot monitor.
|
||||
echo -n "Starting services:"
|
||||
up -n random -dev /dev/random -devstyle STYLE_DEVA -period 3HZ
|
||||
up -n random -dev /dev/random -period 3HZ
|
||||
|
||||
# load random number generator
|
||||
if [ -f $RANDOM_FILE ]
|
||||
|
|
@ -188,9 +188,9 @@ start)
|
|||
done
|
||||
if [ X`/bin/sysenv lwip` = Xyes ]
|
||||
then
|
||||
up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A
|
||||
up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
|
||||
else
|
||||
up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
|
||||
up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE
|
||||
fi
|
||||
|
||||
up -n ipc
|
||||
|
|
|
|||
|
|
@ -109,8 +109,5 @@
|
|||
|
||||
#define VFS_VMCALL 117
|
||||
|
||||
#define TASK_REPLY 121 /* to VFS: reply code from drivers, not
|
||||
* really a standalone call.
|
||||
*/
|
||||
#define MAPDRIVER 122 /* to VFS, map a device */
|
||||
#define GETRUSAGE 123 /* to PM, VFS */
|
||||
|
|
|
|||
|
|
@ -19,17 +19,12 @@ struct chardriver {
|
|||
int(*cdr_other) (message *m_ptr);
|
||||
};
|
||||
|
||||
#define CHARDRIVER_SYNC 0 /* use the synchronous protocol */
|
||||
#define CHARDRIVER_ASYNC 1 /* use the asynchronous protocol */
|
||||
|
||||
#define IS_CDEV_MINOR_RQ(type) (IS_DEV_RQ(type) && (type) != DEV_STATUS)
|
||||
|
||||
/* Functions defined by libchardriver. */
|
||||
void chardriver_announce(void);
|
||||
void chardriver_process(struct chardriver *cdp, int driver_type, message
|
||||
*m_ptr, int ipc_status);
|
||||
void chardriver_process(struct chardriver *cdp, message *m_ptr,
|
||||
int ipc_status);
|
||||
void chardriver_terminate(void);
|
||||
void chardriver_task(struct chardriver *cdp, int driver_type);
|
||||
void chardriver_task(struct chardriver *cdp);
|
||||
|
||||
int do_nop(message *m_ptr);
|
||||
void nop_cleanup(void);
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@
|
|||
#define DEV_OPEN (DEV_RQ_BASE + 6) /* open a minor device */
|
||||
#define DEV_CLOSE (DEV_RQ_BASE + 7) /* close a minor device */
|
||||
#define DEV_SELECT (DEV_RQ_BASE + 12) /* request select() attention */
|
||||
#define DEV_STATUS (DEV_RQ_BASE + 13) /* request driver status */
|
||||
#define DEV_REOPEN (DEV_RQ_BASE + 14) /* reopen a minor device */
|
||||
|
||||
#define DEV_READ_S (DEV_RQ_BASE + 20) /* (safecopy) read from minor */
|
||||
|
|
@ -208,8 +207,6 @@
|
|||
#define IS_DEV_RQ(type) (((type) & ~0xff) == DEV_RQ_BASE)
|
||||
|
||||
#define DEV_REVIVE (DEV_RS_BASE + 2) /* driver revives process */
|
||||
#define DEV_IO_READY (DEV_RS_BASE + 3) /* selected device ready */
|
||||
#define DEV_NO_STATUS (DEV_RS_BASE + 4) /* empty status reply */
|
||||
#define DEV_REOPEN_REPL (DEV_RS_BASE + 5) /* reply to DEV_REOPEN */
|
||||
#define DEV_CLOSE_REPL (DEV_RS_BASE + 6) /* reply to DEV_CLOSE */
|
||||
#define DEV_SEL_REPL1 (DEV_RS_BASE + 7) /* first reply to DEV_SELECT */
|
||||
|
|
@ -241,12 +238,6 @@
|
|||
#define REP_IO_GRANT m2_i3 /* DEV_REVIVE: grant by which I/O was done */
|
||||
# define SUSPEND -998 /* status to suspend caller, reply later */
|
||||
|
||||
/* Field names for messages to TTY driver. */
|
||||
#define TTY_LINE DEVICE /* message parameter: terminal line */
|
||||
#define TTY_REQUEST COUNT /* message parameter: ioctl request code */
|
||||
#define TTY_SPEK POSITION/* message parameter: ioctl speed, erasing */
|
||||
#define TTY_PGRP m2_i3 /* message parameter: process group */
|
||||
|
||||
/*===========================================================================*
|
||||
* Messages for networking layer *
|
||||
*===========================================================================*/
|
||||
|
|
@ -825,7 +816,6 @@
|
|||
|
||||
/* Additional parameters for PM_DUMPCORE */
|
||||
# define PM_TERM_SIG m7_i2 /* process's termination signal */
|
||||
# define PM_TRACED_PROC m7_i3 /* required for T_DUMPCORE */
|
||||
|
||||
/* Parameters for the EXEC_NEWMEM call */
|
||||
#define EXC_NM_PROC m1_i1 /* process that needs new map */
|
||||
|
|
@ -911,6 +901,11 @@
|
|||
#define STATVFS_NAME m1_p1
|
||||
#define STATVFS_BUF m1_p2
|
||||
|
||||
/* Field names for the ioctl(2) call. */
|
||||
#define VFS_IOCTL_FD m2_i1
|
||||
#define VFS_IOCTL_REQ m2_i3
|
||||
#define VFS_IOCTL_ARG m2_p1
|
||||
|
||||
/*===========================================================================*
|
||||
* Messages for VM server *
|
||||
*===========================================================================*/
|
||||
|
|
|
|||
|
|
@ -4,12 +4,8 @@
|
|||
#include <minix/sys_config.h>
|
||||
#include <minix/ipc.h>
|
||||
|
||||
enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
|
||||
STYLE_CLONE, STYLE_CLONE_A };
|
||||
#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE_A)
|
||||
|
||||
#define dev_style_asyn(devstyle) ((devstyle) == STYLE_DEVA || \
|
||||
(devstyle) == STYLE_CLONE_A)
|
||||
enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY, STYLE_CLONE };
|
||||
#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE)
|
||||
|
||||
/*===========================================================================*
|
||||
* Major and minor device numbers *
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#define FSTATE_LOCK 'L'
|
||||
#define FSTATE_POPEN 'O'
|
||||
#define FSTATE_SELECT 'S'
|
||||
#define FSTATE_DOPEN 'D'
|
||||
#define FSTATE_TASK 'T'
|
||||
#define FSTATE_UNKNOWN '?'
|
||||
|
||||
|
|
|
|||
|
|
@ -159,8 +159,6 @@ int sys_umap_data_fb(endpoint_t proc_ep, vir_bytes vir_addr, vir_bytes
|
|||
int sys_umap_remote(endpoint_t proc_ep, endpoint_t grantee, int seg,
|
||||
vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr);
|
||||
|
||||
int send_taskreply(endpoint_t who, endpoint_t endpoint, int status);
|
||||
|
||||
/* Shorthands for sys_getinfo() system call. */
|
||||
#define sys_getkinfo(dst) sys_getinfo(GET_KINFO, dst, 0,0,0)
|
||||
#define sys_getloadinfo(dst) sys_getinfo(GET_LOADINFO, dst, 0,0,0)
|
||||
|
|
|
|||
|
|
@ -20,11 +20,7 @@
|
|||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_IOCTL_S | device | proc nr |func code| | buf ptr |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_STATUS | | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | HARD_INT | | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | SIG_STOP | | | | | |
|
||||
* -----------------------------------------------------------------
|
||||
*
|
||||
* The file contains one entry point:
|
||||
|
|
@ -81,7 +77,6 @@ static void sef_cb_signal_handler(int signo);
|
|||
EXTERN int sef_cb_lu_prepare(int state);
|
||||
EXTERN int sef_cb_lu_state_isvalid(int state);
|
||||
EXTERN void sef_cb_lu_state_dump(int state);
|
||||
int is_status_msg_expected = FALSE;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -121,8 +116,10 @@ int main(void)
|
|||
case DEV_OPEN:
|
||||
/* open the special file ( = parameter) */
|
||||
r = msg_open(mess.DEVICE);
|
||||
repl_mess.m_type = DEV_REVIVE;
|
||||
repl_mess.m_type = DEV_OPEN_REPL;
|
||||
repl_mess.REP_ENDPT = mess.USER_ENDPT;
|
||||
repl_mess.REP_IO_GRANT =
|
||||
(cp_grant_id_t) mess.IO_GRANT;
|
||||
repl_mess.REP_STATUS = r;
|
||||
send(caller, &repl_mess);
|
||||
|
||||
|
|
@ -133,6 +130,8 @@ int main(void)
|
|||
r = msg_close(mess.DEVICE);
|
||||
repl_mess.m_type = DEV_CLOSE_REPL;
|
||||
repl_mess.REP_ENDPT = mess.USER_ENDPT;
|
||||
repl_mess.REP_IO_GRANT =
|
||||
(cp_grant_id_t) mess.IO_GRANT;
|
||||
repl_mess.REP_STATUS = r;
|
||||
send(caller, &repl_mess);
|
||||
|
||||
|
|
@ -146,7 +145,7 @@ int main(void)
|
|||
repl_mess.m_type = DEV_REVIVE;
|
||||
repl_mess.REP_ENDPT = mess.USER_ENDPT;
|
||||
repl_mess.REP_IO_GRANT =
|
||||
(unsigned)mess.IO_GRANT;
|
||||
(cp_grant_id_t) mess.IO_GRANT;
|
||||
repl_mess.REP_STATUS = r;
|
||||
send(caller, &repl_mess);
|
||||
}
|
||||
|
|
@ -156,13 +155,13 @@ int main(void)
|
|||
msg_read(&mess); continue; /* don't reply */
|
||||
case DEV_WRITE_S:
|
||||
msg_write(&mess); continue; /* don't reply */
|
||||
case DEV_STATUS:
|
||||
msg_status(&mess);continue; /* don't reply */
|
||||
case DEV_REOPEN:
|
||||
/* reopen the special file ( = parameter) */
|
||||
r = msg_open(mess.DEVICE);
|
||||
repl_mess.m_type = DEV_REOPEN_REPL;
|
||||
repl_mess.REP_ENDPT = mess.USER_ENDPT;
|
||||
repl_mess.REP_IO_GRANT =
|
||||
(cp_grant_id_t) mess.IO_GRANT;
|
||||
repl_mess.REP_STATUS = r;
|
||||
send(caller, &repl_mess);
|
||||
continue;
|
||||
|
|
@ -626,35 +625,6 @@ static void msg_hardware(void) {
|
|||
}
|
||||
|
||||
|
||||
static void msg_status(message *m_ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < drv.NrOfSubDevices; i++) {
|
||||
|
||||
if(sub_dev[i].ReadyToRevive)
|
||||
{
|
||||
m_ptr->m_type = DEV_REVIVE; /* build message */
|
||||
m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr;
|
||||
m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant;
|
||||
m_ptr->REP_STATUS = sub_dev[i].ReviveStatus;
|
||||
send(m_ptr->m_source, m_ptr); /* send the message */
|
||||
|
||||
/* reset variables */
|
||||
sub_dev[i].ReadyToRevive = FALSE;
|
||||
sub_dev[i].RevivePending = 0;
|
||||
|
||||
is_status_msg_expected = TRUE;
|
||||
return; /* stop after one mess,
|
||||
file system will get back for other processes */
|
||||
}
|
||||
}
|
||||
m_ptr->m_type = DEV_NO_STATUS;
|
||||
m_ptr->REP_STATUS = 0;
|
||||
send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */
|
||||
is_status_msg_expected = FALSE;
|
||||
}
|
||||
|
||||
/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/
|
||||
static void handle_int_write(int sub_dev_nr)
|
||||
{
|
||||
|
|
@ -712,6 +682,7 @@ static void handle_int_write(int sub_dev_nr)
|
|||
static void handle_int_read(int sub_dev_nr)
|
||||
{
|
||||
sub_dev_t *sub_dev_ptr;
|
||||
message m;
|
||||
|
||||
sub_dev_ptr = &sub_dev[sub_dev_nr];
|
||||
|
||||
|
|
@ -729,9 +700,14 @@ static void handle_int_read(int sub_dev_nr)
|
|||
printf("All buffers full, we have a problem.\n");
|
||||
drv_stop(sub_dev_nr); /* stop the sub device */
|
||||
sub_dev_ptr->DmaBusy = FALSE;
|
||||
sub_dev_ptr->ReviveStatus = 0; /* no data for user,
|
||||
this is a sad story */
|
||||
sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */
|
||||
sub_dev_ptr->ReviveStatus = 0; /* no data for user,
|
||||
* this is a sad story
|
||||
*/
|
||||
m.m_type = DEV_REVIVE;
|
||||
m.REP_ENDPT = sub_dev_ptr->ReviveProcNr;
|
||||
m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant;
|
||||
m.REP_STATUS = sub_dev_ptr->ReviveStatus;
|
||||
send(sub_dev_ptr->SourceProcNr, &m);
|
||||
return;
|
||||
}
|
||||
else { /* dma full, still room in extra buf;
|
||||
|
|
@ -790,9 +766,6 @@ static void data_from_user(sub_dev_t *subdev)
|
|||
|
||||
if (!subdev->RevivePending) return; /* no new data waiting to be copied */
|
||||
|
||||
if (subdev->RevivePending &&
|
||||
subdev->ReadyToRevive) return; /* we already got this data */
|
||||
|
||||
if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */
|
||||
|
||||
r = sys_safecopyfrom(subdev->SourceProcNr,
|
||||
|
|
@ -835,7 +808,6 @@ static void data_from_user(sub_dev_t *subdev)
|
|||
}
|
||||
|
||||
subdev->ReviveStatus = subdev->FragSize;
|
||||
subdev->ReadyToRevive = TRUE;
|
||||
|
||||
m.m_type = DEV_REVIVE; /* build message */
|
||||
m.REP_ENDPT = subdev->ReviveProcNr;
|
||||
|
|
@ -849,7 +821,6 @@ static void data_from_user(sub_dev_t *subdev)
|
|||
}
|
||||
|
||||
/* reset variables */
|
||||
subdev->ReadyToRevive = FALSE;
|
||||
subdev->RevivePending = 0;
|
||||
}
|
||||
|
||||
|
|
@ -860,7 +831,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr)
|
|||
message m;
|
||||
|
||||
if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */
|
||||
if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */
|
||||
if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return;
|
||||
/* no data for user */
|
||||
|
||||
|
|
@ -896,7 +866,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr)
|
|||
}
|
||||
|
||||
sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize;
|
||||
sub_dev_ptr->ReadyToRevive = TRUE;
|
||||
/* drv_status will send REVIVE mess to FS*/
|
||||
|
||||
m.m_type = DEV_REVIVE; /* build message */
|
||||
|
|
@ -911,7 +880,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr)
|
|||
}
|
||||
|
||||
/* reset variables */
|
||||
sub_dev_ptr->ReadyToRevive = FALSE;
|
||||
sub_dev_ptr->RevivePending = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
#include <minix/audio_fw.h>
|
||||
|
||||
/* State management variables. */
|
||||
EXTERN int is_status_msg_expected;
|
||||
/*
|
||||
* - From audio_fw.h:
|
||||
* EXTERN drv_t drv;
|
||||
|
|
@ -60,8 +58,7 @@ int sef_cb_lu_prepare(int state)
|
|||
break;
|
||||
|
||||
case SEF_LU_STATE_PROTOCOL_FREE:
|
||||
is_ready = (!is_read_pending && !is_write_pending
|
||||
&& !is_status_msg_expected);
|
||||
is_ready = (!is_read_pending && !is_write_pending);
|
||||
break;
|
||||
|
||||
/* Custom states. */
|
||||
|
|
@ -95,8 +92,6 @@ void sef_cb_lu_state_dump(int state)
|
|||
load_state_info();
|
||||
|
||||
sef_lu_dprint("audio: live update state = %d\n", state);
|
||||
sef_lu_dprint("audio: is_status_msg_expected = %d\n",
|
||||
is_status_msg_expected);
|
||||
sef_lu_dprint("audio: is_read_pending = %d\n", is_read_pending);
|
||||
sef_lu_dprint("audio: is_write_pending = %d\n", is_write_pending);
|
||||
|
||||
|
|
@ -105,8 +100,7 @@ void sef_cb_lu_state_dump(int state)
|
|||
sef_lu_dprint("audio: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_REQUEST_FREE, (!is_read_pending && !is_write_pending));
|
||||
sef_lu_dprint("audio: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending
|
||||
&& !is_status_msg_expected));
|
||||
SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending));
|
||||
sef_lu_dprint("audio: AUDIO_STATE_READ_REQUEST_FREE(%d) reached = %d\n",
|
||||
AUDIO_STATE_READ_REQUEST_FREE, (!is_read_pending));
|
||||
sef_lu_dprint("audio: AUDIO_STATE_WRITE_REQUEST_FREE(%d) reached = %d\n",
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ void *data;
|
|||
break;
|
||||
}
|
||||
|
||||
m.TTY_LINE = fd;
|
||||
m.TTY_REQUEST = request;
|
||||
m.ADDRESS = (char *) addr;
|
||||
m.VFS_IOCTL_FD = fd;
|
||||
m.VFS_IOCTL_REQ = request;
|
||||
m.VFS_IOCTL_ARG = (char *) addr;
|
||||
|
||||
r = _syscall(VFS_PROC_NR, IOCTL, &m);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
* driver_receive: message receive interface for drivers
|
||||
*
|
||||
* Changes:
|
||||
* Oct 20, 2013 retire synchronous protocol (D.C. van Moolenbroek)
|
||||
* Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek)
|
||||
* Aug 27, 2011 move common functions into driver.c (A. Welzel)
|
||||
* Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder)
|
||||
|
|
@ -117,16 +118,19 @@ void chardriver_announce(void)
|
|||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* async_reply *
|
||||
* send_reply *
|
||||
*===========================================================================*/
|
||||
static void async_reply(message *mess, int r)
|
||||
static void send_reply(message *mess, int ipc_status, int r)
|
||||
{
|
||||
/* Send a reply using the asynchronous character device protocol. */
|
||||
/* Prepare and send a reply message. */
|
||||
message reply_mess;
|
||||
|
||||
/* Do not reply with ERESTART in this protocol. The only possible caller,
|
||||
* VFS, will find out through other means when we have restarted, and is not
|
||||
* (fully) ready to deal with ERESTART errors.
|
||||
if (r == EDONTREPLY)
|
||||
return;
|
||||
|
||||
/* Do not reply with ERESTART. The only possible caller, VFS, will find out
|
||||
* through other means when we have restarted, and is not (fully) ready to
|
||||
* deal with ERESTART errors.
|
||||
*/
|
||||
if (r == ERESTART)
|
||||
return;
|
||||
|
|
@ -150,7 +154,7 @@ static void async_reply(message *mess, int r)
|
|||
case DEV_WRITE_S:
|
||||
case DEV_IOCTL_S:
|
||||
if (r == SUSPEND)
|
||||
printf("driver_task: reviving %d (%d) with SUSPEND\n",
|
||||
printf("chardriver_task: reviving %d (%d) with SUSPEND\n",
|
||||
mess->m_source, mess->USER_ENDPT);
|
||||
|
||||
reply_mess.m_type = DEV_REVIVE;
|
||||
|
|
@ -170,60 +174,22 @@ static void async_reply(message *mess, int r)
|
|||
break;
|
||||
|
||||
default:
|
||||
reply_mess.m_type = TASK_REPLY;
|
||||
reply_mess.m_type = DEV_REVIVE;
|
||||
reply_mess.REP_ENDPT = mess->USER_ENDPT;
|
||||
/* Status is # of bytes transferred or error code. */
|
||||
reply_mess.REP_STATUS = r;
|
||||
break;
|
||||
}
|
||||
|
||||
r = asynsend(mess->m_source, &reply_mess);
|
||||
|
||||
if (r != OK)
|
||||
printf("asyn_reply: unable to asynsend reply to %d: %d\n",
|
||||
mess->m_source, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sync_reply *
|
||||
*===========================================================================*/
|
||||
static void sync_reply(message *m_ptr, int ipc_status, int reply)
|
||||
{
|
||||
/* Reply to a message sent to the driver. */
|
||||
endpoint_t caller_e, user_e;
|
||||
int r;
|
||||
|
||||
caller_e = m_ptr->m_source;
|
||||
user_e = m_ptr->USER_ENDPT;
|
||||
|
||||
m_ptr->m_type = TASK_REPLY;
|
||||
m_ptr->REP_ENDPT = user_e;
|
||||
m_ptr->REP_STATUS = reply;
|
||||
|
||||
/* If we would block sending the message, send it asynchronously. */
|
||||
if (IPC_STATUS_CALL(ipc_status) == SENDREC)
|
||||
r = sendnb(caller_e, m_ptr);
|
||||
r = sendnb(mess->m_source, &reply_mess);
|
||||
else
|
||||
r = asynsend(caller_e, m_ptr);
|
||||
r = asynsend3(mess->m_source, &reply_mess, AMF_NOREPLY);
|
||||
|
||||
if (r != OK)
|
||||
printf("driver_reply: unable to send reply to %d: %d\n", caller_e, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* send_reply *
|
||||
*===========================================================================*/
|
||||
static void send_reply(int type, message *m_ptr, int ipc_status, int reply)
|
||||
{
|
||||
/* Prepare and send a reply message. */
|
||||
|
||||
if (reply == EDONTREPLY)
|
||||
return;
|
||||
|
||||
if (type == CHARDRIVER_ASYNC)
|
||||
async_reply(m_ptr, reply);
|
||||
else
|
||||
sync_reply(m_ptr, ipc_status, reply);
|
||||
printf("send_reply: unable to send reply to %d: %d\n",
|
||||
mess->m_source, r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -343,7 +309,7 @@ static int handle_request(struct chardriver *cdp, message *m_ptr)
|
|||
* requests on devices that have not previously been opened, signaling the
|
||||
* caller that something went wrong.
|
||||
*/
|
||||
if (IS_CDEV_MINOR_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
|
||||
if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
|
||||
/* Reply ERESTART to spurious requests for unopened devices. */
|
||||
if (m_ptr->m_type != DEV_OPEN)
|
||||
return ERESTART;
|
||||
|
|
@ -380,8 +346,7 @@ static int handle_request(struct chardriver *cdp, message *m_ptr)
|
|||
/*===========================================================================*
|
||||
* chardriver_process *
|
||||
*===========================================================================*/
|
||||
void chardriver_process(struct chardriver *cdp, int driver_type,
|
||||
message *m_ptr, int ipc_status)
|
||||
void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
|
||||
{
|
||||
/* Handle the given received message. */
|
||||
int r;
|
||||
|
|
@ -394,14 +359,14 @@ void chardriver_process(struct chardriver *cdp, int driver_type,
|
|||
} else {
|
||||
r = handle_request(cdp, m_ptr);
|
||||
|
||||
send_reply(driver_type, m_ptr, ipc_status, r);
|
||||
send_reply(m_ptr, ipc_status, r);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* chardriver_task *
|
||||
*===========================================================================*/
|
||||
void chardriver_task(struct chardriver *cdp, int driver_type)
|
||||
void chardriver_task(struct chardriver *cdp)
|
||||
{
|
||||
/* Main program of any device driver task. */
|
||||
int r, ipc_status;
|
||||
|
|
@ -416,7 +381,7 @@ void chardriver_task(struct chardriver *cdp, int driver_type)
|
|||
if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK)
|
||||
panic("driver_receive failed: %d", r);
|
||||
|
||||
chardriver_process(cdp, driver_type, &mess, ipc_status);
|
||||
chardriver_process(cdp, &mess, ipc_status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,19 +93,14 @@ _ddekit_minix_queue_msg (
|
|||
full = ddekit_sem_down_try(mq->msg_w_sem);
|
||||
|
||||
if (full) {
|
||||
/* Our message queue is full... inform the sender. */
|
||||
/* Our message queue is full... */
|
||||
int result;
|
||||
DDEBUG_MSG_WARN("Receive queue is full. Ommiting ingoing msg.\n");
|
||||
|
||||
m->m_type = TASK_REPLY;
|
||||
m->REP_STATUS = EAGAIN;
|
||||
result = asynsend(m->m_source, m);
|
||||
|
||||
if (result != 0) {
|
||||
ddekit_panic("unable to send reply to %d: %d\n",
|
||||
m->m_source, result);
|
||||
}
|
||||
DDEBUG_MSG_WARN("Receive queue is full. Dropping request.\n");
|
||||
|
||||
/* XXX should reply to the sender with EIO or so, but for that
|
||||
* we would need to look at the request and find a suitable
|
||||
* reply code..
|
||||
*/
|
||||
} else {
|
||||
/* queue the message */
|
||||
memcpy(&mq->messages[mq->msg_w_pos], m, sizeof(message));
|
||||
|
|
|
|||
|
|
@ -122,10 +122,14 @@ void mthread_stacktrace(mthread_thread_t t)
|
|||
mcontext_t *mtx;
|
||||
struct stackframe_s *frame;
|
||||
|
||||
printf("thread %d: ", t);
|
||||
|
||||
tcb = mthread_find_tcb(t);
|
||||
ctx = &tcb->m_context;
|
||||
|
||||
if (t != MAIN_THREAD && ctx->uc_stack.ss_size == 0)
|
||||
return; /* no stack, no stacktrace */
|
||||
|
||||
printf("thread %d: ", t);
|
||||
|
||||
mtx = &ctx->uc_mcontext;
|
||||
frame = &mtx->mc_p_reg;
|
||||
bp = frame->fp;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ SRCS+= \
|
|||
sys_vsafecopy.c \
|
||||
sys_vtimer.c \
|
||||
sys_vumap.c \
|
||||
send_taskreply.c \
|
||||
taskcall.c \
|
||||
tickdelay.c \
|
||||
timers.c \
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "syslib.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* sys_taskreply *
|
||||
*===========================================================================*/
|
||||
int send_taskreply(endpoint_t who, endpoint_t endpoint, int status)
|
||||
{
|
||||
message m;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
|
||||
m.REP_ENDPT = endpoint;
|
||||
m.REP_STATUS = status;
|
||||
|
||||
return _sendcall(who, TASK_REPLY, &m);
|
||||
}
|
||||
|
||||
|
|
@ -3,8 +3,7 @@ MAN= ash.1 at.1 \
|
|||
chmod.1 cmp.1 comm.1 compress.1 \
|
||||
cp.1 crc.1 crontab.1 dd.1 \
|
||||
df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \
|
||||
dumpcore.1 eject.1 \
|
||||
env.1 factor.1 \
|
||||
eject.1 env.1 factor.1 \
|
||||
flexdoc.1 fold.1 format.1 fortune.1 \
|
||||
fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \
|
||||
isodir.1 isoinfo.1 isoread.1 \
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
.TH DUMPCORE 1
|
||||
.SH NAME
|
||||
dumpcore \- generate core file of running process
|
||||
.SH SYNOPSIS
|
||||
dumpcore \fIpid\fR
|
||||
.br
|
||||
.de FL
|
||||
.TP
|
||||
\\fB\\$1\\fR
|
||||
\\$2
|
||||
..
|
||||
.de EX
|
||||
.TP 20
|
||||
\\fB\\$1\\fR
|
||||
# \\$2
|
||||
..
|
||||
.SH DESCRIPTION
|
||||
The \fBdumpcore\fR utility generates a core file for a running process, based
|
||||
on that process's process ID (\fIpid\fP). The resulting core file will be
|
||||
stored under the name "core" in the current working directory. Any previous
|
||||
file with that name will be overwritten.
|
||||
.PP
|
||||
The resulting core file can be used with for example
|
||||
.BR mdb (1).
|
||||
.SH BUGS
|
||||
The process of generating the core file is currently very rudimentary, and
|
||||
the generated core file does not contain for example memory mapped areas.
|
||||
.SH "SEE ALSO"
|
||||
.BR mdb (1).
|
||||
|
|
@ -25,31 +25,10 @@
|
|||
* | DEV_SELECT | minor dev | ops | | |
|
||||
* |-------------+-----------+-----------+-----------+-----------|
|
||||
*
|
||||
* m_type
|
||||
* --------------|
|
||||
* | DEV_STATUS |
|
||||
* |-------------|
|
||||
*
|
||||
* m_type DEVICE USER_ENDPT COUNT
|
||||
* --------------------------------------------------|
|
||||
* | CANCEL | minor dev | proc nr | mode |
|
||||
* |-------------+-----------+-----------+-----------|
|
||||
*
|
||||
* Replies:
|
||||
*
|
||||
* m_type REP_ENDPT REP_STATUS REP_IO_GRANT
|
||||
* -------------------------------------------------------|
|
||||
* | TASK_REPLY | proc nr | status | grant ID |
|
||||
* |---------------+-----------+-----------+--------------|
|
||||
*
|
||||
* m_type REP_ENDPT REP_STATUS REP_IO_GRANT
|
||||
* ----------------+-----------+--------------------------|
|
||||
* | DEV_REVIVE | proc nr | | grant ID |
|
||||
* |---------------+-----------+-----------+--------------|
|
||||
* | DEV_IO_READY | minor dev | sel ops | |
|
||||
* |---------------+-----------+-----------+--------------|
|
||||
* | DEV_NO_STATUS | | | |
|
||||
* |---------------+-----------+-----------+--------------|
|
||||
*/
|
||||
|
||||
#include "inet.h"
|
||||
|
|
@ -72,7 +51,6 @@ THIS_FILE
|
|||
|
||||
sr_fd_t sr_fd_table[FD_NR];
|
||||
|
||||
static mq_t *repl_queue, *repl_queue_tail;
|
||||
static struct vscp_vec s_cp_req[SCPVEC_NR];
|
||||
|
||||
static int sr_open(message *m);
|
||||
|
|
@ -82,16 +60,14 @@ static int sr_restart_read(sr_fd_t *fdp);
|
|||
static int sr_restart_write(sr_fd_t *fdp);
|
||||
static int sr_restart_ioctl(sr_fd_t *fdp);
|
||||
static int sr_cancel(message *m);
|
||||
static int sr_select(message *m);
|
||||
static void sr_status(message *m);
|
||||
static void sr_reply_(mq_t *m, int reply, int is_revive);
|
||||
static void sr_select(message *m);
|
||||
static void sr_reply_(mq_t *m, int code, int reply, int is_revive);
|
||||
static sr_fd_t *sr_getchannel(int minor);
|
||||
static acc_t *sr_get_userdata(int fd, size_t offset, size_t count, int
|
||||
for_ioctl);
|
||||
static int sr_put_userdata(int fd, size_t offset, acc_t *data, int
|
||||
for_ioctl);
|
||||
static void sr_select_res(int fd, unsigned ops);
|
||||
static int sr_repl_queue(int proc, int ref, int operation);
|
||||
static int walk_queue(sr_fd_t *sr_fd, mq_t **q_head_ptr, mq_t
|
||||
**q_tail_ptr, int type, int proc_nr, int ref, int first_flag);
|
||||
static void sr_event(event_t *evp, ev_arg_t arg);
|
||||
|
|
@ -111,44 +87,26 @@ void sr_init()
|
|||
ev_init(&sr_fd_table[i].srf_read_ev);
|
||||
ev_init(&sr_fd_table[i].srf_write_ev);
|
||||
}
|
||||
repl_queue= NULL;
|
||||
}
|
||||
|
||||
void sr_rec(m)
|
||||
mq_t *m;
|
||||
{
|
||||
int result;
|
||||
int code = DEV_REVIVE, result;
|
||||
int send_reply = 0, free_mess = 0;
|
||||
|
||||
if (repl_queue)
|
||||
{
|
||||
if (m->mq_mess.m_type == CANCEL)
|
||||
{
|
||||
result= sr_repl_queue(m->mq_mess.USER_ENDPT,
|
||||
(int)m->mq_mess.IO_GRANT, 0);
|
||||
|
||||
if (result)
|
||||
{
|
||||
mq_free(m);
|
||||
return; /* canceled request in queue */
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
sr_repl_queue(ANY, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (m->mq_mess.m_type)
|
||||
{
|
||||
case DEV_OPEN:
|
||||
result= sr_open(&m->mq_mess);
|
||||
code= DEV_OPEN_REPL;
|
||||
send_reply= 1;
|
||||
free_mess= 1;
|
||||
break;
|
||||
case DEV_CLOSE:
|
||||
sr_close(&m->mq_mess);
|
||||
result= OK;
|
||||
code= DEV_CLOSE_REPL;
|
||||
send_reply= 1;
|
||||
free_mess= 1;
|
||||
break;
|
||||
|
|
@ -156,25 +114,19 @@ mq_t *m;
|
|||
case DEV_WRITE_S:
|
||||
case DEV_IOCTL_S:
|
||||
result= sr_rwio(m);
|
||||
assert(result == OK || result == SUSPEND);
|
||||
send_reply= (result == SUSPEND);
|
||||
free_mess= 0;
|
||||
assert(result == OK || result == EAGAIN || result == EINTR ||
|
||||
result == SUSPEND);
|
||||
send_reply= (result == EAGAIN);
|
||||
free_mess= (result == EAGAIN);
|
||||
break;
|
||||
case CANCEL:
|
||||
result= sr_cancel(&m->mq_mess);
|
||||
assert(result == OK || result == EINTR);
|
||||
assert(result == OK || result == EINTR || result == SUSPEND);
|
||||
send_reply= (result == EINTR);
|
||||
free_mess= 1;
|
||||
m->mq_mess.m_type= 0;
|
||||
break;
|
||||
case DEV_SELECT:
|
||||
result= sr_select(&m->mq_mess);
|
||||
send_reply= 1;
|
||||
free_mess= 1;
|
||||
break;
|
||||
case DEV_STATUS:
|
||||
sr_status(&m->mq_mess);
|
||||
result= OK; /* Satisfy lint. */
|
||||
sr_select(&m->mq_mess);
|
||||
send_reply= 0;
|
||||
free_mess= 1;
|
||||
break;
|
||||
|
|
@ -184,7 +136,7 @@ mq_t *m;
|
|||
}
|
||||
if (send_reply)
|
||||
{
|
||||
sr_reply_(m, result, FALSE /* !is_revive */);
|
||||
sr_reply_(m, code, result, FALSE /* !is_revive */);
|
||||
}
|
||||
if (free_mess)
|
||||
mq_free(m);
|
||||
|
|
@ -323,6 +275,9 @@ mq_t *m;
|
|||
assert(sr_fd->srf_flags & susp_flag);
|
||||
assert(*q_head_ptr);
|
||||
|
||||
if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK)
|
||||
return EAGAIN;
|
||||
|
||||
(*q_tail_ptr)->mq_next= m;
|
||||
*q_tail_ptr= m;
|
||||
return SUSPEND;
|
||||
|
|
@ -368,9 +323,14 @@ mq_t *m;
|
|||
|
||||
assert(r == OK || r == SUSPEND ||
|
||||
(printf("r= %d\n", r), 0));
|
||||
if (r == SUSPEND)
|
||||
if (r == SUSPEND) {
|
||||
sr_fd->srf_flags |= susp_flag;
|
||||
else
|
||||
if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK) {
|
||||
r= sr_cancel(&m->mq_mess);
|
||||
assert(r == OK); /* must have been head of queue */
|
||||
return EINTR;
|
||||
}
|
||||
} else
|
||||
mq_free(m);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -460,7 +420,6 @@ message *m;
|
|||
int result;
|
||||
int proc_nr, ref;
|
||||
|
||||
result=EINTR;
|
||||
proc_nr= m->USER_ENDPT;
|
||||
ref= (int)m->IO_GRANT;
|
||||
sr_fd= sr_getchannel(m->DEVICE);
|
||||
|
|
@ -484,27 +443,24 @@ message *m;
|
|||
if (result != EAGAIN)
|
||||
return result;
|
||||
|
||||
ip_panic((
|
||||
"request not found: from %d, type %d, MINOR= %d, PROC= %d, REF= %d",
|
||||
m->m_source, m->m_type, m->DEVICE,
|
||||
m->USER_ENDPT, (int) m->IO_GRANT));
|
||||
|
||||
return result;
|
||||
/* We already replied to the request, so don't reply to the CANCEL. */
|
||||
return SUSPEND;
|
||||
}
|
||||
|
||||
static int sr_select(m)
|
||||
static void sr_select(m)
|
||||
message *m;
|
||||
{
|
||||
message m_reply;
|
||||
sr_fd_t *sr_fd;
|
||||
int r;
|
||||
unsigned m_ops, i_ops;
|
||||
|
||||
sr_fd= sr_getchannel(m->DEVICE);
|
||||
sr_fd= sr_getchannel(m->DEV_MINOR);
|
||||
assert (sr_fd);
|
||||
|
||||
sr_fd->srf_select_proc= m->m_source;
|
||||
|
||||
m_ops= m->USER_ENDPT;
|
||||
m_ops= m->DEV_SEL_OPS;
|
||||
i_ops= 0;
|
||||
if (m_ops & SEL_RD) i_ops |= SR_SELECT_READ;
|
||||
if (m_ops & SEL_WR) i_ops |= SR_SELECT_WRITE;
|
||||
|
|
@ -512,72 +468,22 @@ message *m;
|
|||
if (!(m_ops & SEL_NOTIFY)) i_ops |= SR_SELECT_POLL;
|
||||
|
||||
r= (*sr_fd->srf_select)(sr_fd->srf_fd, i_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
m_ops= 0;
|
||||
if (r & SR_SELECT_READ) m_ops |= SEL_RD;
|
||||
if (r & SR_SELECT_WRITE) m_ops |= SEL_WR;
|
||||
if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR;
|
||||
|
||||
return m_ops;
|
||||
}
|
||||
|
||||
static void sr_status(m)
|
||||
message *m;
|
||||
{
|
||||
int fd, result;
|
||||
unsigned m_ops;
|
||||
sr_fd_t *sr_fd;
|
||||
mq_t *mq;
|
||||
|
||||
mq= repl_queue;
|
||||
if (mq != NULL)
|
||||
{
|
||||
repl_queue= mq->mq_next;
|
||||
|
||||
mq->mq_mess.m_type= DEV_REVIVE;
|
||||
result= send(mq->mq_mess.m_source, &mq->mq_mess);
|
||||
if (result != OK)
|
||||
ip_panic(("unable to send"));
|
||||
mq_free(mq);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (fd=0, sr_fd= sr_fd_table; fd<FD_NR; fd++, sr_fd++)
|
||||
{
|
||||
if ((sr_fd->srf_flags &
|
||||
(SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X)) == 0)
|
||||
{
|
||||
/* Nothing to report */
|
||||
continue;
|
||||
}
|
||||
if (sr_fd->srf_select_proc != m->m_source)
|
||||
{
|
||||
/* Wrong process */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
m_ops= r;
|
||||
} else {
|
||||
m_ops= 0;
|
||||
if (sr_fd->srf_flags & SFF_SELECT_R) m_ops |= SEL_RD;
|
||||
if (sr_fd->srf_flags & SFF_SELECT_W) m_ops |= SEL_WR;
|
||||
if (sr_fd->srf_flags & SFF_SELECT_X) m_ops |= SEL_ERR;
|
||||
|
||||
sr_fd->srf_flags &= ~(SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X);
|
||||
|
||||
m->m_type= DEV_IO_READY;
|
||||
m->DEV_MINOR= fd;
|
||||
m->DEV_SEL_OPS= m_ops;
|
||||
|
||||
result= send(m->m_source, m);
|
||||
if (result != OK)
|
||||
ip_panic(("unable to send"));
|
||||
return;
|
||||
if (r & SR_SELECT_READ) m_ops |= SEL_RD;
|
||||
if (r & SR_SELECT_WRITE) m_ops |= SEL_WR;
|
||||
if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR;
|
||||
}
|
||||
|
||||
m->m_type= DEV_NO_STATUS;
|
||||
result= send(m->m_source, m);
|
||||
if (result != OK)
|
||||
memset(&m_reply, 0, sizeof(m_reply));
|
||||
m_reply.m_type= DEV_SEL_REPL1;
|
||||
m_reply.DEV_MINOR= m->DEV_MINOR;
|
||||
m_reply.DEV_SEL_OPS= m_ops;
|
||||
|
||||
r= send(m->m_source, &m_reply);
|
||||
if (r != OK)
|
||||
ip_panic(("unable to send"));
|
||||
}
|
||||
|
||||
|
|
@ -642,8 +548,9 @@ int minor;
|
|||
return loc_fd;
|
||||
}
|
||||
|
||||
static void sr_reply_(mq, status, is_revive)
|
||||
static void sr_reply_(mq, code, status, is_revive)
|
||||
mq_t *mq;
|
||||
int code;
|
||||
int status;
|
||||
int is_revive;
|
||||
{
|
||||
|
|
@ -658,30 +565,12 @@ int is_revive;
|
|||
else
|
||||
mp= &reply;
|
||||
|
||||
mp->m_type= TASK_REPLY;
|
||||
mp->m_type= code;
|
||||
mp->REP_ENDPT= proc;
|
||||
mp->REP_STATUS= status;
|
||||
mp->REP_IO_GRANT= ref;
|
||||
if (is_revive)
|
||||
{
|
||||
notify(mq->mq_mess.m_source);
|
||||
result= ELOCKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
result= send(mq->mq_mess.m_source, mp);
|
||||
}
|
||||
result= send(mq->mq_mess.m_source, mp);
|
||||
|
||||
if (result == ELOCKED && is_revive)
|
||||
{
|
||||
mq->mq_next= NULL;
|
||||
if (repl_queue)
|
||||
repl_queue_tail->mq_next= mq;
|
||||
else
|
||||
repl_queue= mq;
|
||||
repl_queue_tail= mq;
|
||||
return;
|
||||
}
|
||||
if (result != OK)
|
||||
ip_panic(("unable to send"));
|
||||
if (is_revive)
|
||||
|
|
@ -730,7 +619,7 @@ int for_ioctl;
|
|||
*head_ptr= mq;
|
||||
result= (int)offset;
|
||||
is_revive= !(loc_fd->srf_flags & first_flag);
|
||||
sr_reply_(m, result, is_revive);
|
||||
sr_reply_(m, DEV_REVIVE, result, is_revive);
|
||||
suspended= (loc_fd->srf_flags & susp_flag);
|
||||
loc_fd->srf_flags &= ~(ip_flag|susp_flag);
|
||||
if (suspended)
|
||||
|
|
@ -791,7 +680,7 @@ int for_ioctl;
|
|||
*head_ptr= mq;
|
||||
result= (int)offset;
|
||||
is_revive= !(loc_fd->srf_flags & first_flag);
|
||||
sr_reply_(m, result, is_revive);
|
||||
sr_reply_(m, DEV_REVIVE, result, is_revive);
|
||||
suspended= (loc_fd->srf_flags & susp_flag);
|
||||
loc_fd->srf_flags &= ~(ip_flag|susp_flag);
|
||||
if (suspended)
|
||||
|
|
@ -811,15 +700,26 @@ int for_ioctl;
|
|||
|
||||
static void sr_select_res(int fd, unsigned ops)
|
||||
{
|
||||
message m;
|
||||
sr_fd_t *sr_fd;
|
||||
unsigned int m_ops;
|
||||
int result;
|
||||
|
||||
sr_fd= &sr_fd_table[fd];
|
||||
|
||||
if (ops & SR_SELECT_READ) sr_fd->srf_flags |= SFF_SELECT_R;
|
||||
if (ops & SR_SELECT_WRITE) sr_fd->srf_flags |= SFF_SELECT_W;
|
||||
if (ops & SR_SELECT_EXCEPTION) sr_fd->srf_flags |= SFF_SELECT_X;
|
||||
|
||||
notify(sr_fd->srf_select_proc);
|
||||
m_ops= 0;
|
||||
if (ops & SR_SELECT_READ) m_ops |= SEL_RD;
|
||||
if (ops & SR_SELECT_WRITE) m_ops |= SEL_WR;
|
||||
if (ops & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.m_type= DEV_SEL_REPL2;
|
||||
m.DEV_MINOR= fd;
|
||||
m.DEV_SEL_OPS= m_ops;
|
||||
|
||||
result= send(sr_fd->srf_select_proc, &m);
|
||||
if (result != OK)
|
||||
ip_panic(("unable to send"));
|
||||
}
|
||||
|
||||
static void sr_event(evp, arg)
|
||||
|
|
@ -989,45 +889,6 @@ vir_bytes offset;
|
|||
return OK;
|
||||
}
|
||||
|
||||
static int sr_repl_queue(proc, ref, operation)
|
||||
int proc;
|
||||
int ref;
|
||||
int operation;
|
||||
{
|
||||
mq_t *m, *m_cancel, *m_tmp;
|
||||
mq_t *new_queue;
|
||||
int result;
|
||||
|
||||
m_cancel= NULL;
|
||||
new_queue= NULL;
|
||||
|
||||
for (m= repl_queue; m;)
|
||||
{
|
||||
if (m->mq_mess.REP_ENDPT == proc &&
|
||||
m->mq_mess.REP_IO_GRANT == ref)
|
||||
{
|
||||
assert(!m_cancel);
|
||||
m_cancel= m;
|
||||
m= m->mq_next;
|
||||
continue;
|
||||
}
|
||||
m_tmp= m;
|
||||
m= m->mq_next;
|
||||
m_tmp->mq_next= new_queue;
|
||||
new_queue= m_tmp;
|
||||
}
|
||||
repl_queue= new_queue;
|
||||
if (m_cancel)
|
||||
{
|
||||
result= send(m_cancel->mq_mess.m_source, &m_cancel->mq_mess);
|
||||
if (result != OK)
|
||||
ip_panic(("unable to send: %d", result));
|
||||
mq_free(m_cancel);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: sr.c,v 1.17 2005/06/28 14:26:16 philip Exp $
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ typedef struct sr_fd
|
|||
#define SFF_IOCTL_FIRST 0x200
|
||||
#define SFF_READ_FIRST 0x400
|
||||
#define SFF_WRITE_FIRST 0x800
|
||||
#define SFF_SELECT_R 0x1000
|
||||
#define SFF_SELECT_W 0x2000
|
||||
#define SFF_SELECT_X 0x4000
|
||||
|
||||
EXTERN sr_fd_t sr_fd_table[FD_NR];
|
||||
|
||||
|
|
|
|||
|
|
@ -74,11 +74,9 @@ static char * dmap_style(int dev_style)
|
|||
{
|
||||
switch(dev_style) {
|
||||
case STYLE_DEV: return "STYLE_DEV";
|
||||
case STYLE_DEVA: return "STYLE_DEVA";
|
||||
case STYLE_TTY: return "STYLE_TTY";
|
||||
case STYLE_CTTY: return "STYLE_CTTY";
|
||||
case STYLE_CLONE: return "STYLE_CLONE";
|
||||
case STYLE_CLONE_A: return "STYLE_CLONE_A";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ int uds_open(message *dev_m_in, message *dev_m_out)
|
|||
uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
|
||||
|
||||
/* and the socket doesn't have an I/O grant initially */
|
||||
uds_fd_table[minor].io_gr = (cp_grant_id_t) 0;
|
||||
uds_fd_table[minor].io_gr = GRANT_INVALID;
|
||||
|
||||
/* since there is no I/O grant it effectively has no size either */
|
||||
uds_fd_table[minor].io_gr_size = 0;
|
||||
|
|
@ -813,6 +813,13 @@ int uds_ioctl(message *dev_m_in, message *dev_m_out)
|
|||
/* update the owner endpoint - yes it's really stored in POSITION */
|
||||
uds_fd_table[minor].owner = dev_m_in->POSITION;
|
||||
|
||||
/* update the process endpoint, which may well be different */
|
||||
uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
|
||||
|
||||
/* save I/O Grant info */
|
||||
uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
|
||||
uds_fd_table[minor].io_gr_size = 0; /* should not be used here */
|
||||
|
||||
switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */
|
||||
|
||||
case NWIOSUDSCONN:
|
||||
|
|
@ -1074,14 +1081,8 @@ int uds_cancel(message *dev_m_in, message *dev_m_out)
|
|||
minor = uds_minor(dev_m_in);
|
||||
|
||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
||||
|
||||
/* attempted to close a socket that hasn't been opened --
|
||||
* something is very wrong :(
|
||||
*/
|
||||
uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
|
||||
(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
|
||||
|
||||
return EINVAL;
|
||||
/* attempted to cancel an unknown request - this happens */
|
||||
return SUSPEND;
|
||||
}
|
||||
|
||||
/* Update the process endpoint. */
|
||||
|
|
@ -1184,8 +1185,7 @@ int uds_cancel(message *dev_m_in, message *dev_m_out)
|
|||
uds_fd_table[minor].syscall_done = 1;
|
||||
}
|
||||
|
||||
|
||||
uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
|
||||
uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
|
||||
(cp_grant_id_t) dev_m_in->IO_GRANT, EINTR);
|
||||
|
||||
return EINTR;
|
||||
|
|
|
|||
|
|
@ -61,10 +61,10 @@ int (*dev_call_vec[])(message *dev_m_in, message *dev_m_out) = {
|
|||
uds_close, /* 7 DEV_CLOSE */
|
||||
no_sys, /* 8 */
|
||||
no_sys, /* 9 */
|
||||
no_sys, /* 10 TTY_SETPGRP */
|
||||
no_sys, /* 11 TTY_EXIT */
|
||||
no_sys, /* 10 */
|
||||
no_sys, /* 11 */
|
||||
uds_select, /* 12 DEV_SELECT */
|
||||
no_sys, /* 13 DEV_STATUS */
|
||||
no_sys, /* 13 */
|
||||
uds_open, /* 14 DEV_REOPEN */
|
||||
no_sys, /* 15 */
|
||||
no_sys, /* 16 */
|
||||
|
|
|
|||
|
|
@ -320,11 +320,10 @@ int dump_core; /* flag indicating whether to dump core */
|
|||
/* Tell VFS about the exiting process. */
|
||||
m.m_type = dump_core ? PM_DUMPCORE : PM_EXIT;
|
||||
m.PM_PROC = rmp->mp_endpoint;
|
||||
m.PM_TRACED_PROC = rmp->mp_endpoint;
|
||||
|
||||
if (dump_core) {
|
||||
m.PM_TERM_SIG = rmp->mp_sigstatus;
|
||||
m.PM_PATH = rmp->mp_name;
|
||||
m.PM_TERM_SIG = rmp->mp_sigstatus;
|
||||
m.PM_PATH = rmp->mp_name;
|
||||
}
|
||||
|
||||
tell_vfs(rmp, &m);
|
||||
|
|
|
|||
|
|
@ -447,15 +447,7 @@ static void handle_vfs_reply()
|
|||
if (m_in.PM_STATUS == OK)
|
||||
rmp->mp_sigstatus |= DUMPED;
|
||||
|
||||
if (m_in.PM_PROC == m_in.PM_TRACED_PROC)
|
||||
/* The reply is to a core dump request
|
||||
* for a killed process */
|
||||
exit_restart(rmp, TRUE /*dump_core*/);
|
||||
else
|
||||
/* The reply is to a core dump request
|
||||
* for a traced process (T_DUMPCORE) */
|
||||
/* Wake up the original caller */
|
||||
setreply(rmp-mproc, rmp->mp_procgrp);
|
||||
exit_restart(rmp, TRUE /*dump_core*/);
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -91,27 +91,6 @@ int do_trace()
|
|||
mp->mp_reply.reply_trace = 0;
|
||||
return(OK);
|
||||
|
||||
case T_DUMPCORE:
|
||||
if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH);
|
||||
|
||||
/* Allow dumpcore only if traced! */
|
||||
if (child->mp_tracer != who_p) return(EPERM);
|
||||
|
||||
/* Tell VFS to dump the core. */
|
||||
m.m_type = PM_DUMPCORE;
|
||||
m.PM_PROC = mp->mp_endpoint;
|
||||
m.PM_TRACED_PROC = child->mp_endpoint;
|
||||
/* Note that m.PM_PROC != m.PM_TRACED_PROC
|
||||
* (we use this to differentiate between a VFS core dump reply for a
|
||||
* an exiting process and the one for a traced process) */
|
||||
|
||||
m.PM_TERM_SIG = child->mp_sigstatus;
|
||||
m.PM_PATH = child->mp_name;
|
||||
|
||||
tell_vfs(mp, &m);
|
||||
|
||||
return(SUSPEND); /* Suspend the process until we receive reply from VFS */
|
||||
|
||||
case T_STOP: /* stop the process */
|
||||
/* This call is not exposed to user programs, because its effect can be
|
||||
* achieved better by sending the traced process a signal with kill(2).
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ static void pid_psinfo(int i)
|
|||
case FP_BLOCKED_ON_LOCK: f_state = FSTATE_LOCK; break;
|
||||
case FP_BLOCKED_ON_POPEN: f_state = FSTATE_POPEN; break;
|
||||
case FP_BLOCKED_ON_SELECT: f_state = FSTATE_SELECT; break;
|
||||
case FP_BLOCKED_ON_DOPEN: f_state = FSTATE_DOPEN; break;
|
||||
case FP_BLOCKED_ON_OTHER: f_state = FSTATE_TASK; break;
|
||||
default: f_state = FSTATE_UNKNOWN;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ struct boot_image_dev boot_image_dev_table[] = {
|
|||
/*endpoint, flags, dev_nr, dev_style, dev_style2 */
|
||||
{ TTY_PROC_NR, SRV_DF, TTY_MAJOR, STYLE_TTY, STYLE_CTTY },
|
||||
{ MEM_PROC_NR, SRV_DF, MEMORY_MAJOR, STYLE_DEV, STYLE_NDEV },
|
||||
{ LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEVA, STYLE_NDEV },
|
||||
{ PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE_A,STYLE_NDEV },
|
||||
{ LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEV, STYLE_NDEV },
|
||||
{ PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE,STYLE_NDEV },
|
||||
{ DEFAULT_BOOT_NR, SRV_DF, 0, STYLE_NDEV, STYLE_NDEV } /* default
|
||||
* entry
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -106,83 +106,87 @@ know the details of the protocol.
|
|||
Upon start up, VFS spawns a configurable amount of worker threads. The
|
||||
main thread fetches requests and replies, and hands them off to idle or
|
||||
reply-pending workers, respectively. If no worker threads are available,
|
||||
the request is queued. There are 3 types of worker threads: normal, a system
|
||||
worker, and a deadlock resolver. All standard system calls are handled by
|
||||
normal worker threads. Jobs from PM and notifications from the kernel are taken
|
||||
care of by the system worker. The deadlock resolver handles jobs from system
|
||||
the request is queued. All standard system calls are handled by such worker
|
||||
threads. One of the threads is reserved to handle new requests from system
|
||||
processes (i.e., File Servers and drivers) when there are no normal worker
|
||||
threads available; all normal threads might be blocked on a single worker
|
||||
thread that caused a system process to send a request on its own. To unblock
|
||||
all normal threads, we need to reserve one thread to handle that situation.
|
||||
VFS drives all File Servers and drivers asynchronously. While waiting for
|
||||
a reply, a worker thread is blocked and other workers can keep processing
|
||||
requests. Upon reply the worker thread is unblocked.
|
||||
As mentioned above, the main thread is responsible for retrieving new jobs and
|
||||
replies to current jobs and start or unblock the proper worker thread. Given
|
||||
how many sources for new jobs and replies there are, the work for the main
|
||||
thread is quite complicated. Consider Table 1.
|
||||
{{{
|
||||
---------------------------------------------------------
|
||||
| From | normal | deadlock | system |
|
||||
---------------------------------------------------------
|
||||
msg is new job
|
||||
---------------------------------------------------------
|
||||
| PM | | | X |
|
||||
+----------------------+----------+----------+----------+
|
||||
| Notification from | | | |
|
||||
| the kernel | | | X |
|
||||
+----------------------+----------+----------+----------+
|
||||
| Notification from | | | |
|
||||
| DS or system process | X | X | |
|
||||
+----------------------+----------+----------+----------+
|
||||
| User process | X | | |
|
||||
+----------------------+----------+----------+----------+
|
||||
| Unsuspended process | X | | |
|
||||
---------------------------------------------------------
|
||||
msg is reply
|
||||
---------------------------------------------------------
|
||||
| File Server reply | resume | | |
|
||||
+----------------------+----------+----------+----------+
|
||||
| Sync. driver reply | resume | | |
|
||||
+----------------------+----------+----------+----------+
|
||||
| Async. driver reply | resume/X | X | |
|
||||
---------------------------------------------------------
|
||||
}}}
|
||||
Table 1: VFS' message fetching main loop. X means 'start thread'.
|
||||
all normal threads, we need to reserve one spare thread to handle that
|
||||
situation. VFS drives all File Servers and drivers asynchronously. While
|
||||
waiting for a reply, a worker thread is blocked and other workers can keep
|
||||
processing requests. Upon reply the worker thread is unblocked.
|
||||
|
||||
The reason why asynchronous driver replies get their own thread is for the
|
||||
following. In some cases, a reply has a thread blocked waiting for it which
|
||||
can be resumed (e.g., open). In another case there's a lot of work to be
|
||||
done which involves sending new messages (e.g., select replies). Finally,
|
||||
DEV_REVIVE replies unblock suspended processes which in turn generate new jobs
|
||||
to be handled by the main loop (e.g., suspended reads and writes). So depending
|
||||
on the reply a new thread has to be started. Having all this logic in the main
|
||||
loop is messy, so we start a thread regardless of the actual reply contents.
|
||||
When there are no worker threads available and there is no need to invoke
|
||||
the deadlock resolver (i.e., normal system calls), the request is queued in
|
||||
the fproc table. This works because a process can send only one system call
|
||||
at a time. When implementing kernel threads, one has to take this assumption
|
||||
into account.
|
||||
The protocol PM speaks with VFS is asynchronous and PM is allowed to
|
||||
send as many request to VFS as it wants. It is impossible to use the same
|
||||
queueing mechanism as normal processes use, because that would allow for
|
||||
just 1 queued message. Instead, the system worker maintains a linked list
|
||||
of pending requests. Moreover, this queueing mechanism is also the reason
|
||||
why notifications from the kernel are handled by the system worker; the
|
||||
kernel has no corresponding fproc table entry (so we can't store it there)
|
||||
and the linked list has no dependencies on that table.
|
||||
Communication with drivers is asynchronous even when the driver uses the
|
||||
synchronous driver protocol. However, to guarantee identical behavior,
|
||||
access to synchronous drivers is serialized. File Servers are treated
|
||||
differently. VFS was designed to be able to send requests concurrently to
|
||||
File Servers, although at the time of writing there are no File Servers that
|
||||
can actually make use of that functionality. To identify which reply from an
|
||||
FS belongs to which worker thread, all requests have an embedded transaction
|
||||
identification number (a magic number + thread id encoded in the mtype field
|
||||
of a message) which the FS has to echo upon reply. Because the range of valid
|
||||
transaction IDs is isolated from valid system call numbers, VFS can use that
|
||||
ID to differentiate between replies from File Servers and actual new system
|
||||
calls from FSes. Using this mechanism VFS is able to support FUSE and ProcFS.
|
||||
As mentioned above, the main thread is responsible for retrieving new jobs and
|
||||
replies to current jobs and start or unblock the proper worker thread.
|
||||
Driver replies are processed directly from the main thread. As a consequence,
|
||||
these processing routines may not block their calling thread. In some cases,
|
||||
these routines may resume a thread that is blocked waiting for the reply. This
|
||||
is always the case for block driver replies, and may or may not be the case for
|
||||
character driver replies. The character driver reply processing routines may
|
||||
also unblock suspended processes which in turn generate new jobs to be handled
|
||||
by the main loop (e.g., suspended reads and writes on pipes). So depending
|
||||
on the reply a new thread may have to be started.
|
||||
|
||||
Worker threads are strictly tied to a process, and each process can have at
|
||||
most one worker thread running for it. Generally speaking, there are two types
|
||||
of work supported by worker threads: normal work, and work from PM. The main
|
||||
subtype of normal work is the handling of a system call made by the process
|
||||
itself. The process is blocked while VFS is handling the system call, so no new
|
||||
system call can arrive from a process while VFS has not completed a previous
|
||||
system call from that process. For that reason, if there are no worker threads
|
||||
available to handle the work, the work is queued in the corresponding process
|
||||
entry of the fproc table.
|
||||
|
||||
The other main type of work consists of requests from PM. The protocol PM
|
||||
speaks with VFS is asynchronous. PM is allowed to send up to one request per
|
||||
process to VFS, in addition to a request to initiate a reboot. Most jobs from
|
||||
PM are taken care of immediately by the main thread, but some jobs require a
|
||||
worker thread context (to be able to sleep) and/or serialization with normal
|
||||
work. Therefore, each process may have a PM request queued for execution, also
|
||||
in the fproc table. Managing proper queuing, addition, and execution of both
|
||||
normal and PM work is the responsibility of the worker thread infrastructure.
|
||||
|
||||
There are several special tasks that require a worker thread, and these are
|
||||
implemented as normal work associated with a certain special process that does
|
||||
not make regular VFS calls anyway. For example, the initial ramdisk mount
|
||||
procedure and the post-crash filp garbage collector use a thread associated
|
||||
with the VFS process. Some of these special tasks require protection against
|
||||
being started multiple times at once, as this is not only undesirable but also
|
||||
disallowed. The full list of worker thread task types and subtypes is shown in
|
||||
Table 1.
|
||||
|
||||
{{{
|
||||
-------------------------------------------------------------------------
|
||||
| Worker thread task | Type | Association | May use spare? |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| system call from process | normal | calling process | if system proc |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| resumed pipe operation | normal | calling process | no |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| postponed PM request | PM | target process | no |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| DS event notification | normal | DS | yes |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| filp garbage collection | normal | VFS | no |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| initial ramdisk mounting | normal | VFS | no |
|
||||
+---------------------------+--------+-----------------+----------------+
|
||||
| reboot sequence | normal | PM | no |
|
||||
-------------------------------------------------------------------------
|
||||
}}}
|
||||
Table 1: worker thread work types and subtypes
|
||||
|
||||
Communication with block drivers is asynchronous, but at this time, access to
|
||||
these drivers is serialized on a per-driver basis. File Servers are treated
|
||||
differently. VFS was designed to be able to send requests concurrently to File
|
||||
Servers, although at the time of writing there are no File Servers that can
|
||||
actually make use of that functionality. To identify which reply from an FS
|
||||
belongs to which worker thread, all requests have an embedded transaction
|
||||
identification number (a magic number + thread id encoded in the mtype field of
|
||||
a message) which the FS has to echo upon reply. Because the range of valid
|
||||
transaction IDs is isolated from valid system call numbers, VFS can use that ID
|
||||
to differentiate between replies from File Servers and actual new system calls
|
||||
from FSes. Using this mechanism VFS is able to support FUSE and ProcFS.
|
||||
|
||||
== Locking ==
|
||||
## 4 Locking
|
||||
|
|
@ -306,22 +310,42 @@ fproc, vmnt, vnode, and filp objects. To prevent deadlocks as a result of
|
|||
object locking, we need to define a strict locking order. In VFS we use the
|
||||
following order:
|
||||
|
||||
fproc -> [exec] -> vmnt -> vnode -> filp -> [block special file] -> [dmap]
|
||||
{{{
|
||||
fproc > [exec] > vmnt > vnode > filp > [block special file] > [dmap]
|
||||
}}}
|
||||
|
||||
That is, no thread may lock an fproc object while holding a vmnt lock,
|
||||
and no thread may lock a vmnt object while holding an (associated) vnode, etc.
|
||||
|
||||
Fproc needs protection because processes themselves can initiate system
|
||||
calls, but also PM can cause system calls that have to be executed in their
|
||||
name. For example, a process might be busy reading from a character device
|
||||
and another process sends a termination signal. The exit(2) that follows is
|
||||
sent by PM and is to be executed by the to-be-killed process itself. At this
|
||||
point there is contention for the fproc object that belongs to the process,
|
||||
hence the need for protection.
|
||||
The exec(2) call is protected by a mutex for the following reason. VFS uses a
|
||||
number of variables on the heap to read ELF headers. They are on the heap due
|
||||
to their size; putting them on the stack would increase stack size demands for
|
||||
worker threads. The exec call does blocking read calls and thus needs exclusive
|
||||
access to these variables. However, only the exec(2) syscall needs this lock.
|
||||
hence the need for protection. This problem is solved in a simple way. Recall
|
||||
that all worker threads are bound to a process. This also forms the basis of
|
||||
fproc locking: each worker thread acquires and holds the fproc lock for its
|
||||
associated process for as long as it is processing work for that process.
|
||||
|
||||
There are two cases where a worker thread may hold the lock to more than one
|
||||
process. First, as mentioned, the reboot procedure is executed from a worker
|
||||
thread set in the context of the PM process, thus with the PM process entry
|
||||
lock held. The procedure itself then acquires a temporary lock on every other
|
||||
process in turn, in order to clean it up without interference. Thus, the PM
|
||||
process entry is higher up in the locking order than all other process entries.
|
||||
|
||||
Second, the exec(2) call is protected by a lock, and this exec lock is
|
||||
currently implemented as a lock on the VM process entry. The exec lock is
|
||||
acquired by a worker thread for the process performing the exec(2) call, and
|
||||
thus, the VM process entry is below all other process entries in the locking
|
||||
order. The exec(2) call is protected by a lock for the following reason. VFS
|
||||
uses a number of variables on the heap to read ELF headers. They are on the
|
||||
heap due to their size; putting them on the stack would increase stack size
|
||||
demands for worker threads. The exec call does blocking read calls and thus
|
||||
needs exclusive access to these variables. However, only the exec(2) syscall
|
||||
needs this lock.
|
||||
|
||||
Access to block special files needs to be exclusive. File Servers are
|
||||
responsible for handling reads from and writes to block special files; if
|
||||
a block special file is on a device that is mounted, the FS responsible for
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
#include "fs.h"
|
||||
#include "glo.h"
|
||||
#include "vmnt.h"
|
||||
#include "fproc.h"
|
||||
#include <minix/vfsif.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#define NR_LOCKS 8 /* # slots in the file locking table */
|
||||
#define NR_MNTS 16 /* # slots in mount table */
|
||||
#define NR_VNODES 1024 /* # slots in vnode table */
|
||||
#define NR_WTHREADS 8 /* # slots in worker thread table */
|
||||
#define NR_WTHREADS 9 /* # slots in worker thread table */
|
||||
|
||||
#define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */
|
||||
|
||||
|
|
@ -20,15 +20,14 @@
|
|||
#define FP_BLOCKED_ON_LOCK 2 /* susp'd on lock */
|
||||
#define FP_BLOCKED_ON_POPEN 3 /* susp'd on pipe open */
|
||||
#define FP_BLOCKED_ON_SELECT 4 /* susp'd on select */
|
||||
#define FP_BLOCKED_ON_DOPEN 5 /* susp'd on device open */
|
||||
#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check
|
||||
#define FP_BLOCKED_ON_OTHER 5 /* blocked on other process, check
|
||||
fp_task to find out */
|
||||
|
||||
/* test if the process is blocked on something */
|
||||
#define fp_is_blocked(fp) ((fp)->fp_blocked_on != FP_BLOCKED_ON_NONE)
|
||||
|
||||
/* test if reply is a driver reply */
|
||||
#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x) || (x) == TASK_REPLY)
|
||||
#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x))
|
||||
#define DUP_MASK 0100 /* mask to distinguish dup2 from dup */
|
||||
|
||||
#define LOOK_UP 0 /* tells search_dir to lookup string */
|
||||
|
|
@ -43,10 +42,4 @@
|
|||
* M3_LONG_STRING.
|
||||
*/
|
||||
|
||||
/* Args to dev_io */
|
||||
#define VFS_DEV_READ 2001
|
||||
#define VFS_DEV_WRITE 2002
|
||||
#define VFS_DEV_IOCTL 2005
|
||||
#define VFS_DEV_SELECT 2006
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "fs.h"
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include "fproc.h"
|
||||
#include <minix/vm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/exec_elf.h>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@
|
|||
* dev_open: open a character device
|
||||
* dev_reopen: reopen a character device after a driver crash
|
||||
* dev_close: close a character device
|
||||
* cdev_reply: process the result of a character driver request
|
||||
* bdev_open: open a block device
|
||||
* bdev_close: close a block device
|
||||
* bdev_reply: process the result of a block driver request
|
||||
* dev_io: FS does a read or write on a device
|
||||
* dev_status: FS processes callback request alert
|
||||
* gen_opcl: generic call to a task to perform an open/close
|
||||
* gen_io: generic call to a task to perform an I/O operation
|
||||
* gen_opcl: generic call to a character driver to perform an open/close
|
||||
* gen_io: generic call to a character driver to initiate I/O
|
||||
* no_dev: open/close processing for devices that don't exist
|
||||
* no_dev_io: i/o processing for devices that don't exist
|
||||
* tty_opcl: perform tty-specific processing for open/close
|
||||
|
|
@ -18,6 +19,8 @@
|
|||
* ctty_io: perform controlling-tty-specific processing for I/O
|
||||
* pm_setsid: perform VFS's side of setsid system call
|
||||
* do_ioctl: perform the IOCTL system call
|
||||
* dev_select: initiate a select call on a device
|
||||
* dev_cancel: cancel an I/O request, blocking until it has been cancelled
|
||||
*/
|
||||
|
||||
#include "fs.h"
|
||||
|
|
@ -31,7 +34,6 @@
|
|||
#include <minix/ioctl.h>
|
||||
#include <minix/u64.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "dmap.h"
|
||||
#include <minix/vfsif.h>
|
||||
|
|
@ -39,13 +41,14 @@
|
|||
#include "vmnt.h"
|
||||
#include "param.h"
|
||||
|
||||
static int block_io(endpoint_t driver_e, message *mess_ptr);
|
||||
static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op,
|
||||
void *buf, size_t size);
|
||||
static void restart_reopen(int major);
|
||||
static int safe_io_conversion(endpoint_t, cp_grant_id_t *, int *,
|
||||
endpoint_t *, void **, size_t, u32_t *);
|
||||
static void reopen_reply(message *m_ptr);
|
||||
|
||||
static int dummyproc;
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dev_open *
|
||||
*===========================================================================*/
|
||||
|
|
@ -158,10 +161,9 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf)
|
|||
{
|
||||
/* Perform an I/O control operation on a block device. */
|
||||
struct dmap *dp;
|
||||
u32_t dummy;
|
||||
cp_grant_id_t gid;
|
||||
message dev_mess;
|
||||
int op, major_dev, minor_dev;
|
||||
int major_dev, minor_dev;
|
||||
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
|
|
@ -169,14 +171,12 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf)
|
|||
/* Determine task dmap. */
|
||||
dp = &dmap[major_dev];
|
||||
if (dp->dmap_driver == NONE) {
|
||||
printf("VFS: dev_io: no driver for major %d\n", major_dev);
|
||||
printf("VFS: bdev_ioctl: no driver for major %d\n", major_dev);
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
/* Set up a grant if necessary. */
|
||||
op = VFS_DEV_IOCTL;
|
||||
(void) safe_io_conversion(dp->dmap_driver, &gid, &op, &proc_e, &buf, req,
|
||||
&dummy);
|
||||
gid = make_grant(dp->dmap_driver, proc_e, BDEV_IOCTL, buf, req);
|
||||
|
||||
/* Set up the message passed to the task. */
|
||||
memset(&dev_mess, 0, sizeof(dev_mess));
|
||||
|
|
@ -188,7 +188,7 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf)
|
|||
dev_mess.BDEV_ID = 0;
|
||||
|
||||
/* Call the task. */
|
||||
(*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
block_io(dp->dmap_driver, &dev_mess);
|
||||
|
||||
/* Clean up. */
|
||||
if (GRANT_VALID(gid)) cpf_revoke(gid);
|
||||
|
|
@ -206,7 +206,7 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf)
|
|||
/*===========================================================================*
|
||||
* find_suspended_ep *
|
||||
*===========================================================================*/
|
||||
endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g)
|
||||
static endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g)
|
||||
{
|
||||
/* A process is suspended on a driver for which VFS issued a grant. Find out
|
||||
* which process it was.
|
||||
|
|
@ -216,9 +216,11 @@ endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g)
|
|||
if(rfp->fp_pid == PID_FREE)
|
||||
continue;
|
||||
|
||||
if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER &&
|
||||
rfp->fp_task == driver && rfp->fp_grant == g)
|
||||
if (rfp->fp_task == driver && rfp->fp_grant == g) {
|
||||
assert(!fp_is_blocked(rfp) ||
|
||||
rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER);
|
||||
return(rfp->fp_endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return(NONE);
|
||||
|
|
@ -226,105 +228,29 @@ endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g)
|
|||
|
||||
|
||||
/*===========================================================================*
|
||||
* dev_status *
|
||||
* make_grant *
|
||||
*===========================================================================*/
|
||||
void dev_status(endpoint_t drv_e)
|
||||
static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op,
|
||||
void *buf, size_t bytes)
|
||||
{
|
||||
/* A device sent us a notification it has something for us. Retrieve it. */
|
||||
|
||||
message st;
|
||||
int major, get_more = 1;
|
||||
endpoint_t endpt;
|
||||
|
||||
for (major = 0; major < NR_DEVICES; major++)
|
||||
if (dmap_driver_match(drv_e, major))
|
||||
break; /* 'major' is the device that sent the message */
|
||||
|
||||
if (major >= NR_DEVICES) /* Device endpoint not found; nothing to do */
|
||||
return;
|
||||
|
||||
if (dev_style_asyn(dmap[major].dmap_style)) {
|
||||
printf("VFS: not doing dev_status for async driver %d\n", drv_e);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Continuously send DEV_STATUS messages until the device has nothing to
|
||||
* say to us anymore. */
|
||||
do {
|
||||
int r;
|
||||
st.m_type = DEV_STATUS;
|
||||
r = drv_sendrec(drv_e, &st);
|
||||
if (r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT;
|
||||
if (r != OK) {
|
||||
printf("VFS: DEV_STATUS failed to %d: %d\n", drv_e, r);
|
||||
if (r == EDEADSRCDST || r == EDEADEPT) return;
|
||||
panic("VFS: couldn't sendrec for DEV_STATUS: %d", r);
|
||||
}
|
||||
|
||||
switch(st.m_type) {
|
||||
case DEV_REVIVE:
|
||||
/* We've got results for a read/write/ioctl call to a
|
||||
* synchronous character driver */
|
||||
endpt = st.REP_ENDPT;
|
||||
if (endpt == VFS_PROC_NR) {
|
||||
endpt = find_suspended_ep(drv_e, st.REP_IO_GRANT);
|
||||
if (endpt == NONE) {
|
||||
printf("VFS: proc with grant %d from %d not found\n",
|
||||
st.REP_IO_GRANT, st.m_source);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
revive(endpt, st.REP_STATUS);
|
||||
break;
|
||||
case DEV_IO_READY:
|
||||
/* Reply to a select request: driver is ready for I/O */
|
||||
select_reply2(st.m_source, st.DEV_MINOR, st.DEV_SEL_OPS);
|
||||
break;
|
||||
default:
|
||||
printf("VFS: unrecognized reply %d to DEV_STATUS\n",st.m_type);
|
||||
/* Fall through. */
|
||||
case DEV_NO_STATUS:
|
||||
get_more = 0;
|
||||
break;
|
||||
}
|
||||
} while(get_more);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* safe_io_conversion *
|
||||
*===========================================================================*/
|
||||
static int safe_io_conversion(driver, gid, op, io_ept, buf, bytes, pos_lo)
|
||||
endpoint_t driver;
|
||||
cp_grant_id_t *gid;
|
||||
int *op;
|
||||
endpoint_t *io_ept;
|
||||
void **buf;
|
||||
size_t bytes;
|
||||
u32_t *pos_lo;
|
||||
{
|
||||
/* Convert operation to the 'safe' variant (i.e., grant based) if applicable.
|
||||
* If no copying of data is involved, there is also no need to convert. */
|
||||
|
||||
int access = 0;
|
||||
/* Create a magic grant for the given operation and buffer. */
|
||||
cp_grant_id_t gid;
|
||||
int access;
|
||||
size_t size;
|
||||
|
||||
*gid = GRANT_INVALID; /* Grant to buffer */
|
||||
|
||||
switch(*op) {
|
||||
case VFS_DEV_READ:
|
||||
case VFS_DEV_WRITE:
|
||||
/* Change to safe op. */
|
||||
*op = (*op == VFS_DEV_READ) ? DEV_READ_S : DEV_WRITE_S;
|
||||
*gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes,
|
||||
*op == DEV_READ_S ? CPF_WRITE : CPF_READ);
|
||||
if (*gid < 0)
|
||||
panic("VFS: cpf_grant_magic of READ/WRITE buffer failed");
|
||||
switch (op) {
|
||||
case DEV_READ_S:
|
||||
case DEV_WRITE_S:
|
||||
gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, bytes,
|
||||
op == DEV_READ_S ? CPF_WRITE : CPF_READ);
|
||||
break;
|
||||
case VFS_DEV_IOCTL:
|
||||
*pos_lo = *io_ept; /* Old endpoint in POSITION field. */
|
||||
*op = DEV_IOCTL_S;
|
||||
|
||||
case DEV_IOCTL_S:
|
||||
case BDEV_IOCTL:
|
||||
/* For IOCTLs, the bytes parameter encodes requested access method
|
||||
* and buffer size */
|
||||
* and buffer size
|
||||
*/
|
||||
access = 0;
|
||||
if(_MINIX_IOCTL_IOR(bytes)) access |= CPF_WRITE;
|
||||
if(_MINIX_IOCTL_IOW(bytes)) access |= CPF_READ;
|
||||
if(_MINIX_IOCTL_BIG(bytes))
|
||||
|
|
@ -335,65 +261,27 @@ u32_t *pos_lo;
|
|||
/* Grant access to the buffer even if no I/O happens with the ioctl, in
|
||||
* order to disambiguate requests with DEV_IOCTL_S.
|
||||
*/
|
||||
*gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, access);
|
||||
if (*gid < 0)
|
||||
panic("VFS: cpf_grant_magic IOCTL buffer failed");
|
||||
gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, size, access);
|
||||
break;
|
||||
|
||||
break;
|
||||
case VFS_DEV_SELECT:
|
||||
*op = DEV_SELECT;
|
||||
break;
|
||||
default:
|
||||
panic("VFS: unknown operation %d for safe I/O conversion", *op);
|
||||
default:
|
||||
panic("VFS: unknown operation %d", op);
|
||||
}
|
||||
|
||||
/* If we have converted to a safe operation, I/O endpoint becomes VFS if it
|
||||
* wasn't already.
|
||||
*/
|
||||
if(GRANT_VALID(*gid)) {
|
||||
*io_ept = VFS_PROC_NR;
|
||||
return(1);
|
||||
}
|
||||
if (!GRANT_VALID(gid))
|
||||
panic("VFS: cpf_grant_magic failed");
|
||||
|
||||
/* Not converted to a safe operation (because there is no copying involved in
|
||||
* this operation).
|
||||
*/
|
||||
return(0);
|
||||
return gid;
|
||||
}
|
||||
|
||||
static int cancel_nblock(struct dmap * dp,
|
||||
int minor,
|
||||
int call,
|
||||
endpoint_t ioproc,
|
||||
cp_grant_id_t gid)
|
||||
{
|
||||
message dev_mess;
|
||||
|
||||
dev_mess.m_type = CANCEL;
|
||||
dev_mess.USER_ENDPT = ioproc;
|
||||
dev_mess.IO_GRANT = (char *) gid;
|
||||
|
||||
/* This R_BIT/W_BIT check taken from suspend()/unpause()
|
||||
* logic. Mode is expected in the COUNT field.
|
||||
*/
|
||||
dev_mess.COUNT = 0;
|
||||
if (call == READ)
|
||||
dev_mess.COUNT = R_BIT;
|
||||
else if (call == WRITE)
|
||||
dev_mess.COUNT = W_BIT;
|
||||
dev_mess.DEVICE = minor;
|
||||
(*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
|
||||
return dev_mess.REP_STATUS;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* dev_io *
|
||||
*===========================================================================*/
|
||||
int dev_io(
|
||||
int op, /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
|
||||
int op, /* DEV_READ_S, DEV_WRITE_S, or DEV_IOCTL_S */
|
||||
dev_t dev, /* major-minor device number */
|
||||
endpoint_t proc_e, /* in whose address space is buf? */
|
||||
endpoint_t proc_e, /* in whose address space is buf? */
|
||||
void *buf, /* virtual address of the buffer */
|
||||
u64_t pos, /* byte position */
|
||||
size_t bytes, /* how many bytes to transfer */
|
||||
|
|
@ -401,22 +289,17 @@ int dev_io(
|
|||
int suspend_reopen /* Just suspend the process */
|
||||
)
|
||||
{
|
||||
/* Read from or write to a device. The parameter 'dev' tells which one. */
|
||||
/* Initiate a read, write, or ioctl to a device. */
|
||||
struct dmap *dp;
|
||||
u32_t pos_lo, pos_high;
|
||||
message dev_mess;
|
||||
cp_grant_id_t gid = GRANT_INVALID;
|
||||
int safe, minor_dev, major_dev;
|
||||
void *buf_used;
|
||||
endpoint_t ioproc;
|
||||
int ret, is_asyn;
|
||||
cp_grant_id_t gid;
|
||||
int r, minor_dev, major_dev;
|
||||
|
||||
pos_lo = ex64lo(pos);
|
||||
pos_high = ex64hi(pos);
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
assert(op == DEV_READ_S || op == DEV_WRITE_S || op == DEV_IOCTL_S);
|
||||
|
||||
/* Determine task dmap. */
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
dp = &dmap[major_dev];
|
||||
|
||||
/* See if driver is roughly valid. */
|
||||
|
|
@ -437,82 +320,42 @@ int dev_io(
|
|||
return(ENXIO);
|
||||
}
|
||||
|
||||
/* By default, these are right. */
|
||||
dev_mess.USER_ENDPT = proc_e;
|
||||
dev_mess.ADDRESS = buf;
|
||||
/* Create a grant for the buffer provided by the user process. */
|
||||
gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes);
|
||||
|
||||
/* Convert DEV_* to DEV_*_S variants. */
|
||||
buf_used = buf;
|
||||
safe = safe_io_conversion(dp->dmap_driver, &gid, &op,
|
||||
(endpoint_t *) &dev_mess.USER_ENDPT, &buf_used,
|
||||
bytes, &pos_lo);
|
||||
|
||||
is_asyn = dev_style_asyn(dp->dmap_style);
|
||||
|
||||
/* If the safe conversion was done, set the IO_GRANT to
|
||||
* the grant id.
|
||||
*/
|
||||
if(safe) dev_mess.IO_GRANT = (char *) gid;
|
||||
|
||||
/* Set up the rest of the message passed to task. */
|
||||
/* Set up the rest of the message that will be sent to the driver. */
|
||||
dev_mess.m_type = op;
|
||||
dev_mess.DEVICE = minor_dev;
|
||||
dev_mess.POSITION = pos_lo;
|
||||
dev_mess.COUNT = bytes;
|
||||
dev_mess.HIGHPOS = pos_high;
|
||||
if (op == DEV_IOCTL_S) {
|
||||
dev_mess.REQUEST = bytes;
|
||||
dev_mess.POSITION = proc_e;
|
||||
} else {
|
||||
dev_mess.POSITION = ex64lo(pos);
|
||||
dev_mess.COUNT = bytes;
|
||||
}
|
||||
dev_mess.HIGHPOS = ex64hi(pos);
|
||||
dev_mess.USER_ENDPT = VFS_PROC_NR;
|
||||
dev_mess.IO_GRANT = (void *) gid;
|
||||
dev_mess.FLAGS = 0;
|
||||
|
||||
if (flags & O_NONBLOCK)
|
||||
dev_mess.FLAGS |= FLG_OP_NONBLOCK;
|
||||
|
||||
/* This will be used if the i/o is suspended. */
|
||||
ioproc = dev_mess.USER_ENDPT;
|
||||
/* Send the request to the driver. */
|
||||
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
|
||||
/* Call the task. */
|
||||
(*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
if (r != OK) {
|
||||
cpf_revoke(gid);
|
||||
|
||||
if(dp->dmap_driver == NONE) {
|
||||
/* Driver has vanished. */
|
||||
printf("VFS: driver gone?!\n");
|
||||
if(safe) cpf_revoke(gid);
|
||||
return(EIO);
|
||||
return r;
|
||||
}
|
||||
|
||||
ret = dev_mess.REP_STATUS;
|
||||
/* Suspend the calling process until a reply arrives. */
|
||||
wait_for(dp->dmap_driver);
|
||||
assert(!GRANT_VALID(fp->fp_grant));
|
||||
fp->fp_grant = gid; /* revoke this when unsuspended. */
|
||||
fp->fp_ioproc = VFS_PROC_NR;
|
||||
|
||||
/* Task has completed. See if call completed. */
|
||||
if (ret == SUSPEND) {
|
||||
if ((flags & O_NONBLOCK) && !is_asyn) {
|
||||
/* Not supposed to block. */
|
||||
ret = cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid);
|
||||
if (ret == EINTR)
|
||||
ret = EAGAIN;
|
||||
} else {
|
||||
/* select() will do suspending itself. */
|
||||
if(op != DEV_SELECT) {
|
||||
/* Suspend user. */
|
||||
wait_for(dp->dmap_driver);
|
||||
}
|
||||
assert(!GRANT_VALID(fp->fp_grant));
|
||||
fp->fp_grant = gid; /* revoke this when unsuspended. */
|
||||
fp->fp_ioproc = ioproc;
|
||||
|
||||
if ((flags & O_NONBLOCK) && !is_asyn) {
|
||||
/* Not supposed to block, send cancel message */
|
||||
cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid);
|
||||
/*
|
||||
* FIXME Should do something about EINTR -> EAGAIN
|
||||
* mapping
|
||||
*/
|
||||
}
|
||||
return(SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
/* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
|
||||
if(safe) cpf_revoke(gid);
|
||||
|
||||
return ret;
|
||||
return SUSPEND;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -545,20 +388,30 @@ int gen_opcl(
|
|||
dev_mess.BDEV_MINOR = minor_dev;
|
||||
dev_mess.BDEV_ACCESS = flags;
|
||||
dev_mess.BDEV_ID = 0;
|
||||
|
||||
/* Call the task. */
|
||||
r = block_io(dp->dmap_driver, &dev_mess);
|
||||
} else {
|
||||
dev_mess.m_type = op;
|
||||
dev_mess.DEVICE = minor_dev;
|
||||
dev_mess.USER_ENDPT = proc_e;
|
||||
dev_mess.COUNT = flags;
|
||||
|
||||
/* Call the task. */
|
||||
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
}
|
||||
|
||||
/* Call the task. */
|
||||
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
if (r != OK) return(r);
|
||||
|
||||
if (op == DEV_OPEN && dp->dmap_style == STYLE_DEVA) {
|
||||
if (op == DEV_OPEN) {
|
||||
fp->fp_task = dp->dmap_driver;
|
||||
self->w_task = dp->dmap_driver;
|
||||
self->w_drv_sendrec = &dev_mess;
|
||||
|
||||
worker_wait();
|
||||
|
||||
self->w_task = NONE;
|
||||
self->w_drv_sendrec = NULL;
|
||||
}
|
||||
|
||||
if (is_bdev)
|
||||
|
|
@ -662,9 +515,9 @@ int do_ioctl(message *UNUSED(m_out))
|
|||
dev_t dev;
|
||||
void *argx;
|
||||
|
||||
scratch(fp).file.fd_nr = job_m_in.ls_fd;
|
||||
ioctlrequest = job_m_in.REQUEST;
|
||||
argx = job_m_in.ADDRESS;
|
||||
scratch(fp).file.fd_nr = job_m_in.VFS_IOCTL_FD;
|
||||
ioctlrequest = job_m_in.VFS_IOCTL_REQ;
|
||||
argx = job_m_in.VFS_IOCTL_ARG;
|
||||
|
||||
if ((f = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL)
|
||||
return(err_code);
|
||||
|
|
@ -680,7 +533,7 @@ int do_ioctl(message *UNUSED(m_out))
|
|||
if (S_ISBLK(vp->v_mode))
|
||||
r = bdev_ioctl(dev, who_e, ioctlrequest, argx);
|
||||
else
|
||||
r = dev_io(VFS_DEV_IOCTL, dev, who_e, argx, ((u64_t)(0)),
|
||||
r = dev_io(DEV_IOCTL_S, dev, who_e, argx, 0,
|
||||
ioctlrequest, f->filp_flags, suspend_reopen);
|
||||
}
|
||||
|
||||
|
|
@ -691,31 +544,100 @@ int do_ioctl(message *UNUSED(m_out))
|
|||
|
||||
|
||||
/*===========================================================================*
|
||||
* gen_io *
|
||||
* dev_select *
|
||||
*===========================================================================*/
|
||||
int gen_io(driver_e, mess_ptr)
|
||||
endpoint_t driver_e; /* which endpoint to call */
|
||||
message *mess_ptr; /* pointer to message for task */
|
||||
int dev_select(dev_t dev, int ops)
|
||||
{
|
||||
/* All file system I/O ultimately comes down to I/O on major/minor device
|
||||
* pairs. These lead to calls on the following routines via the dmap table.
|
||||
/* Initiate a select call on a device. Return OK iff the request was sent. */
|
||||
int major_dev, minor_dev;
|
||||
message dev_mess;
|
||||
struct dmap *dp;
|
||||
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
dp = &dmap[major_dev];
|
||||
|
||||
if (dp->dmap_driver == NONE) return ENXIO;
|
||||
|
||||
memset(&dev_mess, 0, sizeof(dev_mess));
|
||||
|
||||
dev_mess.m_type = DEV_SELECT;
|
||||
dev_mess.DEV_MINOR = minor_dev;
|
||||
dev_mess.DEV_SEL_OPS = ops;
|
||||
|
||||
/* Call the task. */
|
||||
return (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dev_cancel *
|
||||
*===========================================================================*/
|
||||
int dev_cancel(dev_t dev)
|
||||
{
|
||||
/* Cancel an I/O request, blocking until it has been cancelled. */
|
||||
int r, minor_dev, major_dev;
|
||||
message dev_mess;
|
||||
struct dmap *dp;
|
||||
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
dp = &dmap[major_dev];
|
||||
|
||||
memset(&dev_mess, 0, sizeof(dev_mess));
|
||||
|
||||
dev_mess.m_type = CANCEL;
|
||||
dev_mess.DEVICE = minor_dev;
|
||||
dev_mess.USER_ENDPT = fp->fp_ioproc;
|
||||
dev_mess.IO_GRANT = (char *) fp->fp_grant;
|
||||
|
||||
/* Tell driver R or W. Mode is from current call, not open. */
|
||||
/* FIXME: ioctls also pass through here! */
|
||||
dev_mess.COUNT = fp->fp_block_callnr == READ ? R_BIT : W_BIT;
|
||||
|
||||
r = (*dp->dmap_io)(fp->fp_task, &dev_mess);
|
||||
if (r != OK) return r; /* ctty_io returned an error? should be impossible */
|
||||
|
||||
/* Suspend this thread until we have received the response. */
|
||||
fp->fp_task = dp->dmap_driver;
|
||||
self->w_task = dp->dmap_driver;
|
||||
self->w_drv_sendrec = &dev_mess;
|
||||
|
||||
worker_wait();
|
||||
|
||||
self->w_task = NONE;
|
||||
self->w_drv_sendrec = NULL;
|
||||
|
||||
/* Clean up and return the result (note: the request may have completed). */
|
||||
if (GRANT_VALID(fp->fp_grant)) {
|
||||
(void) cpf_revoke(fp->fp_grant);
|
||||
fp->fp_grant = GRANT_INVALID;
|
||||
}
|
||||
|
||||
r = dev_mess.REP_STATUS;
|
||||
return (r == EAGAIN) ? EINTR : r;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* block_io *
|
||||
*===========================================================================*/
|
||||
static int block_io(endpoint_t driver_e, message *mess_ptr)
|
||||
{
|
||||
/* Perform I/O on a block device. The current thread is suspended until a reply
|
||||
* comes in from the driver.
|
||||
*/
|
||||
int r, status = OK, proc_e = NONE, is_bdev, retry_count;
|
||||
int r, status, retry_count;
|
||||
message mess_retry;
|
||||
|
||||
is_bdev = IS_BDEV_RQ(mess_ptr->m_type);
|
||||
assert(IS_BDEV_RQ(mess_ptr->m_type));
|
||||
mess_retry = *mess_ptr;
|
||||
retry_count = 0;
|
||||
|
||||
if (!is_bdev) proc_e = mess_ptr->USER_ENDPT;
|
||||
|
||||
do {
|
||||
r = drv_sendrec(driver_e, mess_ptr);
|
||||
if (r == OK) {
|
||||
if (is_bdev)
|
||||
status = mess_ptr->BDEV_STATUS;
|
||||
else
|
||||
status = mess_ptr->REP_STATUS;
|
||||
status = mess_ptr->BDEV_STATUS;
|
||||
if (status == ERESTART) {
|
||||
r = EDEADEPT;
|
||||
*mess_ptr = mess_retry;
|
||||
|
|
@ -739,41 +661,26 @@ message *mess_ptr; /* pointer to message for task */
|
|||
printf("VFS: ELOCKED talking to %d\n", driver_e);
|
||||
return(r);
|
||||
}
|
||||
panic("call_task: can't send/receive: %d", r);
|
||||
panic("block_io: can't send/receive: %d", r);
|
||||
}
|
||||
|
||||
/* Did the process we did the sendrec() for get a result? */
|
||||
if (!is_bdev && mess_ptr->REP_ENDPT != proc_e && mess_ptr->m_type != EIO) {
|
||||
printf("VFS: strange device reply from %d, type = %d, "
|
||||
"proc = %d (not %d) (2) ignored\n", mess_ptr->m_source,
|
||||
mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT);
|
||||
|
||||
return(EIO);
|
||||
} else if (!IS_DRV_REPLY(mess_ptr->m_type))
|
||||
return(EIO);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* asyn_io *
|
||||
* gen_io *
|
||||
*===========================================================================*/
|
||||
int asyn_io(endpoint_t drv_e, message *mess_ptr)
|
||||
int gen_io(endpoint_t drv_e, message *mess_ptr)
|
||||
{
|
||||
/* All file system I/O ultimately comes down to I/O on major/minor device
|
||||
* pairs. These lead to calls on the following routines via the dmap table.
|
||||
*/
|
||||
|
||||
/* Initiate I/O to a character driver. Do not wait for the reply. */
|
||||
int r;
|
||||
|
||||
assert(!IS_BDEV_RQ(mess_ptr->m_type));
|
||||
self->w_drv_sendrec = mess_ptr; /* Remember where result should be stored */
|
||||
self->w_task = drv_e;
|
||||
|
||||
r = asynsend3(drv_e, mess_ptr, AMF_NOREPLY);
|
||||
|
||||
if (r != OK) panic("VFS: asynsend in asyn_io failed: %d", r);
|
||||
if (r != OK) panic("VFS: asynsend in gen_io failed: %d", r);
|
||||
|
||||
/* Fake a SUSPEND */
|
||||
mess_ptr->REP_STATUS = SUSPEND;
|
||||
|
|
@ -798,7 +705,7 @@ int ctty_io(
|
|||
|
||||
if (fp->fp_tty == 0) {
|
||||
/* No controlling tty present anymore, return an I/O error. */
|
||||
mess_ptr->REP_STATUS = EIO;
|
||||
return(EIO);
|
||||
} else {
|
||||
/* Substitute the controlling terminal device. */
|
||||
dp = &dmap[major(fp->fp_tty)];
|
||||
|
|
@ -814,10 +721,8 @@ int ctty_io(
|
|||
return(EIO);
|
||||
}
|
||||
|
||||
(*dp->dmap_io)(dp->dmap_driver, mess_ptr);
|
||||
return (*dp->dmap_io)(dp->dmap_driver, mess_ptr);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -889,10 +794,16 @@ int clone_opcl(
|
|||
r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
|
||||
if (r != OK) return(r);
|
||||
|
||||
if (op == DEV_OPEN && dev_style_asyn(dp->dmap_style)) {
|
||||
/* Wait for reply when driver is asynchronous */
|
||||
if (op == DEV_OPEN) {
|
||||
/* Wait for the reply. */
|
||||
fp->fp_task = dp->dmap_driver;
|
||||
self->w_task = dp->dmap_driver;
|
||||
self->w_drv_sendrec = &dev_mess;
|
||||
|
||||
worker_wait();
|
||||
|
||||
self->w_task = NONE;
|
||||
self->w_drv_sendrec = NULL;
|
||||
}
|
||||
|
||||
if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) {
|
||||
|
|
@ -1011,30 +922,10 @@ void cdev_up(int maj)
|
|||
{
|
||||
/* A new character device driver has been mapped in.
|
||||
*/
|
||||
int needs_reopen, fd_nr;
|
||||
int needs_reopen;
|
||||
struct filp *rfilp;
|
||||
struct fproc *rfp;
|
||||
struct vnode *vp;
|
||||
|
||||
/* Look for processes that are suspended in an OPEN call. Set FP_SUSP_REOPEN
|
||||
* to indicate that this process was suspended before the call to dev_up.
|
||||
*/
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if(rfp->fp_pid == PID_FREE) continue;
|
||||
if(rfp->fp_blocked_on != FP_BLOCKED_ON_DOPEN) continue;
|
||||
|
||||
fd_nr = scratch(rfp).file.fd_nr;
|
||||
printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n",
|
||||
fd_nr);
|
||||
rfilp = rfp->fp_filp[fd_nr];
|
||||
vp = rfilp->filp_vno;
|
||||
if (!vp) panic("VFS: cdev_up: no vp");
|
||||
if (!S_ISCHR(vp->v_mode)) continue;
|
||||
if (major(vp->v_sdev) != maj) continue;
|
||||
|
||||
rfp->fp_flags |= FP_SUSP_REOPEN;
|
||||
}
|
||||
|
||||
needs_reopen= FALSE;
|
||||
for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) {
|
||||
if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue;
|
||||
|
|
@ -1052,32 +943,122 @@ void cdev_up(int maj)
|
|||
/*===========================================================================*
|
||||
* open_reply *
|
||||
*===========================================================================*/
|
||||
void open_reply(void)
|
||||
static void open_reply(message *m_ptr)
|
||||
{
|
||||
/* A character driver has replied to an open request. This function MUST NOT
|
||||
* block its calling thread.
|
||||
*/
|
||||
struct fproc *rfp;
|
||||
struct worker_thread *wp;
|
||||
endpoint_t proc_e;
|
||||
int slot;
|
||||
|
||||
proc_e = job_m_in.REP_ENDPT;
|
||||
proc_e = m_ptr->REP_ENDPT;
|
||||
if (isokendpt(proc_e, &slot) != OK) return;
|
||||
rfp = &fproc[slot];
|
||||
wp = worker_get(rfp->fp_wtid);
|
||||
wp = rfp->fp_worker;
|
||||
if (wp == NULL || wp->w_task != who_e) {
|
||||
printf("VFS: no worker thread waiting for a reply from %d\n", who_e);
|
||||
return;
|
||||
}
|
||||
*wp->w_drv_sendrec = job_m_in;
|
||||
wp->w_drv_sendrec = NULL;
|
||||
wp->w_task = NONE;
|
||||
*wp->w_drv_sendrec = *m_ptr;
|
||||
worker_signal(wp); /* Continue open */
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dev_reply *
|
||||
* task_reply *
|
||||
*===========================================================================*/
|
||||
void dev_reply(struct dmap *dp)
|
||||
static void task_reply(message *m_ptr)
|
||||
{
|
||||
/* A character driver has results for a read, write, or ioctl call. There may
|
||||
* be a thread waiting for these results as part of an ongoing dev_cancel call.
|
||||
* If so, wake up that thread; if not, send a reply to the requesting process.
|
||||
* This function MUST NOT block its calling thread.
|
||||
*/
|
||||
struct fproc *rfp;
|
||||
struct worker_thread *wp;
|
||||
endpoint_t proc_e;
|
||||
int slot;
|
||||
|
||||
proc_e = m_ptr->REP_ENDPT;
|
||||
if (proc_e == VFS_PROC_NR)
|
||||
proc_e = find_suspended_ep(m_ptr->m_source, m_ptr->REP_IO_GRANT);
|
||||
else
|
||||
printf("VFS: endpoint %u from %u is not VFS\n",
|
||||
proc_e, m_ptr->m_source);
|
||||
|
||||
if (proc_e == NONE) {
|
||||
printf("VFS: proc with grant %d from %d not found\n",
|
||||
m_ptr->REP_IO_GRANT, m_ptr->m_source);
|
||||
} else if (m_ptr->REP_STATUS == SUSPEND) {
|
||||
printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n");
|
||||
} else {
|
||||
/* If there is a thread active for this process, we assume that this
|
||||
* thread aims to cancel the ongoing operation. In that case, wake up
|
||||
* the thread to let it finish unpausing the process. Otherwise, revive
|
||||
* the process as usual.
|
||||
*/
|
||||
if (isokendpt(proc_e, &slot) != OK) return;
|
||||
rfp = &fproc[slot];
|
||||
wp = rfp->fp_worker;
|
||||
if (wp != NULL && wp->w_task == who_e) {
|
||||
assert(!fp_is_blocked(rfp));
|
||||
*wp->w_drv_sendrec = *m_ptr;
|
||||
worker_signal(wp); /* Continue cancel */
|
||||
} else {
|
||||
revive(proc_e, m_ptr->REP_STATUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* close_reply *
|
||||
*===========================================================================*/
|
||||
static void close_reply(message *m_ptr __unused)
|
||||
{
|
||||
/* A character driver replied to a close request. There is no need to do
|
||||
* anything here, because we cheat: we assume that the close operation will
|
||||
* succeed anyway, so we don't wait for the reply.
|
||||
*/
|
||||
|
||||
/* Nothing. */
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* cdev_reply *
|
||||
*===========================================================================*/
|
||||
void cdev_reply(void)
|
||||
{
|
||||
/* A character driver has results for us. */
|
||||
|
||||
switch (call_nr) {
|
||||
case DEV_OPEN_REPL: open_reply(&m_in); break;
|
||||
case DEV_REOPEN_REPL: reopen_reply(&m_in); break;
|
||||
case DEV_CLOSE_REPL: close_reply(&m_in); break;
|
||||
case DEV_REVIVE: task_reply(&m_in); break;
|
||||
case DEV_SEL_REPL1:
|
||||
select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS);
|
||||
break;
|
||||
case DEV_SEL_REPL2:
|
||||
select_reply2(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS);
|
||||
break;
|
||||
default:
|
||||
printf("VFS: char driver %u sent unknown reply %x\n", who_e, call_nr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* bdev_reply *
|
||||
*===========================================================================*/
|
||||
void bdev_reply(struct dmap *dp)
|
||||
{
|
||||
/* A block driver has results for a call. There must be a thread waiting for
|
||||
* these results - wake it up. This function MUST NOT block its calling thread.
|
||||
*/
|
||||
struct worker_thread *wp;
|
||||
|
||||
assert(dp != NULL);
|
||||
|
|
@ -1096,13 +1077,27 @@ void dev_reply(struct dmap *dp)
|
|||
worker_signal(wp);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* filp_gc_thread *
|
||||
*===========================================================================*/
|
||||
static void filp_gc_thread(void)
|
||||
{
|
||||
/* Filp garbage collection thread function. Since new filps may be invalidated
|
||||
* while the actual garbage collection procedure is running, we repeat the
|
||||
* procedure until it can not find any more work to do.
|
||||
*/
|
||||
|
||||
while (do_filp_gc())
|
||||
/* simply repeat */;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* restart_reopen *
|
||||
*===========================================================================*/
|
||||
static void restart_reopen(maj)
|
||||
int maj;
|
||||
{
|
||||
int n, r, minor_dev, major_dev, fd_nr;
|
||||
int n, r, minor_dev, major_dev;
|
||||
endpoint_t driver_e;
|
||||
struct vnode *vp;
|
||||
struct filp *rfilp;
|
||||
|
|
@ -1143,9 +1138,14 @@ int maj;
|
|||
|
||||
/* We have to clean up this filp and vnode, but can't do that yet as
|
||||
* it's locked by a worker thread. Start a new job to garbage collect
|
||||
* invalidated filps associated with this device driver.
|
||||
* invalidated filps associated with this device driver. This thread
|
||||
* is associated with a process that we know is idle otherwise: VFS.
|
||||
* Be careful that we don't start two threads or lose work, though.
|
||||
*/
|
||||
sys_worker_start(do_filp_gc);
|
||||
if (worker_can_start(fproc_addr(VFS_PROC_NR))) {
|
||||
worker_start(fproc_addr(VFS_PROC_NR), filp_gc_thread,
|
||||
&m_out /*unused*/, FALSE /*use_spare*/);
|
||||
}
|
||||
}
|
||||
|
||||
/* Nothing more to re-open. Restart suspended processes */
|
||||
|
|
@ -1159,41 +1159,13 @@ int maj;
|
|||
reply(&m_out, rfp->fp_endpoint, ERESTART);
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for processes that are suspened in an OPEN call */
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if (rfp->fp_pid == PID_FREE) continue;
|
||||
if (rfp->fp_blocked_on == FP_BLOCKED_ON_DOPEN ||
|
||||
!(rfp->fp_flags & FP_SUSP_REOPEN)) continue;
|
||||
|
||||
fd_nr = scratch(rfp).file.fd_nr;
|
||||
printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n",
|
||||
fd_nr);
|
||||
rfilp = rfp->fp_filp[fd_nr];
|
||||
|
||||
if (!rfilp) {
|
||||
/* Open failed, and automatic reopen was not requested */
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
FD_CLR(fd_nr, &rfp->fp_filp_inuse);
|
||||
reply(&m_out, rfp->fp_endpoint, EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
vp = rfilp->filp_vno;
|
||||
if (!vp) panic("VFS: restart_reopen: no vp");
|
||||
if (!S_ISCHR(vp->v_mode)) continue;
|
||||
if (major(vp->v_sdev) != maj) continue;
|
||||
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
reply(&m_out, rfp->fp_endpoint, fd_nr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* reopen_reply *
|
||||
*===========================================================================*/
|
||||
void reopen_reply()
|
||||
static void reopen_reply(message *m_ptr)
|
||||
{
|
||||
endpoint_t driver_e;
|
||||
int filp_no, status, maj;
|
||||
|
|
@ -1201,9 +1173,9 @@ void reopen_reply()
|
|||
struct vnode *vp;
|
||||
struct dmap *dp;
|
||||
|
||||
driver_e = job_m_in.m_source;
|
||||
filp_no = job_m_in.REP_ENDPT;
|
||||
status = job_m_in.REP_STATUS;
|
||||
driver_e = m_ptr->m_source;
|
||||
filp_no = m_ptr->REP_ENDPT;
|
||||
status = m_ptr->REP_STATUS;
|
||||
|
||||
if (filp_no < 0 || filp_no >= NR_FILPS) {
|
||||
printf("VFS: reopen_reply: bad filp number %d from driver %d\n",
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
#include <unistd.h>
|
||||
#include <minix/com.h>
|
||||
#include <minix/ds.h>
|
||||
#include "fproc.h"
|
||||
#include "dmap.h"
|
||||
#include "param.h"
|
||||
|
||||
/* The order of the entries in the table determines the mapping between major
|
||||
|
|
@ -24,9 +22,6 @@
|
|||
|
||||
struct dmap dmap[NR_DEVICES];
|
||||
|
||||
#define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL, NONE, \
|
||||
0, NULL, 0}
|
||||
|
||||
/*===========================================================================*
|
||||
* lock_dmap *
|
||||
*===========================================================================*/
|
||||
|
|
@ -34,20 +29,17 @@ void lock_dmap(struct dmap *dp)
|
|||
{
|
||||
/* Lock a driver */
|
||||
struct worker_thread *org_self;
|
||||
struct fproc *org_fp;
|
||||
int r;
|
||||
|
||||
assert(dp != NULL);
|
||||
assert(dp->dmap_driver != NONE);
|
||||
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
org_self = worker_suspend();
|
||||
|
||||
if ((r = mutex_lock(dp->dmap_lock_ref)) != 0)
|
||||
panic("unable to get a lock on dmap: %d\n", r);
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
worker_resume(org_self);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -182,10 +174,6 @@ int flags; /* device flags */
|
|||
dp->dmap_opcl = gen_opcl;
|
||||
dp->dmap_io = gen_io;
|
||||
break;
|
||||
case STYLE_DEVA:
|
||||
dp->dmap_opcl = gen_opcl;
|
||||
dp->dmap_io = asyn_io;
|
||||
break;
|
||||
case STYLE_TTY:
|
||||
dp->dmap_opcl = tty_opcl;
|
||||
dp->dmap_io = gen_io;
|
||||
|
|
@ -198,10 +186,6 @@ int flags; /* device flags */
|
|||
dp->dmap_opcl = clone_opcl;
|
||||
dp->dmap_io = gen_io;
|
||||
break;
|
||||
case STYLE_CLONE_A:
|
||||
dp->dmap_opcl = clone_opcl;
|
||||
dp->dmap_io = asyn_io;
|
||||
break;
|
||||
default:
|
||||
return(EINVAL);
|
||||
}
|
||||
|
|
@ -289,10 +273,16 @@ void init_dmap()
|
|||
{
|
||||
/* Initialize the table with empty device <-> driver mappings. */
|
||||
int i;
|
||||
struct dmap dmap_default = DT_EMPTY;
|
||||
|
||||
for (i = 0; i < NR_DEVICES; i++)
|
||||
dmap[i] = dmap_default;
|
||||
memset(dmap, 0, sizeof(dmap));
|
||||
|
||||
for (i = 0; i < NR_DEVICES; i++) {
|
||||
dmap[i].dmap_opcl = no_dev;
|
||||
dmap[i].dmap_io = no_dev_io;
|
||||
dmap[i].dmap_driver = NONE;
|
||||
dmap[i].dmap_style = STYLE_NDEV;
|
||||
dmap[i].dmap_servicing = NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ extern struct dmap {
|
|||
char dmap_label[LABEL_MAX];
|
||||
int dmap_flags;
|
||||
int dmap_style;
|
||||
int dmap_sel_busy;
|
||||
struct filp *dmap_sel_filp;
|
||||
endpoint_t dmap_servicing;
|
||||
mutex_t dmap_lock;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/param.h>
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
#include "param.h"
|
||||
#include "vnode.h"
|
||||
|
|
@ -53,8 +52,6 @@ struct vfs_exec_info {
|
|||
int vmfd_used;
|
||||
};
|
||||
|
||||
static void lock_exec(void);
|
||||
static void unlock_exec(void);
|
||||
static int patch_stack(struct vnode *vp, char stack[ARG_MAX],
|
||||
size_t *stk_bytes, char path[PATH_MAX]);
|
||||
static int is_script(struct vfs_exec_info *execi);
|
||||
|
|
@ -82,36 +79,8 @@ static const struct exec_loaders exec_loaders[] = {
|
|||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*===========================================================================*
|
||||
* lock_exec *
|
||||
*===========================================================================*/
|
||||
static void lock_exec(void)
|
||||
{
|
||||
struct fproc *org_fp;
|
||||
struct worker_thread *org_self;
|
||||
|
||||
/* First try to get it right off the bat */
|
||||
if (mutex_trylock(&exec_lock) == 0)
|
||||
return;
|
||||
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
|
||||
if (mutex_lock(&exec_lock) != 0)
|
||||
panic("Could not obtain lock on exec");
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* unlock_exec *
|
||||
*===========================================================================*/
|
||||
static void unlock_exec(void)
|
||||
{
|
||||
if (mutex_unlock(&exec_lock) != 0)
|
||||
panic("Could not release lock on exec");
|
||||
}
|
||||
#define lock_exec() lock_proc(fproc_addr(VM_PROC_NR))
|
||||
#define unlock_exec() unlock_proc(fproc_addr(VM_PROC_NR))
|
||||
|
||||
/*===========================================================================*
|
||||
* get_read_vp *
|
||||
|
|
@ -212,17 +181,15 @@ static int vfs_memmap(struct exec_info *execi,
|
|||
/*===========================================================================*
|
||||
* pm_exec *
|
||||
*===========================================================================*/
|
||||
int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
||||
vir_bytes frame, size_t frame_len, vir_bytes *pc,
|
||||
vir_bytes *newsp, int user_exec_flags)
|
||||
int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
|
||||
vir_bytes *pc, vir_bytes *newsp, int user_exec_flags)
|
||||
{
|
||||
/* Perform the execve(name, argv, envp) call. The user library builds a
|
||||
* complete stack image, including pointers, args, environ, etc. The stack
|
||||
* is copied to a buffer inside VFS, and then to the new core image.
|
||||
*/
|
||||
int r, slot;
|
||||
int r;
|
||||
vir_bytes vsp;
|
||||
struct fproc *rfp;
|
||||
int extrabase = 0;
|
||||
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
|
||||
struct vfs_exec_info execi;
|
||||
|
|
@ -232,14 +199,13 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
firstexec[PATH_MAX],
|
||||
finalexec[PATH_MAX];
|
||||
struct lookup resolve;
|
||||
struct fproc *vmfp = &fproc[VM_PROC_NR];
|
||||
struct fproc *vmfp = fproc_addr(VM_PROC_NR);
|
||||
stackhook_t makestack = NULL;
|
||||
static int n;
|
||||
n++;
|
||||
struct filp *newfilp = NULL;
|
||||
|
||||
lock_exec();
|
||||
lock_proc(vmfp, 0);
|
||||
|
||||
/* unset execi values are 0. */
|
||||
memset(&execi, 0, sizeof(execi));
|
||||
|
|
@ -250,10 +216,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
execi.args.stack_high = kinfo.user_sp;
|
||||
execi.args.stack_size = DEFAULT_STACK_LIMIT;
|
||||
|
||||
okendpt(proc_e, &slot);
|
||||
rfp = fp = &fproc[slot];
|
||||
rfp->text_size = 0;
|
||||
rfp->data_size = 0;
|
||||
fp->text_size = 0;
|
||||
fp->data_size = 0;
|
||||
|
||||
lookup_init(&resolve, fullpath, PATH_NOFLAGS, &execi.vmp, &execi.vp);
|
||||
|
||||
|
|
@ -264,7 +228,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
if (frame_len > ARG_MAX)
|
||||
FAILCHECK(ENOMEM); /* stack too big */
|
||||
|
||||
r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf,
|
||||
r = sys_datacopy(fp->fp_endpoint, (vir_bytes) frame, SELF, (vir_bytes) mbuf,
|
||||
(size_t) frame_len);
|
||||
if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */
|
||||
printf("VFS: pm_exec: sys_datacopy failed\n");
|
||||
|
|
@ -272,8 +236,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
}
|
||||
|
||||
/* The default is to keep the original user and group IDs */
|
||||
execi.args.new_uid = rfp->fp_effuid;
|
||||
execi.args.new_gid = rfp->fp_effgid;
|
||||
execi.args.new_uid = fp->fp_effuid;
|
||||
execi.args.new_gid = fp->fp_effgid;
|
||||
|
||||
/* Get the exec file name. */
|
||||
FAILCHECK(fetch_name(path, path_len, fullpath));
|
||||
|
|
@ -369,7 +333,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
execi.args.allocmem_ondemand = libexec_alloc_mmap_ondemand;
|
||||
execi.args.opaque = &execi;
|
||||
|
||||
execi.args.proc_e = proc_e;
|
||||
execi.args.proc_e = fp->fp_endpoint;
|
||||
execi.args.frame_len = frame_len;
|
||||
execi.args.filesize = execi.vp->v_size;
|
||||
|
||||
|
|
@ -382,7 +346,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
FAILCHECK(r);
|
||||
|
||||
/* Inform PM */
|
||||
FAILCHECK(libexec_pm_newexec(proc_e, &execi.args));
|
||||
FAILCHECK(libexec_pm_newexec(fp->fp_endpoint, &execi.args));
|
||||
|
||||
/* Save off PC */
|
||||
*pc = execi.args.pc;
|
||||
|
|
@ -393,25 +357,25 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
|
|||
|
||||
/* Patch up stack and copy it from VFS to new core image. */
|
||||
libexec_patch_ptr(mbuf, vsp + extrabase);
|
||||
FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp,
|
||||
(phys_bytes)frame_len));
|
||||
FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, fp->fp_endpoint,
|
||||
(vir_bytes) vsp, (phys_bytes)frame_len));
|
||||
|
||||
/* Return new stack pointer to caller */
|
||||
*newsp = vsp;
|
||||
|
||||
clo_exec(rfp);
|
||||
clo_exec(fp);
|
||||
|
||||
if (execi.args.allow_setuid) {
|
||||
/* If after loading the image we're still allowed to run with
|
||||
* setuid or setgid, change credentials now */
|
||||
rfp->fp_effuid = execi.args.new_uid;
|
||||
rfp->fp_effgid = execi.args.new_gid;
|
||||
fp->fp_effuid = execi.args.new_uid;
|
||||
fp->fp_effgid = execi.args.new_gid;
|
||||
}
|
||||
|
||||
/* Remember the new name of the process */
|
||||
strlcpy(rfp->fp_name, execi.args.progname, PROC_NAME_LEN);
|
||||
rfp->text_size = execi.args.text_size;
|
||||
rfp->data_size = execi.args.data_size;
|
||||
strlcpy(fp->fp_name, execi.args.progname, PROC_NAME_LEN);
|
||||
fp->text_size = execi.args.text_size;
|
||||
fp->data_size = execi.args.data_size;
|
||||
|
||||
pm_execfinal:
|
||||
if(newfilp) unlock_filp(newfilp);
|
||||
|
|
@ -426,7 +390,6 @@ pm_execfinal:
|
|||
}
|
||||
}
|
||||
|
||||
unlock_proc(vmfp);
|
||||
unlock_exec();
|
||||
|
||||
return(r);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ EXTERN struct filp {
|
|||
|
||||
/* the following fields are for select() and are owned by the generic
|
||||
* select() code (i.e., fd-type-specific select() code can't touch these).
|
||||
* These fields may be changed without holding the filp lock.
|
||||
*/
|
||||
int filp_selectors; /* select()ing processes blocking on this fd */
|
||||
int filp_select_ops; /* interested in these SEL_* operations */
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include "fs.h"
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "vnode.h"
|
||||
|
||||
|
||||
|
|
@ -77,16 +76,22 @@ void check_filp_locks(void)
|
|||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_filp_gc *
|
||||
* do_filp_gc *
|
||||
*===========================================================================*/
|
||||
void *do_filp_gc(void *UNUSED(arg))
|
||||
int do_filp_gc(void)
|
||||
{
|
||||
/* Perform filp garbage collection. Return whether at least one invalidated
|
||||
* filp was found, in which case the entire procedure will be invoked again.
|
||||
*/
|
||||
struct filp *f;
|
||||
struct vnode *vp;
|
||||
int found = FALSE;
|
||||
|
||||
for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
|
||||
if (!(f->filp_state & FS_INVALIDATED)) continue;
|
||||
|
||||
found = TRUE;
|
||||
|
||||
if (f->filp_mode == FILP_CLOSED || f->filp_vno == NULL) {
|
||||
/* File was already closed before gc could kick in */
|
||||
assert(f->filp_count <= 0);
|
||||
|
|
@ -125,12 +130,11 @@ void *do_filp_gc(void *UNUSED(arg))
|
|||
f->filp_state &= ~FS_INVALIDATED;
|
||||
}
|
||||
|
||||
thread_cleanup(NULL);
|
||||
return(NULL);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* init_filps *
|
||||
* init_filps *
|
||||
*===========================================================================*/
|
||||
void init_filps(void)
|
||||
{
|
||||
|
|
@ -320,7 +324,6 @@ void lock_filp(filp, locktype)
|
|||
struct filp *filp;
|
||||
tll_access_t locktype;
|
||||
{
|
||||
struct fproc *org_fp;
|
||||
struct worker_thread *org_self;
|
||||
struct vnode *vp;
|
||||
|
||||
|
|
@ -350,14 +353,12 @@ tll_access_t locktype;
|
|||
if (mutex_trylock(&filp->filp_lock) != 0) {
|
||||
|
||||
/* Already in use, let's wait for our turn */
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
org_self = worker_suspend();
|
||||
|
||||
if (mutex_lock(&filp->filp_lock) != 0)
|
||||
panic("unable to obtain lock on filp");
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
worker_resume(org_self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,11 @@ EXTERN struct fproc {
|
|||
mode_t fp_umask; /* mask set by umask system call */
|
||||
|
||||
mutex_t fp_lock; /* mutex to lock fproc object */
|
||||
struct job fp_job; /* pending job */
|
||||
thread_t fp_wtid; /* Thread ID of worker */
|
||||
struct worker_thread *fp_worker;/* active worker thread, or NULL */
|
||||
void (*fp_func)(); /* handler function for pending work */
|
||||
message fp_msg; /* pending or active message from process */
|
||||
message fp_pm_msg; /* pending/active postponed PM request */
|
||||
|
||||
char fp_name[PROC_NAME_LEN]; /* Last exec() */
|
||||
#if LOCK_DEBUG
|
||||
int fp_vp_rdlocks; /* number of read-only locks on vnodes */
|
||||
|
|
@ -64,9 +67,8 @@ EXTERN struct fproc {
|
|||
#define FP_SESLDR 0004 /* Set if process is session leader */
|
||||
#define FP_PENDING 0010 /* Set if process has pending work */
|
||||
#define FP_EXITING 0020 /* Set if process is exiting */
|
||||
#define FP_PM_PENDING 0040 /* Set if process has pending PM request */
|
||||
#define FP_PM_WORK 0040 /* Set if process has a postponed PM request */
|
||||
#define FP_SRV_PROC 0100 /* Set if process is a service */
|
||||
#define FP_DROP_WORK 0200 /* Set if process won't accept new work */
|
||||
|
||||
/* Field values. */
|
||||
#define NOT_REVIVING 0xC0FFEEE /* process is not being revived */
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@
|
|||
#include "glo.h"
|
||||
#include "comm.h"
|
||||
#include "vmnt.h"
|
||||
#include "fproc.h"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
#include "fs.h"
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
|
||||
int gcov_flush(cp_grant_id_t grantid, size_t size );
|
||||
|
||||
|
|
|
|||
|
|
@ -25,24 +25,17 @@ EXTERN u32_t system_hz; /* system clock frequency. */
|
|||
/* The parameters of the call are kept here. */
|
||||
EXTERN message m_in; /* the input message itself */
|
||||
# define who_p ((int) (fp - fproc))
|
||||
# define isokslot(p) (p >= 0 && \
|
||||
p < (int)(sizeof(fproc) / sizeof(struct fproc)))
|
||||
# define who_e (self != NULL && fp != NULL ? fp->fp_endpoint : \
|
||||
m_in.m_source)
|
||||
# define fproc_addr(e) (&fproc[_ENDPOINT_P(e)])
|
||||
# define who_e (self != NULL ? fp->fp_endpoint : m_in.m_source)
|
||||
# define call_nr (m_in.m_type)
|
||||
# define job_m_in (self->w_job.j_m_in)
|
||||
# define job_m_in (self->w_msg)
|
||||
# define job_call_nr (job_m_in.m_type)
|
||||
# define super_user (fp->fp_effuid == SU_UID ? 1 : 0)
|
||||
# define scratch(p) (scratchpad[((int) ((p) - fproc))])
|
||||
EXTERN struct worker_thread *self;
|
||||
EXTERN int force_sync; /* toggle forced synchronous communication */
|
||||
EXTERN int deadlock_resolving;
|
||||
EXTERN mutex_t exec_lock;
|
||||
EXTERN mutex_t bsf_lock;/* Global lock for access to block special files */
|
||||
EXTERN struct worker_thread workers[NR_WTHREADS];
|
||||
EXTERN struct worker_thread sys_worker;
|
||||
EXTERN struct worker_thread dl_worker;
|
||||
EXTERN thread_t invalid_thread_id;
|
||||
EXTERN char mount_label[LABEL_MAX]; /* label of file system to mount */
|
||||
|
||||
/* The following variables are used for returning results to the caller. */
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef __VFS_WORK_H__
|
||||
#define __VFS_WORK_H__
|
||||
|
||||
struct job {
|
||||
struct fproc *j_fp;
|
||||
message j_m_in;
|
||||
int j_err_code;
|
||||
void *(*j_func)(void *arg);
|
||||
struct job *j_next;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
#include "vnode.h"
|
||||
#include "param.h"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "lock.h"
|
||||
#include "vnode.h"
|
||||
|
|
|
|||
|
|
@ -27,12 +27,9 @@
|
|||
#include <minix/debug.h>
|
||||
#include <minix/vfsif.h>
|
||||
#include "file.h"
|
||||
#include "dmap.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "vmnt.h"
|
||||
#include "vnode.h"
|
||||
#include "job.h"
|
||||
#include "param.h"
|
||||
|
||||
#if ENABLE_SYSCALL_STATS
|
||||
|
|
@ -40,26 +37,18 @@ EXTERN unsigned long calls_stats[NCALLS];
|
|||
#endif
|
||||
|
||||
/* Thread related prototypes */
|
||||
static void *do_async_dev_result(void *arg);
|
||||
static void *do_control_msgs(void *arg);
|
||||
static void *do_dev_event(void *arg);
|
||||
static void *do_fs_reply(struct job *job);
|
||||
static void *do_work(void *arg);
|
||||
static void *do_pm(void *arg);
|
||||
static void *do_init_root(void *arg);
|
||||
static void handle_work(void *(*func)(void *arg));
|
||||
static void do_fs_reply(struct worker_thread *wp);
|
||||
static void do_work(void);
|
||||
static void do_init_root(void);
|
||||
static void handle_work(void (*func)(void));
|
||||
|
||||
static void get_work(void);
|
||||
static void lock_pm(void);
|
||||
static void unlock_pm(void);
|
||||
static void service_pm(void);
|
||||
static void service_pm_postponed(void);
|
||||
static int unblock(struct fproc *rfp);
|
||||
|
||||
/* SEF functions and variables. */
|
||||
static void sef_local_startup(void);
|
||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
||||
static mutex_t pm_lock;
|
||||
static endpoint_t receive_from;
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -72,7 +61,7 @@ int main(void)
|
|||
* the reply. This loop never terminates as long as the file system runs.
|
||||
*/
|
||||
int transid;
|
||||
struct job *job;
|
||||
struct worker_thread *wp;
|
||||
|
||||
/* SEF local startup. */
|
||||
sef_local_startup();
|
||||
|
|
@ -86,38 +75,46 @@ int main(void)
|
|||
while (TRUE) {
|
||||
yield_all(); /* let other threads run */
|
||||
self = NULL;
|
||||
job = NULL;
|
||||
send_work();
|
||||
get_work();
|
||||
|
||||
transid = TRNS_GET_ID(m_in.m_type);
|
||||
if (IS_VFS_FS_TRANSID(transid)) {
|
||||
job = worker_getjob( (thread_t) transid - VFS_TRANSID);
|
||||
if (job == NULL) {
|
||||
wp = worker_get((thread_t) transid - VFS_TRANSID);
|
||||
if (wp == NULL || wp->w_fp == NULL) {
|
||||
printf("VFS: spurious message %d from endpoint %d\n",
|
||||
m_in.m_type, m_in.m_source);
|
||||
continue;
|
||||
}
|
||||
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
|
||||
}
|
||||
|
||||
if (job != NULL) {
|
||||
do_fs_reply(job);
|
||||
do_fs_reply(wp);
|
||||
continue;
|
||||
} else if (who_e == PM_PROC_NR) { /* Calls from PM */
|
||||
/* Special control messages from PM */
|
||||
sys_worker_start(do_pm);
|
||||
service_pm();
|
||||
continue;
|
||||
} else if (is_notify(call_nr)) {
|
||||
/* A task notify()ed us */
|
||||
if (who_e == DS_PROC_NR)
|
||||
handle_work(ds_event);
|
||||
else if (who_e == KERNEL)
|
||||
switch (who_e) {
|
||||
case DS_PROC_NR:
|
||||
/* Start a thread to handle DS events, if no thread
|
||||
* is pending or active for it already. DS is not
|
||||
* supposed to issue calls to VFS or be the subject of
|
||||
* postponed PM requests, so this should be no problem.
|
||||
*/
|
||||
if (worker_can_start(fp))
|
||||
handle_work(ds_event);
|
||||
break;
|
||||
case KERNEL:
|
||||
mthread_stacktraces();
|
||||
else if (fp != NULL && (fp->fp_flags & FP_SRV_PROC))
|
||||
handle_work(do_dev_event);
|
||||
else
|
||||
sys_worker_start(do_control_msgs);
|
||||
break;
|
||||
case CLOCK:
|
||||
/* Timer expired. Used only for select(). Check it. */
|
||||
expire_timers(m_in.NOTIFY_TIMESTAMP);
|
||||
break;
|
||||
default:
|
||||
printf("VFS: ignoring notification from %d\n", who_e);
|
||||
}
|
||||
continue;
|
||||
} else if (who_p < 0) { /* i.e., message comes from a task */
|
||||
/* We're going to ignore this message. Tasks should
|
||||
|
|
@ -140,15 +137,15 @@ int main(void)
|
|||
|
||||
dp = get_dmap(who_e);
|
||||
if (dp != NULL) {
|
||||
if (dev_style_asyn(dp->dmap_style)) {
|
||||
handle_work(do_async_dev_result);
|
||||
if (!IS_BDEV_RS(call_nr)) {
|
||||
cdev_reply();
|
||||
|
||||
} else {
|
||||
if (dp->dmap_servicing == NONE) {
|
||||
printf("Got spurious dev reply from %d",
|
||||
who_e);
|
||||
} else {
|
||||
dev_reply(dp);
|
||||
bdev_reply(dp);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
|
@ -166,217 +163,73 @@ int main(void)
|
|||
/*===========================================================================*
|
||||
* handle_work *
|
||||
*===========================================================================*/
|
||||
static void handle_work(void *(*func)(void *arg))
|
||||
static void handle_work(void (*func)(void))
|
||||
{
|
||||
/* Handle asynchronous device replies and new system calls. If the originating
|
||||
* endpoint is an FS endpoint, take extra care not to get in deadlock. */
|
||||
struct vmnt *vmp = NULL;
|
||||
endpoint_t proc_e;
|
||||
int use_spare = FALSE;
|
||||
|
||||
proc_e = m_in.m_source;
|
||||
|
||||
if (fp->fp_flags & FP_SRV_PROC) {
|
||||
vmp = find_vmnt(proc_e);
|
||||
if (vmp != NULL) {
|
||||
/* A call back or dev result from an FS
|
||||
* endpoint. Set call back flag. Can do only
|
||||
* one call back at a time.
|
||||
*/
|
||||
/* A callback from an FS endpoint. Can do only one at once. */
|
||||
if (vmp->m_flags & VMNT_CALLBACK) {
|
||||
replycode(proc_e, EAGAIN);
|
||||
return;
|
||||
}
|
||||
/* Already trying to resolve a deadlock? Can't handle more. */
|
||||
if (worker_available() == 0) {
|
||||
replycode(proc_e, EAGAIN);
|
||||
return;
|
||||
}
|
||||
/* A thread is available. Set callback flag. */
|
||||
vmp->m_flags |= VMNT_CALLBACK;
|
||||
if (vmp->m_flags & VMNT_MOUNTING) {
|
||||
vmp->m_flags |= VMNT_FORCEROOTBSF;
|
||||
}
|
||||
}
|
||||
|
||||
if (worker_available() == 0) {
|
||||
if (!deadlock_resolving) {
|
||||
deadlock_resolving = 1;
|
||||
dl_worker_start(func);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vmp != NULL) {
|
||||
/* Already trying to resolve a deadlock, can't
|
||||
* handle more, sorry */
|
||||
|
||||
replycode(proc_e, EAGAIN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Use the spare thread to handle this request if needed. */
|
||||
use_spare = TRUE;
|
||||
}
|
||||
|
||||
worker_start(func);
|
||||
worker_start(fp, func, &m_in, use_spare);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_async_dev_result *
|
||||
*===========================================================================*/
|
||||
static void *do_async_dev_result(void *arg)
|
||||
{
|
||||
endpoint_t endpt;
|
||||
struct job my_job;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
/* An asynchronous character driver has results for us */
|
||||
if (job_call_nr == DEV_REVIVE) {
|
||||
endpt = job_m_in.REP_ENDPT;
|
||||
if (endpt == VFS_PROC_NR)
|
||||
endpt = find_suspended_ep(job_m_in.m_source,
|
||||
job_m_in.REP_IO_GRANT);
|
||||
|
||||
if (endpt == NONE) {
|
||||
printf("VFS: proc with grant %d from %d not found\n",
|
||||
job_m_in.REP_IO_GRANT, job_m_in.m_source);
|
||||
} else if (job_m_in.REP_STATUS == SUSPEND) {
|
||||
printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n");
|
||||
} else
|
||||
revive(endpt, job_m_in.REP_STATUS);
|
||||
}
|
||||
else if (job_call_nr == DEV_OPEN_REPL) open_reply();
|
||||
else if (job_call_nr == DEV_REOPEN_REPL) reopen_reply();
|
||||
else if (job_call_nr == DEV_CLOSE_REPL) close_reply();
|
||||
else if (job_call_nr == DEV_SEL_REPL1)
|
||||
select_reply1(job_m_in.m_source, job_m_in.DEV_MINOR,
|
||||
job_m_in.DEV_SEL_OPS);
|
||||
else if (job_call_nr == DEV_SEL_REPL2)
|
||||
select_reply2(job_m_in.m_source, job_m_in.DEV_MINOR,
|
||||
job_m_in.DEV_SEL_OPS);
|
||||
|
||||
thread_cleanup(fp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_control_msgs *
|
||||
*===========================================================================*/
|
||||
static void *do_control_msgs(void *arg)
|
||||
{
|
||||
struct job my_job;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
/* Check for special control messages. */
|
||||
if (job_m_in.m_source == CLOCK) {
|
||||
/* Alarm timer expired. Used only for select(). Check it. */
|
||||
expire_timers(job_m_in.NOTIFY_TIMESTAMP);
|
||||
}
|
||||
|
||||
thread_cleanup(NULL);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_dev_event *
|
||||
*===========================================================================*/
|
||||
static void *do_dev_event(void *arg)
|
||||
{
|
||||
/* Device notifies us of an event. */
|
||||
struct job my_job;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
dev_status(job_m_in.m_source);
|
||||
|
||||
thread_cleanup(fp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_fs_reply *
|
||||
*===========================================================================*/
|
||||
static void *do_fs_reply(struct job *job)
|
||||
static void do_fs_reply(struct worker_thread *wp)
|
||||
{
|
||||
struct vmnt *vmp;
|
||||
struct worker_thread *wp;
|
||||
|
||||
if ((vmp = find_vmnt(who_e)) == NULL)
|
||||
panic("Couldn't find vmnt for endpoint %d", who_e);
|
||||
|
||||
wp = worker_get(job->j_fp->fp_wtid);
|
||||
|
||||
if (wp == NULL) {
|
||||
printf("VFS: spurious reply from %d\n", who_e);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (wp->w_task != who_e) {
|
||||
printf("VFS: expected %d to reply, not %d\n", wp->w_task, who_e);
|
||||
return(NULL);
|
||||
return;
|
||||
}
|
||||
*wp->w_fs_sendrec = m_in;
|
||||
wp->w_task = NONE;
|
||||
vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */
|
||||
worker_signal(wp); /* Continue this thread */
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* lock_pm *
|
||||
*===========================================================================*/
|
||||
static void lock_pm(void)
|
||||
{
|
||||
struct fproc *org_fp;
|
||||
struct worker_thread *org_self;
|
||||
|
||||
/* First try to get it right off the bat */
|
||||
if (mutex_trylock(&pm_lock) == 0)
|
||||
return;
|
||||
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
|
||||
if (mutex_lock(&pm_lock) != 0)
|
||||
panic("Could not obtain lock on pm\n");
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* unlock_pm *
|
||||
*===========================================================================*/
|
||||
static void unlock_pm(void)
|
||||
{
|
||||
if (mutex_unlock(&pm_lock) != 0)
|
||||
panic("Could not release lock on pm");
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_pm *
|
||||
*===========================================================================*/
|
||||
static void *do_pm(void *arg __unused)
|
||||
{
|
||||
lock_pm();
|
||||
service_pm();
|
||||
unlock_pm();
|
||||
|
||||
thread_cleanup(NULL);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_pending_pipe *
|
||||
*===========================================================================*/
|
||||
static void *do_pending_pipe(void *arg)
|
||||
static void do_pending_pipe(void)
|
||||
{
|
||||
int r, op;
|
||||
struct job my_job;
|
||||
struct filp *f;
|
||||
tll_access_t locktype;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
lock_proc(fp, 1 /* force lock */);
|
||||
|
||||
f = scratch(fp).file.filp;
|
||||
assert(f != NULL);
|
||||
scratch(fp).file.filp = NULL;
|
||||
|
|
@ -391,48 +244,18 @@ static void *do_pending_pipe(void *arg)
|
|||
replycode(fp->fp_endpoint, r);
|
||||
|
||||
unlock_filp(f);
|
||||
thread_cleanup(fp);
|
||||
unlock_proc(fp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_dummy *
|
||||
*===========================================================================*/
|
||||
void *do_dummy(void *arg)
|
||||
{
|
||||
struct job my_job;
|
||||
int r;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
if ((r = mutex_trylock(&fp->fp_lock)) == 0) {
|
||||
thread_cleanup(fp);
|
||||
unlock_proc(fp);
|
||||
} else {
|
||||
/* Proc is busy, let that worker thread carry out the work */
|
||||
thread_cleanup(NULL);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_work *
|
||||
*===========================================================================*/
|
||||
static void *do_work(void *arg)
|
||||
static void do_work(void)
|
||||
{
|
||||
int error;
|
||||
struct job my_job;
|
||||
message m_out;
|
||||
|
||||
memset(&m_out, 0, sizeof(m_out));
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
lock_proc(fp, 0); /* This proc is busy */
|
||||
|
||||
if (job_call_nr == MAPDRIVER) {
|
||||
error = do_mapdriver();
|
||||
} else if (job_call_nr == COMMON_GETSYSINFO) {
|
||||
|
|
@ -468,10 +291,6 @@ static void *do_work(void *arg)
|
|||
|
||||
/* Copy the results back to the user and send reply. */
|
||||
if (error != SUSPEND) reply(&m_out, fp->fp_endpoint, error);
|
||||
|
||||
thread_cleanup(fp);
|
||||
unlock_proc(fp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -500,7 +319,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
|
|||
message mess;
|
||||
struct rprocpub rprocpub[NR_BOOT_PROCS];
|
||||
|
||||
force_sync = 0;
|
||||
receive_from = ANY;
|
||||
self = NULL;
|
||||
verbose = 0;
|
||||
|
|
@ -541,8 +359,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
|
|||
s = send(PM_PROC_NR, &mess); /* send synchronization message */
|
||||
|
||||
/* All process table entries have been set. Continue with initialization. */
|
||||
fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with
|
||||
* FSes is on behalf of myself */
|
||||
init_dmap(); /* Initialize device table. */
|
||||
system_hz = sys_hz();
|
||||
|
||||
|
|
@ -564,28 +380,28 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
|
|||
if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s);
|
||||
|
||||
/* Initialize worker threads */
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
worker_init(&workers[i]);
|
||||
}
|
||||
worker_init(&sys_worker); /* exclusive system worker thread */
|
||||
worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */
|
||||
worker_init();
|
||||
|
||||
/* Initialize global locks */
|
||||
if (mthread_mutex_init(&pm_lock, NULL) != 0)
|
||||
panic("VFS: couldn't initialize pm lock mutex");
|
||||
if (mthread_mutex_init(&exec_lock, NULL) != 0)
|
||||
panic("VFS: couldn't initialize exec lock");
|
||||
if (mthread_mutex_init(&bsf_lock, NULL) != 0)
|
||||
panic("VFS: couldn't initialize block special file lock");
|
||||
|
||||
/* Initialize event resources for boot procs and locks for all procs */
|
||||
/* Initialize locks and initial values for all processes. */
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if (mutex_init(&rfp->fp_lock, NULL) != 0)
|
||||
panic("unable to initialize fproc lock");
|
||||
rfp->fp_worker = NULL;
|
||||
#if LOCK_DEBUG
|
||||
rfp->fp_vp_rdlocks = 0;
|
||||
rfp->fp_vmnt_rdlocks = 0;
|
||||
#endif
|
||||
|
||||
/* Initialize process directories. mount_fs will set them to the
|
||||
* correct values.
|
||||
*/
|
||||
FD_ZERO(&(rfp->fp_filp_inuse));
|
||||
rfp->fp_rd = NULL;
|
||||
rfp->fp_wd = NULL;
|
||||
}
|
||||
|
||||
init_dmap_locks(); /* init dmap locks */
|
||||
|
|
@ -594,9 +410,11 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
|
|||
init_select(); /* init select() structures */
|
||||
init_filps(); /* Init filp structures */
|
||||
mount_pfs(); /* mount Pipe File Server */
|
||||
worker_start(do_init_root); /* mount initial ramdisk as file system root */
|
||||
yield(); /* force do_init_root to start */
|
||||
self = NULL;
|
||||
|
||||
/* Mount initial ramdisk as file system root. */
|
||||
receive_from = MFS_PROC_NR;
|
||||
worker_start(fproc_addr(VFS_PROC_NR), do_init_root, &mess /*unused*/,
|
||||
FALSE /*use_spare*/);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
|
@ -604,66 +422,34 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
|
|||
/*===========================================================================*
|
||||
* do_init_root *
|
||||
*===========================================================================*/
|
||||
static void *do_init_root(void *arg)
|
||||
static void do_init_root(void)
|
||||
{
|
||||
struct fproc *rfp;
|
||||
struct job my_job;
|
||||
int r;
|
||||
char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
lock_proc(fp, 1 /* force lock */); /* This proc is busy */
|
||||
lock_pm();
|
||||
|
||||
/* Initialize process directories. mount_fs will set them to the correct
|
||||
* values */
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
FD_ZERO(&(rfp->fp_filp_inuse));
|
||||
rfp->fp_rd = NULL;
|
||||
rfp->fp_wd = NULL;
|
||||
}
|
||||
|
||||
receive_from = MFS_PROC_NR;
|
||||
r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_label);
|
||||
if (r != OK)
|
||||
panic("Failed to initialize root");
|
||||
receive_from = ANY;
|
||||
|
||||
unlock_pm();
|
||||
thread_cleanup(fp);
|
||||
unlock_proc(fp);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* lock_proc *
|
||||
*===========================================================================*/
|
||||
void lock_proc(struct fproc *rfp, int force_lock)
|
||||
void lock_proc(struct fproc *rfp)
|
||||
{
|
||||
int r;
|
||||
struct fproc *org_fp;
|
||||
struct worker_thread *org_self;
|
||||
|
||||
r = mutex_trylock(&rfp->fp_lock);
|
||||
|
||||
/* Were we supposed to obtain this lock immediately? */
|
||||
if (force_lock) {
|
||||
assert(r == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r == 0) return;
|
||||
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
org_self = worker_suspend();
|
||||
|
||||
if ((r = mutex_lock(&rfp->fp_lock)) != 0)
|
||||
panic("unable to lock fproc lock: %d", r);
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
worker_resume(org_self);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -680,48 +466,23 @@ void unlock_proc(struct fproc *rfp)
|
|||
/*===========================================================================*
|
||||
* thread_cleanup *
|
||||
*===========================================================================*/
|
||||
void thread_cleanup(struct fproc *rfp)
|
||||
void thread_cleanup(void)
|
||||
{
|
||||
/* Clean up worker thread. Skip parts if this thread is not associated
|
||||
* with a particular process (i.e., rfp is NULL) */
|
||||
/* Perform cleanup actions for a worker thread. */
|
||||
|
||||
#if LOCK_DEBUG
|
||||
if (rfp != NULL) {
|
||||
check_filp_locks_by_me();
|
||||
check_vnode_locks_by_me(rfp);
|
||||
check_vmnt_locks_by_me(rfp);
|
||||
}
|
||||
check_filp_locks_by_me();
|
||||
check_vnode_locks_by_me(fp);
|
||||
check_vmnt_locks_by_me(fp);
|
||||
#endif
|
||||
|
||||
if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */
|
||||
job_m_in = rfp->fp_job.j_m_in;
|
||||
rfp->fp_flags &= ~FP_PM_PENDING;
|
||||
service_pm_postponed();
|
||||
}
|
||||
if (fp->fp_flags & FP_SRV_PROC) {
|
||||
struct vmnt *vmp;
|
||||
|
||||
#if LOCK_DEBUG
|
||||
if (rfp != NULL) {
|
||||
check_filp_locks_by_me();
|
||||
check_vnode_locks_by_me(rfp);
|
||||
check_vmnt_locks_by_me(rfp);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rfp != NULL) {
|
||||
rfp->fp_flags &= ~FP_DROP_WORK;
|
||||
if (rfp->fp_flags & FP_SRV_PROC) {
|
||||
struct vmnt *vmp;
|
||||
|
||||
if ((vmp = find_vmnt(rfp->fp_endpoint)) != NULL) {
|
||||
vmp->m_flags &= ~VMNT_CALLBACK;
|
||||
}
|
||||
if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) {
|
||||
vmp->m_flags &= ~VMNT_CALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
if (deadlock_resolving) {
|
||||
if (self->w_tid == dl_worker.w_tid)
|
||||
deadlock_resolving = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -831,80 +592,81 @@ void replycode(endpoint_t whom, int result)
|
|||
/*===========================================================================*
|
||||
* service_pm_postponed *
|
||||
*===========================================================================*/
|
||||
static void service_pm_postponed(void)
|
||||
void service_pm_postponed(void)
|
||||
{
|
||||
int r;
|
||||
vir_bytes pc, newsp;
|
||||
int r, term_signal;
|
||||
vir_bytes core_path;
|
||||
vir_bytes exec_path, stack_frame, pc, newsp;
|
||||
size_t exec_path_len, stack_frame_len;
|
||||
endpoint_t proc_e;
|
||||
message m_out;
|
||||
|
||||
memset(&m_out, 0, sizeof(m_out));
|
||||
|
||||
switch(job_call_nr) {
|
||||
case PM_EXEC:
|
||||
{
|
||||
endpoint_t proc_e;
|
||||
vir_bytes exec_path, stack_frame;
|
||||
size_t exec_path_len, stack_frame_len;
|
||||
case PM_EXEC:
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
exec_path = (vir_bytes) job_m_in.PM_PATH;
|
||||
exec_path_len = (size_t) job_m_in.PM_PATH_LEN;
|
||||
stack_frame = (vir_bytes) job_m_in.PM_FRAME;
|
||||
stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
exec_path = (vir_bytes) job_m_in.PM_PATH;
|
||||
exec_path_len = (size_t) job_m_in.PM_PATH_LEN;
|
||||
stack_frame = (vir_bytes) job_m_in.PM_FRAME;
|
||||
stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN;
|
||||
assert(proc_e == fp->fp_endpoint);
|
||||
|
||||
r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame,
|
||||
stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS);
|
||||
r = pm_exec(exec_path, exec_path_len, stack_frame, stack_frame_len,
|
||||
&pc, &newsp, job_m_in.PM_EXECFLAGS);
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_EXEC_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
m_out.PM_PC = (void*) pc;
|
||||
m_out.PM_STATUS = r;
|
||||
m_out.PM_NEWSP = (void *) newsp;
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_EXEC_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
m_out.PM_PC = (void*) pc;
|
||||
m_out.PM_STATUS = r;
|
||||
m_out.PM_NEWSP = (void *) newsp;
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_EXIT:
|
||||
{
|
||||
endpoint_t proc_e;
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
case PM_EXIT:
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
|
||||
pm_exit(proc_e);
|
||||
assert(proc_e == fp->fp_endpoint);
|
||||
|
||||
pm_exit();
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m_out.m_type = PM_EXIT_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m_out.m_type = PM_EXIT_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_DUMPCORE:
|
||||
{
|
||||
endpoint_t proc_e, traced_proc_e;
|
||||
int term_signal;
|
||||
vir_bytes core_path;
|
||||
case PM_DUMPCORE:
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
term_signal = job_m_in.PM_TERM_SIG;
|
||||
core_path = (vir_bytes) job_m_in.PM_PATH;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
traced_proc_e = job_m_in.PM_TRACED_PROC;
|
||||
if(job_m_in.PM_PROC != job_m_in.PM_TRACED_PROC) {
|
||||
/* dumpcore request */
|
||||
term_signal = 0;
|
||||
} else {
|
||||
/* dumpcore on exit */
|
||||
term_signal = job_m_in.PM_TERM_SIG;
|
||||
}
|
||||
core_path = (vir_bytes) job_m_in.PM_PATH;
|
||||
assert(proc_e == fp->fp_endpoint);
|
||||
|
||||
r = pm_dumpcore(proc_e, term_signal, core_path);
|
||||
r = pm_dumpcore(term_signal, core_path);
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_CORE_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
m_out.PM_STATUS = r;
|
||||
|
||||
/* Reply status to PM */
|
||||
m_out.m_type = PM_CORE_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
m_out.PM_TRACED_PROC = traced_proc_e;
|
||||
m_out.PM_STATUS = r;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case PM_UNPAUSE:
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
|
||||
assert(proc_e == fp->fp_endpoint);
|
||||
|
||||
unpause();
|
||||
|
||||
m_out.m_type = PM_UNPAUSE_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Unhandled postponed PM call %d", job_m_in.m_type);
|
||||
}
|
||||
|
||||
|
|
@ -916,22 +678,34 @@ static void service_pm_postponed(void)
|
|||
/*===========================================================================*
|
||||
* service_pm *
|
||||
*===========================================================================*/
|
||||
static void service_pm()
|
||||
static void service_pm(void)
|
||||
{
|
||||
/* Process a request from PM. This function is called from the main thread, and
|
||||
* may therefore not block. Any requests that may require blocking the calling
|
||||
* thread must be executed in a separate thread. Aside from PM_REBOOT, all
|
||||
* requests from PM involve another, target process: for example, PM tells VFS
|
||||
* that a process is performing a setuid() call. For some requests however,
|
||||
* that other process may not be idle, and in that case VFS must serialize the
|
||||
* PM request handling with any operation is it handling for that target
|
||||
* process. As it happens, the requests that may require blocking are also the
|
||||
* ones where the target process may not be idle. For both these reasons, such
|
||||
* requests are run in worker threads associated to the target process.
|
||||
*/
|
||||
struct fproc *rfp;
|
||||
int r, slot;
|
||||
message m_out;
|
||||
|
||||
memset(&m_out, 0, sizeof(m_out));
|
||||
|
||||
switch (job_call_nr) {
|
||||
switch (call_nr) {
|
||||
case PM_SETUID:
|
||||
{
|
||||
endpoint_t proc_e;
|
||||
uid_t euid, ruid;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
euid = job_m_in.PM_EID;
|
||||
ruid = job_m_in.PM_RID;
|
||||
proc_e = m_in.PM_PROC;
|
||||
euid = m_in.PM_EID;
|
||||
ruid = m_in.PM_RID;
|
||||
|
||||
pm_setuid(proc_e, euid, ruid);
|
||||
|
||||
|
|
@ -945,9 +719,9 @@ static void service_pm()
|
|||
endpoint_t proc_e;
|
||||
gid_t egid, rgid;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
egid = job_m_in.PM_EID;
|
||||
rgid = job_m_in.PM_RID;
|
||||
proc_e = m_in.PM_PROC;
|
||||
egid = m_in.PM_EID;
|
||||
rgid = m_in.PM_RID;
|
||||
|
||||
pm_setgid(proc_e, egid, rgid);
|
||||
|
||||
|
|
@ -960,7 +734,7 @@ static void service_pm()
|
|||
{
|
||||
endpoint_t proc_e;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
proc_e = m_in.PM_PROC;
|
||||
pm_setsid(proc_e);
|
||||
|
||||
m_out.m_type = PM_SETSID_REPLY;
|
||||
|
|
@ -971,39 +745,22 @@ static void service_pm()
|
|||
case PM_EXEC:
|
||||
case PM_EXIT:
|
||||
case PM_DUMPCORE:
|
||||
case PM_UNPAUSE:
|
||||
{
|
||||
endpoint_t proc_e = job_m_in.PM_PROC;
|
||||
endpoint_t proc_e = m_in.PM_PROC;
|
||||
|
||||
if(isokendpt(proc_e, &slot) != OK) {
|
||||
printf("VFS: proc ep %d not ok\n", proc_e);
|
||||
return;
|
||||
}
|
||||
|
||||
fp = &fproc[slot];
|
||||
|
||||
if (fp->fp_flags & FP_PENDING) {
|
||||
/* This process has a request pending, but PM wants it
|
||||
* gone. Forget about the pending request and satisfy
|
||||
* PM's request instead. Note that a pending request
|
||||
* AND an EXEC request are mutually exclusive. Also, PM
|
||||
* should send only one request/process at a time.
|
||||
*/
|
||||
assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR);
|
||||
}
|
||||
rfp = &fproc[slot];
|
||||
|
||||
/* PM requests on behalf of a proc are handled after the
|
||||
* system call that might be in progress for that proc has
|
||||
* finished. If the proc is not busy, we start a dummy call.
|
||||
* finished. If the proc is not busy, we start a new thread.
|
||||
*/
|
||||
if (!(fp->fp_flags & FP_PENDING) &&
|
||||
mutex_trylock(&fp->fp_lock) == 0) {
|
||||
mutex_unlock(&fp->fp_lock);
|
||||
worker_start(do_dummy);
|
||||
fp->fp_flags |= FP_DROP_WORK;
|
||||
}
|
||||
|
||||
fp->fp_job.j_m_in = job_m_in;
|
||||
fp->fp_flags |= FP_PM_PENDING;
|
||||
worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1015,16 +772,16 @@ static void service_pm()
|
|||
uid_t reuid;
|
||||
gid_t regid;
|
||||
|
||||
pproc_e = job_m_in.PM_PPROC;
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
child_pid = job_m_in.PM_CPID;
|
||||
reuid = job_m_in.PM_REUID;
|
||||
regid = job_m_in.PM_REGID;
|
||||
pproc_e = m_in.PM_PPROC;
|
||||
proc_e = m_in.PM_PROC;
|
||||
child_pid = m_in.PM_CPID;
|
||||
reuid = m_in.PM_REUID;
|
||||
regid = m_in.PM_REGID;
|
||||
|
||||
pm_fork(pproc_e, proc_e, child_pid);
|
||||
m_out.m_type = PM_FORK_REPLY;
|
||||
|
||||
if (job_call_nr == PM_SRV_FORK) {
|
||||
if (call_nr == PM_SRV_FORK) {
|
||||
m_out.m_type = PM_SRV_FORK_REPLY;
|
||||
pm_setuid(proc_e, reuid, reuid);
|
||||
pm_setgid(proc_e, regid, regid);
|
||||
|
|
@ -1039,9 +796,9 @@ static void service_pm()
|
|||
int group_no;
|
||||
gid_t *group_addr;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
group_no = job_m_in.PM_GROUP_NO;
|
||||
group_addr = (gid_t *) job_m_in.PM_GROUP_ADDR;
|
||||
proc_e = m_in.PM_PROC;
|
||||
group_no = m_in.PM_GROUP_NO;
|
||||
group_addr = (gid_t *) m_in.PM_GROUP_ADDR;
|
||||
|
||||
pm_setgroups(proc_e, group_no, group_addr);
|
||||
|
||||
|
|
@ -1050,29 +807,21 @@ static void service_pm()
|
|||
}
|
||||
break;
|
||||
|
||||
case PM_UNPAUSE:
|
||||
{
|
||||
endpoint_t proc_e;
|
||||
|
||||
proc_e = job_m_in.PM_PROC;
|
||||
|
||||
unpause(proc_e);
|
||||
|
||||
m_out.m_type = PM_UNPAUSE_REPLY;
|
||||
m_out.PM_PROC = proc_e;
|
||||
}
|
||||
break;
|
||||
|
||||
case PM_REBOOT:
|
||||
pm_reboot();
|
||||
/* Reboot requests are not considered postponed PM work and are instead
|
||||
* handled from a separate worker thread that is associated with PM's
|
||||
* process. PM makes no regular VFS calls, and thus, from VFS's
|
||||
* perspective, PM is always idle. Therefore, we can safely do this.
|
||||
* We do assume that PM sends us only one PM_REBOOT message at once,
|
||||
* or ever for that matter. :)
|
||||
*/
|
||||
worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in,
|
||||
FALSE /*use_spare*/);
|
||||
|
||||
/* Reply dummy status to PM for synchronization */
|
||||
m_out.m_type = PM_REBOOT_REPLY;
|
||||
|
||||
break;
|
||||
return;
|
||||
|
||||
default:
|
||||
printf("VFS: don't know how to handle PM request %d\n", job_call_nr);
|
||||
printf("VFS: don't know how to handle PM request %d\n", call_nr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1080,7 +829,6 @@ static void service_pm()
|
|||
r = send(PM_PROC_NR, &m_out);
|
||||
if (r != OK)
|
||||
panic("service_pm: send failed: %d", r);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1090,33 +838,41 @@ static void service_pm()
|
|||
static int unblock(rfp)
|
||||
struct fproc *rfp;
|
||||
{
|
||||
/* Unblock a process that was previously blocked on a pipe or a lock. This is
|
||||
* done by reconstructing the original request and continuing/repeating it.
|
||||
* This function returns TRUE when it has restored a request for execution, and
|
||||
* FALSE if the caller should continue looking for work to do.
|
||||
*/
|
||||
int blocked_on;
|
||||
|
||||
fp = rfp;
|
||||
blocked_on = rfp->fp_blocked_on;
|
||||
|
||||
assert(blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK);
|
||||
|
||||
/* READ, WRITE, FCNTL requests all use the same message layout. */
|
||||
m_in.m_source = rfp->fp_endpoint;
|
||||
m_in.m_type = rfp->fp_block_callnr;
|
||||
m_in.fd = scratch(fp).file.fd_nr;
|
||||
m_in.buffer = scratch(fp).io.io_buffer;
|
||||
m_in.nbytes = scratch(fp).io.io_nbytes;
|
||||
m_in.fd = scratch(rfp).file.fd_nr;
|
||||
m_in.buffer = scratch(rfp).io.io_buffer;
|
||||
m_in.nbytes = scratch(rfp).io.io_nbytes;
|
||||
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */
|
||||
rfp->fp_flags &= ~FP_REVIVED;
|
||||
reviving--;
|
||||
assert(reviving >= 0);
|
||||
|
||||
/* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak'
|
||||
* grants.
|
||||
*/
|
||||
/* This should not be device I/O. If it is, it'll 'leak' grants. */
|
||||
assert(!GRANT_VALID(rfp->fp_grant));
|
||||
|
||||
/* Pending pipe reads/writes can be handled directly */
|
||||
/* Pending pipe reads/writes cannot be repeated as is, and thus require a
|
||||
* special resumption procedure.
|
||||
*/
|
||||
if (blocked_on == FP_BLOCKED_ON_PIPE) {
|
||||
worker_start(do_pending_pipe);
|
||||
yield(); /* Give thread a chance to run */
|
||||
self = NULL;
|
||||
return(0); /* Retrieve more work */
|
||||
worker_start(rfp, do_pending_pipe, &m_in, FALSE /*use_spare*/);
|
||||
return(FALSE); /* Retrieve more work */
|
||||
}
|
||||
|
||||
return(1); /* We've unblocked a process */
|
||||
/* A lock request. Repeat the original request as though it just came in. */
|
||||
fp = rfp;
|
||||
return(TRUE); /* We've unblocked a process */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@
|
|||
#include <sys/svrctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "dmap.h"
|
||||
#include <minix/vfsif.h>
|
||||
#include "vnode.h"
|
||||
#include "vmnt.h"
|
||||
|
|
@ -47,14 +45,7 @@
|
|||
unsigned long calls_stats[NCALLS];
|
||||
#endif
|
||||
|
||||
static void free_proc(struct fproc *freed, int flags);
|
||||
/*
|
||||
static int dumpcore(int proc_e, struct mem_map *seg_ptr);
|
||||
static int write_bytes(struct inode *rip, off_t off, char *buf, size_t
|
||||
bytes);
|
||||
static int write_seg(struct inode *rip, off_t off, int proc_e, int seg,
|
||||
off_t seg_off, phys_bytes seg_bytes);
|
||||
*/
|
||||
static void free_proc(int flags);
|
||||
|
||||
/*===========================================================================*
|
||||
* do_getsysinfo *
|
||||
|
|
@ -316,7 +307,7 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp)
|
|||
{
|
||||
int result, procfd;
|
||||
struct filp *f = NULL;
|
||||
struct fproc *vmf = &fproc[VM_PROC_NR];
|
||||
struct fproc *vmf = fproc_addr(VM_PROC_NR);
|
||||
|
||||
*newfilp = NULL;
|
||||
|
||||
|
|
@ -391,7 +382,7 @@ int do_vm_call(message *m_out)
|
|||
if(isokendpt(ep, &slot) != OK) rfp = NULL;
|
||||
else rfp = &fproc[slot];
|
||||
|
||||
vmf = &fproc[VM_PROC_NR];
|
||||
vmf = fproc_addr(VM_PROC_NR);
|
||||
assert(fp == vmf);
|
||||
assert(rfp != vmf);
|
||||
|
||||
|
|
@ -487,9 +478,14 @@ reqdone:
|
|||
*===========================================================================*/
|
||||
void pm_reboot()
|
||||
{
|
||||
/* Perform the VFS side of the reboot call. */
|
||||
int i;
|
||||
struct fproc *rfp;
|
||||
/* Perform the VFS side of the reboot call. This call is performed from the PM
|
||||
* process context.
|
||||
*/
|
||||
message m_out;
|
||||
int i, r;
|
||||
struct fproc *rfp, *pmfp;
|
||||
|
||||
pmfp = fp;
|
||||
|
||||
sync_fses();
|
||||
|
||||
|
|
@ -499,15 +495,25 @@ void pm_reboot()
|
|||
* them the chance to unmount (which should be possible as all normal
|
||||
* processes have no open files anymore).
|
||||
*/
|
||||
/* This is the only place where we allow special modification of "fp". The
|
||||
* reboot procedure should really be implemented as a PM message broadcasted
|
||||
* to all processes, so that each process will be shut down cleanly by a
|
||||
* thread operating on its behalf. Doing everything here is simpler, but it
|
||||
* requires an exception to the strict model of having "fp" be the process
|
||||
* that owns the current worker thread.
|
||||
*/
|
||||
for (i = 0; i < NR_PROCS; i++) {
|
||||
rfp = &fproc[i];
|
||||
|
||||
/* Don't just free the proc right away, but let it finish what it was
|
||||
* doing first */
|
||||
lock_proc(rfp, 0);
|
||||
if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL)
|
||||
free_proc(rfp, 0);
|
||||
unlock_proc(rfp);
|
||||
if (rfp != fp) lock_proc(rfp);
|
||||
if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) {
|
||||
worker_set_proc(rfp); /* temporarily fake process context */
|
||||
free_proc(0);
|
||||
worker_set_proc(pmfp); /* restore original process context */
|
||||
}
|
||||
if (rfp != fp) unlock_proc(rfp);
|
||||
}
|
||||
|
||||
sync_fses();
|
||||
|
|
@ -519,15 +525,25 @@ void pm_reboot()
|
|||
|
||||
/* Don't just free the proc right away, but let it finish what it was
|
||||
* doing first */
|
||||
lock_proc(rfp, 0);
|
||||
if (rfp->fp_endpoint != NONE)
|
||||
free_proc(rfp, 0);
|
||||
unlock_proc(rfp);
|
||||
if (rfp != fp) lock_proc(rfp);
|
||||
if (rfp->fp_endpoint != NONE) {
|
||||
worker_set_proc(rfp); /* temporarily fake process context */
|
||||
free_proc(0);
|
||||
worker_set_proc(pmfp); /* restore original process context */
|
||||
}
|
||||
if (rfp != fp) unlock_proc(rfp);
|
||||
}
|
||||
|
||||
sync_fses();
|
||||
unmount_all(1 /* Force */);
|
||||
|
||||
/* Reply to PM for synchronization */
|
||||
memset(&m_out, 0, sizeof(m_out));
|
||||
|
||||
m_out.m_type = PM_REBOOT_REPLY;
|
||||
|
||||
if ((r = send(PM_PROC_NR, &m_out)) != OK)
|
||||
panic("pm_reboot: send failed: %d", r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -597,7 +613,7 @@ void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid)
|
|||
/*===========================================================================*
|
||||
* free_proc *
|
||||
*===========================================================================*/
|
||||
static void free_proc(struct fproc *exiter, int flags)
|
||||
static void free_proc(int flags)
|
||||
{
|
||||
int i;
|
||||
register struct fproc *rfp;
|
||||
|
|
@ -605,46 +621,43 @@ static void free_proc(struct fproc *exiter, int flags)
|
|||
register struct vnode *vp;
|
||||
dev_t dev;
|
||||
|
||||
if (exiter->fp_endpoint == NONE)
|
||||
if (fp->fp_endpoint == NONE)
|
||||
panic("free_proc: already free");
|
||||
|
||||
if (fp_is_blocked(exiter))
|
||||
unpause(exiter->fp_endpoint);
|
||||
if (fp_is_blocked(fp))
|
||||
unpause();
|
||||
|
||||
/* Loop on file descriptors, closing any that are open. */
|
||||
for (i = 0; i < OPEN_MAX; i++) {
|
||||
(void) close_fd(exiter, i);
|
||||
(void) close_fd(fp, i);
|
||||
}
|
||||
|
||||
/* Release root and working directories. */
|
||||
if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; }
|
||||
if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; }
|
||||
if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; }
|
||||
if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; }
|
||||
|
||||
/* The rest of these actions is only done when processes actually exit. */
|
||||
if (!(flags & FP_EXITING)) return;
|
||||
|
||||
exiter->fp_flags |= FP_EXITING;
|
||||
fp->fp_flags |= FP_EXITING;
|
||||
|
||||
/* Check if any process is SUSPENDed on this driver.
|
||||
* If a driver exits, unmap its entries in the dmap table.
|
||||
* (unmapping has to be done after the first step, because the
|
||||
* dmap table is used in the first step.)
|
||||
*/
|
||||
unsuspend_by_endpt(exiter->fp_endpoint);
|
||||
dmap_unmap_by_endpt(exiter->fp_endpoint);
|
||||
unsuspend_by_endpt(fp->fp_endpoint);
|
||||
dmap_unmap_by_endpt(fp->fp_endpoint);
|
||||
|
||||
worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */
|
||||
vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this
|
||||
worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */
|
||||
vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this
|
||||
* was an active FS */
|
||||
|
||||
/* Invalidate endpoint number for error and sanity checks. */
|
||||
exiter->fp_endpoint = NONE;
|
||||
|
||||
/* If a session leader exits and it has a controlling tty, then revoke
|
||||
* access to its controlling tty from all other processes using it.
|
||||
*/
|
||||
if ((exiter->fp_flags & FP_SESLDR) && exiter->fp_tty != 0) {
|
||||
dev = exiter->fp_tty;
|
||||
if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) {
|
||||
dev = fp->fp_tty;
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if(rfp->fp_pid == PID_FREE) continue;
|
||||
if (rfp->fp_tty == dev) rfp->fp_tty = 0;
|
||||
|
|
@ -666,25 +679,21 @@ static void free_proc(struct fproc *exiter, int flags)
|
|||
}
|
||||
|
||||
/* Exit done. Mark slot as free. */
|
||||
exiter->fp_pid = PID_FREE;
|
||||
if (exiter->fp_flags & FP_PENDING)
|
||||
pending--; /* No longer pending job, not going to do it */
|
||||
exiter->fp_flags = FP_NOFLAGS;
|
||||
fp->fp_endpoint = NONE;
|
||||
fp->fp_pid = PID_FREE;
|
||||
fp->fp_flags = FP_NOFLAGS;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* pm_exit *
|
||||
*===========================================================================*/
|
||||
void pm_exit(proc)
|
||||
endpoint_t proc;
|
||||
void pm_exit(void)
|
||||
{
|
||||
/* Perform the file system portion of the exit(status) system call. */
|
||||
int exitee_p;
|
||||
/* Perform the file system portion of the exit(status) system call.
|
||||
* This function is called from the context of the exiting process.
|
||||
*/
|
||||
|
||||
/* Nevertheless, pretend that the call came from the user. */
|
||||
okendpt(proc, &exitee_p);
|
||||
fp = &fproc[exitee_p];
|
||||
free_proc(fp, FP_EXITING);
|
||||
free_proc(FP_EXITING);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -850,21 +859,18 @@ int do_svrctl(message *UNUSED(m_out))
|
|||
/*===========================================================================*
|
||||
* pm_dumpcore *
|
||||
*===========================================================================*/
|
||||
int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name)
|
||||
int pm_dumpcore(int csig, vir_bytes exe_name)
|
||||
{
|
||||
int slot, r = OK, core_fd;
|
||||
int r = OK, core_fd;
|
||||
struct filp *f;
|
||||
char core_path[PATH_MAX];
|
||||
char proc_name[PROC_NAME_LEN];
|
||||
|
||||
okendpt(proc_e, &slot);
|
||||
fp = &fproc[slot];
|
||||
|
||||
/* if a process is blocked, scratch(fp).file.fd_nr holds the fd it's blocked
|
||||
* on. free it up for use by common_open().
|
||||
*/
|
||||
if (fp_is_blocked(fp))
|
||||
unpause(fp->fp_endpoint);
|
||||
unpause();
|
||||
|
||||
/* open core file */
|
||||
snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid);
|
||||
|
|
@ -884,15 +890,15 @@ int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name)
|
|||
|
||||
core_exit:
|
||||
if(csig)
|
||||
free_proc(fp, FP_EXITING);
|
||||
free_proc(FP_EXITING);
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* ds_event *
|
||||
*===========================================================================*/
|
||||
void *
|
||||
ds_event(void *arg)
|
||||
void
|
||||
ds_event(void)
|
||||
{
|
||||
char key[DS_MAX_KEYLEN];
|
||||
char *blkdrv_prefix = "drv.blk.";
|
||||
|
|
@ -901,11 +907,6 @@ ds_event(void *arg)
|
|||
int type, r, is_blk;
|
||||
endpoint_t owner_endpoint;
|
||||
|
||||
struct job my_job;
|
||||
|
||||
my_job = *((struct job *) arg);
|
||||
fp = my_job.j_fp;
|
||||
|
||||
/* Get the event and the owner from DS. */
|
||||
while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
|
||||
/* Only check for block and character driver up events. */
|
||||
|
|
@ -928,9 +929,6 @@ ds_event(void *arg)
|
|||
}
|
||||
|
||||
if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r);
|
||||
|
||||
thread_cleanup(NULL);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* A function to be called on panic(). */
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "dmap.h"
|
||||
#include <minix/vfsif.h>
|
||||
#include "vnode.h"
|
||||
#include "vmnt.h"
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
#include <minix/com.h>
|
||||
#include <minix/u64.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "dmap.h"
|
||||
#include "lock.h"
|
||||
#include "param.h"
|
||||
#include <dirent.h>
|
||||
|
|
@ -161,9 +159,8 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode)
|
|||
dev = (dev_t) vp->v_sdev;
|
||||
/* TTY needs to know about the O_NOCTTY flag. */
|
||||
r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY));
|
||||
if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN);
|
||||
else vp = filp->filp_vno; /* Might be updated by
|
||||
* dev_open/clone_opcl */
|
||||
vp = filp->filp_vno; /* Might be updated by
|
||||
* dev_open/clone_opcl */
|
||||
break;
|
||||
case S_IFBLK:
|
||||
|
||||
|
|
@ -767,11 +764,3 @@ int fd_nr;
|
|||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* close_reply *
|
||||
*===========================================================================*/
|
||||
void close_reply()
|
||||
{
|
||||
/* No need to do anything */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,9 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <dirent.h>
|
||||
#include "threads.h"
|
||||
#include "vmnt.h"
|
||||
#include "vnode.h"
|
||||
#include "path.h"
|
||||
#include "fproc.h"
|
||||
#include "param.h"
|
||||
|
||||
/* Set to following define to 1 if you really want to use the POSIX definition
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@
|
|||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "dmap.h"
|
||||
#include "param.h"
|
||||
#include <minix/vfsif.h>
|
||||
#include "vnode.h"
|
||||
|
|
@ -436,7 +434,6 @@ int count; /* max number of processes to release */
|
|||
*/
|
||||
|
||||
if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN ||
|
||||
rp->fp_blocked_on == FP_BLOCKED_ON_DOPEN ||
|
||||
rp->fp_blocked_on == FP_BLOCKED_ON_LOCK ||
|
||||
rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) {
|
||||
if (!FD_ISSET(scratch(rp).file.fd_nr,
|
||||
|
|
@ -469,12 +466,12 @@ int count; /* max number of processes to release */
|
|||
void revive(endpoint_t proc_e, int returned)
|
||||
{
|
||||
/* Revive a previously blocked process. When a process hangs on tty, this
|
||||
* is the way it is eventually released.
|
||||
* is the way it is eventually released. For processes blocked on _SELECT and
|
||||
* _OTHER, this function MUST NOT block its calling thread.
|
||||
*/
|
||||
struct fproc *rfp;
|
||||
int blocked_on;
|
||||
int fd_nr, slot;
|
||||
struct filp *fil_ptr;
|
||||
|
||||
if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return;
|
||||
|
||||
|
|
@ -492,26 +489,6 @@ void revive(endpoint_t proc_e, int returned)
|
|||
/* Revive a process suspended on a pipe or lock. */
|
||||
rfp->fp_flags |= FP_REVIVED;
|
||||
reviving++; /* process was waiting on pipe or lock */
|
||||
} else if (blocked_on == FP_BLOCKED_ON_DOPEN) {
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
scratch(rfp).file.fd_nr = 0;
|
||||
if (returned < 0) {
|
||||
fil_ptr = rfp->fp_filp[fd_nr];
|
||||
lock_filp(fil_ptr, VNODE_OPCL);
|
||||
rfp->fp_filp[fd_nr] = NULL;
|
||||
FD_CLR(fd_nr, &rfp->fp_filp_inuse);
|
||||
if (fil_ptr->filp_count != 1) {
|
||||
panic("VFS: revive: bad count in filp: %d",
|
||||
fil_ptr->filp_count);
|
||||
}
|
||||
fil_ptr->filp_count = 0;
|
||||
unlock_filp(fil_ptr);
|
||||
put_vnode(fil_ptr->filp_vno);
|
||||
fil_ptr->filp_vno = NULL;
|
||||
replycode(proc_e, returned);
|
||||
} else {
|
||||
replycode(proc_e, fd_nr);
|
||||
}
|
||||
} else {
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
scratch(rfp).file.fd_nr = 0;
|
||||
|
|
@ -544,97 +521,77 @@ void revive(endpoint_t proc_e, int returned)
|
|||
/*===========================================================================*
|
||||
* unpause *
|
||||
*===========================================================================*/
|
||||
void unpause(endpoint_t proc_e)
|
||||
void unpause(void)
|
||||
{
|
||||
/* A signal has been sent to a user who is paused on the file system.
|
||||
* Abort the system call with the EINTR error message.
|
||||
*/
|
||||
|
||||
register struct fproc *rfp, *org_fp;
|
||||
int slot, blocked_on, fild, status = EINTR, major_dev, minor_dev;
|
||||
int blocked_on, fild, status = EINTR;
|
||||
struct filp *f;
|
||||
dev_t dev;
|
||||
message mess;
|
||||
int wasreviving = 0;
|
||||
|
||||
if (isokendpt(proc_e, &slot) != OK) {
|
||||
printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_e);
|
||||
return;
|
||||
}
|
||||
if (!fp_is_blocked(fp)) return;
|
||||
blocked_on = fp->fp_blocked_on;
|
||||
|
||||
rfp = &fproc[slot];
|
||||
if (!fp_is_blocked(rfp)) return;
|
||||
blocked_on = rfp->fp_blocked_on;
|
||||
/* Clear the block status now. The procedure below might make blocking calls
|
||||
* and it is imperative that while at least dev_cancel() is executing, other
|
||||
* parts of VFS do not perceive this process as blocked on something.
|
||||
*/
|
||||
fp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
|
||||
if (rfp->fp_flags & FP_REVIVED) {
|
||||
rfp->fp_flags &= ~FP_REVIVED;
|
||||
if (fp->fp_flags & FP_REVIVED) {
|
||||
fp->fp_flags &= ~FP_REVIVED;
|
||||
reviving--;
|
||||
wasreviving = 1;
|
||||
}
|
||||
|
||||
switch (blocked_on) {
|
||||
case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
|
||||
/* If the operation succeeded partially, return the bytes
|
||||
* processed so far, and clear the remembered state. Otherwise,
|
||||
* return EINTR as usual.
|
||||
*/
|
||||
if (fp->fp_cum_io_partial > 0) {
|
||||
status = fp->fp_cum_io_partial;
|
||||
|
||||
fp->fp_cum_io_partial = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */
|
||||
break;
|
||||
|
||||
case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
|
||||
select_forget(proc_e);
|
||||
select_forget();
|
||||
break;
|
||||
|
||||
case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */
|
||||
break;
|
||||
|
||||
case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */
|
||||
/* Don't cancel OPEN. Just wait until the open completes. */
|
||||
return;
|
||||
|
||||
case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/
|
||||
if (rfp->fp_flags & FP_SUSP_REOPEN) {
|
||||
if (fp->fp_flags & FP_SUSP_REOPEN) {
|
||||
/* Process is suspended while waiting for a reopen.
|
||||
* Just reply EINTR.
|
||||
*/
|
||||
rfp->fp_flags &= ~FP_SUSP_REOPEN;
|
||||
fp->fp_flags &= ~FP_SUSP_REOPEN;
|
||||
status = EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
fild = scratch(rfp).file.fd_nr;
|
||||
fild = scratch(fp).file.fd_nr;
|
||||
if (fild < 0 || fild >= OPEN_MAX)
|
||||
panic("file descriptor out-of-range");
|
||||
f = rfp->fp_filp[fild];
|
||||
f = fp->fp_filp[fild];
|
||||
if(!f) {
|
||||
sys_sysctl_stacktrace(rfp->fp_endpoint);
|
||||
sys_sysctl_stacktrace(fp->fp_endpoint);
|
||||
panic("process %d blocked on empty fd %d",
|
||||
rfp->fp_endpoint, fild);
|
||||
fp->fp_endpoint, fild);
|
||||
}
|
||||
dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */
|
||||
major_dev = major(dev);
|
||||
minor_dev = minor(dev);
|
||||
mess.TTY_LINE = minor_dev;
|
||||
mess.USER_ENDPT = rfp->fp_ioproc;
|
||||
mess.IO_GRANT = (char *) rfp->fp_grant;
|
||||
|
||||
/* Tell kernel R or W. Mode is from current call, not open. */
|
||||
mess.COUNT = rfp->fp_block_callnr == READ ? R_BIT : W_BIT;
|
||||
mess.m_type = CANCEL;
|
||||
status = dev_cancel(dev);
|
||||
|
||||
org_fp = fp;
|
||||
fp = rfp; /* hack - ctty_io uses fp */
|
||||
(*dmap[major_dev].dmap_io)(rfp->fp_task, &mess);
|
||||
fp = org_fp;
|
||||
status = mess.REP_STATUS;
|
||||
if (status == SUSPEND)
|
||||
return; /* Process will be revived at a
|
||||
* later time.
|
||||
*/
|
||||
|
||||
if (status == EAGAIN) status = EINTR;
|
||||
if (GRANT_VALID(rfp->fp_grant)) {
|
||||
(void) cpf_revoke(rfp->fp_grant);
|
||||
rfp->fp_grant = GRANT_INVALID;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
panic("VFS: unknown block reason: %d", blocked_on);
|
||||
|
|
@ -645,9 +602,5 @@ void unpause(endpoint_t proc_e)
|
|||
susp_count--;
|
||||
}
|
||||
|
||||
if(rfp->fp_blocked_on != FP_BLOCKED_ON_NONE) {
|
||||
rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
|
||||
replycode(proc_e, status); /* signal interrupted call */
|
||||
}
|
||||
replycode(fp->fp_endpoint, status); /* signal interrupted call */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <assert.h>
|
||||
#include <minix/callnr.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
#include "param.h"
|
||||
#include <minix/vfsif.h>
|
||||
|
|
|
|||
|
|
@ -31,15 +31,15 @@ void send_work(void);
|
|||
/* device.c */
|
||||
int dev_open(dev_t dev, endpoint_t proc_e, int flags);
|
||||
int dev_reopen(dev_t dev, int filp_no, int flags);
|
||||
void dev_reply(struct dmap *dp);
|
||||
int dev_close(dev_t dev, int filp_no);
|
||||
void cdev_reply(void);
|
||||
int bdev_open(dev_t dev, int access);
|
||||
int bdev_close(dev_t dev);
|
||||
void bdev_reply(struct dmap *dp);
|
||||
int dev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, u64_t pos,
|
||||
size_t bytes, int flags, int suspend_reopen);
|
||||
int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags);
|
||||
int gen_io(endpoint_t driver_e, message *mess_ptr);
|
||||
int asyn_io(endpoint_t drv_e, message *mess_ptr);
|
||||
int gen_io(endpoint_t drv_e, message *mess_ptr);
|
||||
int no_dev(int op, dev_t dev, endpoint_t proc, int flags);
|
||||
int no_dev_io(endpoint_t, message *);
|
||||
int tty_opcl(int op, dev_t dev, endpoint_t proc, int flags);
|
||||
|
|
@ -47,13 +47,11 @@ int ctty_opcl(int op, dev_t dev, endpoint_t proc, int flags);
|
|||
int clone_opcl(int op, dev_t dev, endpoint_t proc, int flags);
|
||||
int ctty_io(endpoint_t task_nr, message *mess_ptr);
|
||||
int do_ioctl(message *m_out);
|
||||
int dev_select(dev_t dev, int ops);
|
||||
int dev_cancel(dev_t dev);
|
||||
void pm_setsid(endpoint_t proc_e);
|
||||
void dev_status(endpoint_t drv_e);
|
||||
void bdev_up(int major);
|
||||
void cdev_up(int major);
|
||||
endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g);
|
||||
void reopen_reply(void);
|
||||
void open_reply(void);
|
||||
|
||||
/* dmap.c */
|
||||
void lock_dmap(struct dmap *dp);
|
||||
|
|
@ -77,11 +75,11 @@ int map_service(struct rprocpub *rpub);
|
|||
void write_elf_core_file(struct filp *f, int csig, char *exe_name);
|
||||
|
||||
/* exec.c */
|
||||
int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, vir_bytes frame,
|
||||
size_t frame_len, vir_bytes *pc, vir_bytes *newsp, int flags);
|
||||
int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
|
||||
vir_bytes *pc, vir_bytes *newsp, int flags);
|
||||
|
||||
/* filedes.c */
|
||||
void *do_filp_gc(void *arg);
|
||||
int do_filp_gc(void);
|
||||
void check_filp_locks(void);
|
||||
void check_filp_locks_by_me(void);
|
||||
void init_filps(void);
|
||||
|
|
@ -125,14 +123,15 @@ void lock_revive(void);
|
|||
|
||||
/* main.c */
|
||||
int main(void);
|
||||
void lock_proc(struct fproc *rfp, int force_lock);
|
||||
void lock_proc(struct fproc *rfp);
|
||||
void unlock_proc(struct fproc *rfp);
|
||||
void reply(message *m_out, endpoint_t whom, int result);
|
||||
void replycode(endpoint_t whom, int result);
|
||||
void thread_cleanup(struct fproc *rfp);
|
||||
void unlock_proc(struct fproc *rfp);
|
||||
void service_pm_postponed(void);
|
||||
void thread_cleanup(void);
|
||||
|
||||
/* misc.c */
|
||||
void pm_exit(endpoint_t proc);
|
||||
void pm_exit(void);
|
||||
int do_fcntl(message *m_out);
|
||||
void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid);
|
||||
void pm_setgid(endpoint_t proc_e, int egid, int rgid);
|
||||
|
|
@ -144,8 +143,8 @@ void pm_reboot(void);
|
|||
int do_svrctl(message *m_out);
|
||||
int do_getsysinfo(void);
|
||||
int do_vm_call(message *m_out);
|
||||
int pm_dumpcore(endpoint_t proc_e, int sig, vir_bytes exe_name);
|
||||
void * ds_event(void *arg);
|
||||
int pm_dumpcore(int sig, vir_bytes exe_name);
|
||||
void ds_event(void);
|
||||
int dupvm(struct fproc *fp, int pfd, int *vmfd, struct filp **f);
|
||||
int do_getrusage(message *m_out);
|
||||
|
||||
|
|
@ -163,7 +162,6 @@ void unmount_all(int force);
|
|||
/* open.c */
|
||||
int do_close(message *m_out);
|
||||
int close_fd(struct fproc *rfp, int fd_nr);
|
||||
void close_reply(void);
|
||||
int common_open(char path[PATH_MAX], int oflags, mode_t omode);
|
||||
int do_creat(void);
|
||||
int do_lseek(message *m_out);
|
||||
|
|
@ -193,7 +191,7 @@ int do_check_perms(message *m_out);
|
|||
int do_pipe(message *m_out);
|
||||
int do_pipe2(message *m_out);
|
||||
int map_vnode(struct vnode *vp, endpoint_t fs_e);
|
||||
void unpause(endpoint_t proc_e);
|
||||
void unpause(void);
|
||||
int pipe_check(struct filp *filp, int rw_flag, int oflags, int bytes,
|
||||
int notouch);
|
||||
void release(struct vnode *vp, int op, int count);
|
||||
|
|
@ -359,22 +357,24 @@ int do_gcov_flush(void);
|
|||
int do_select(message *m_out);
|
||||
void init_select(void);
|
||||
void select_callback(struct filp *, int ops);
|
||||
void select_forget(endpoint_t proc_e);
|
||||
void select_forget(void);
|
||||
void select_reply1(endpoint_t driver_e, int minor, int status);
|
||||
void select_reply2(endpoint_t driver_e, int minor, int status);
|
||||
void select_timeout_check(timer_t *);
|
||||
void select_unsuspend_by_endpt(endpoint_t proc);
|
||||
|
||||
/* worker.c */
|
||||
void worker_init(void);
|
||||
int worker_available(void);
|
||||
struct worker_thread *worker_get(thread_t worker_tid);
|
||||
struct job *worker_getjob(thread_t worker_tid);
|
||||
void worker_init(struct worker_thread *worker);
|
||||
void worker_signal(struct worker_thread *worker);
|
||||
void worker_start(void *(*func)(void *arg));
|
||||
int worker_can_start(struct fproc *rfp);
|
||||
void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr,
|
||||
int use_spare);
|
||||
void worker_stop(struct worker_thread *worker);
|
||||
void worker_stop_by_endpt(endpoint_t proc_e);
|
||||
void worker_wait(void);
|
||||
void sys_worker_start(void *(*func)(void *arg));
|
||||
void dl_worker_start(void *(*func)(void *arg));
|
||||
struct worker_thread *worker_suspend(void);
|
||||
void worker_resume(struct worker_thread *org_self);
|
||||
void worker_set_proc(struct fproc *rfp);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include <minix/com.h>
|
||||
#include <minix/u64.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "scratchpad.h"
|
||||
#include "param.h"
|
||||
#include <dirent.h>
|
||||
|
|
@ -41,20 +40,17 @@ int do_read(message *UNUSED(m_out))
|
|||
*===========================================================================*/
|
||||
void lock_bsf(void)
|
||||
{
|
||||
struct fproc *org_fp;
|
||||
struct worker_thread *org_self;
|
||||
|
||||
if (mutex_trylock(&bsf_lock) == 0)
|
||||
return;
|
||||
|
||||
org_fp = fp;
|
||||
org_self = self;
|
||||
org_self = worker_suspend();
|
||||
|
||||
if (mutex_lock(&bsf_lock) != 0)
|
||||
panic("unable to lock block special file lock");
|
||||
|
||||
fp = org_fp;
|
||||
self = org_self;
|
||||
worker_resume(org_self);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -150,7 +146,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
|
|||
|
||||
if (size > SSIZE_MAX) return(EINVAL);
|
||||
|
||||
op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE);
|
||||
op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S);
|
||||
|
||||
if (S_ISFIFO(vp->v_mode)) { /* Pipes */
|
||||
if (rfp->fp_cum_io_partial != 0) {
|
||||
|
|
@ -164,7 +160,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
|
|||
} else if (S_ISCHR(vp->v_mode)) { /* Character special files. */
|
||||
dev_t dev;
|
||||
int suspend_reopen;
|
||||
int op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE);
|
||||
int op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S);
|
||||
|
||||
if(rw_flag == PEEKING) {
|
||||
printf("read_write: peek on char device makes no sense\n");
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include <minix/u64.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include "fproc.h"
|
||||
#include "vmnt.h"
|
||||
#include "vnode.h"
|
||||
#include "path.h"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
* do_select: perform the SELECT system call
|
||||
* select_callback: notify select system of possible fd operation
|
||||
* select_unsuspend_by_endpt: cancel a blocking select on exiting driver
|
||||
*
|
||||
* The select code uses minimal locking, so that the replies from character
|
||||
* drivers can be processed without blocking. Filps are locked only for pipes.
|
||||
* We make the assumption that any other structures and fields are safe to
|
||||
* check (and possibly change) as long as we know that a process is blocked on
|
||||
* a select(2) call, meaning that all involved filps are guaranteed to stay
|
||||
* open until either we finish the select call, it the process gets interrupted
|
||||
* by a signal.
|
||||
*/
|
||||
|
||||
#include "fs.h"
|
||||
|
|
@ -17,8 +25,6 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "dmap.h"
|
||||
#include "vnode.h"
|
||||
|
||||
/* max. number of simultaneously pending select() calls */
|
||||
|
|
@ -37,13 +43,12 @@ static struct selectentry {
|
|||
int nfds, nreadyfds;
|
||||
int error;
|
||||
char block;
|
||||
char starting;
|
||||
clock_t expiry;
|
||||
timer_t timer; /* if expiry > 0 */
|
||||
} selecttab[MAXSELECTS];
|
||||
|
||||
static int copy_fdsets(struct selectentry *se, int nfds, int
|
||||
direction);
|
||||
static int do_select_request(struct selectentry *se, int fd, int *ops);
|
||||
static int copy_fdsets(struct selectentry *se, int nfds, int direction);
|
||||
static void filp_status(struct filp *fp, int status);
|
||||
static int is_deferred(struct selectentry *se);
|
||||
static void restart_proc(struct selectentry *se);
|
||||
|
|
@ -52,11 +57,9 @@ static int is_regular_file(struct filp *f);
|
|||
static int is_pipe(struct filp *f);
|
||||
static int is_supported_major(struct filp *f);
|
||||
static void select_lock_filp(struct filp *f, int ops);
|
||||
static int select_request_async(struct filp *f, int *ops, int block);
|
||||
static int select_request_file(struct filp *f, int *ops, int block);
|
||||
static int select_request_major(struct filp *f, int *ops, int block);
|
||||
static int select_request_pipe(struct filp *f, int *ops, int block);
|
||||
static int select_request_sync(struct filp *f, int *ops, int block);
|
||||
static void select_cancel_all(struct selectentry *e);
|
||||
static void select_cancel_filp(struct filp *f);
|
||||
static void select_return(struct selectentry *);
|
||||
|
|
@ -88,13 +91,15 @@ int do_select(message *UNUSED(m_out))
|
|||
{
|
||||
/* Implement the select(nfds, readfds, writefds, errorfds, timeout) system
|
||||
* call. First we copy the arguments and verify their sanity. Then we check
|
||||
* whether there are file descriptors that satisfy the select call right of the
|
||||
* bat. If so, or if there are no ready file descriptors but the process
|
||||
* whether there are file descriptors that satisfy the select call right off
|
||||
* the bat. If so, or if there are no ready file descriptors but the process
|
||||
* requested to return immediately, we return the result. Otherwise we set a
|
||||
* timeout and wait for either the file descriptors to become ready or the
|
||||
* timer to go off. If no timeout value was provided, we wait indefinitely. */
|
||||
|
||||
* timer to go off. If no timeout value was provided, we wait indefinitely.
|
||||
*/
|
||||
int r, nfds, do_timeout = 0, fd, s;
|
||||
struct filp *f;
|
||||
unsigned int type, ops;
|
||||
struct timeval timeout;
|
||||
struct selectentry *se;
|
||||
vir_bytes vtimeout;
|
||||
|
|
@ -153,11 +158,14 @@ int do_select(message *UNUSED(m_out))
|
|||
se->block = 0;
|
||||
se->expiry = 0; /* no timer set (yet) */
|
||||
|
||||
/* We are going to lock filps, and that means that while locking a second
|
||||
* filp, we might already get the results for the first one. In that case,
|
||||
* the incoming results must not cause the select call to finish prematurely.
|
||||
*/
|
||||
se->starting = TRUE;
|
||||
|
||||
/* Verify that file descriptors are okay to select on */
|
||||
for (fd = 0; fd < nfds; fd++) {
|
||||
struct filp *f;
|
||||
unsigned int type, ops;
|
||||
|
||||
/* Because the select() interface implicitly includes file descriptors
|
||||
* you might not want to select on, we have to figure out whether we're
|
||||
* interested in them. Typically, these file descriptors include fd's
|
||||
|
|
@ -210,9 +218,6 @@ int do_select(message *UNUSED(m_out))
|
|||
|
||||
/* Check all file descriptors in the set whether one is 'ready' now */
|
||||
for (fd = 0; fd < nfds; fd++) {
|
||||
int ops, r;
|
||||
struct filp *f;
|
||||
|
||||
/* Again, check for involuntarily selected fd's */
|
||||
if (!(ops = tab2ops(fd, se)))
|
||||
continue; /* No operations set; nothing to do for this fd */
|
||||
|
|
@ -224,9 +229,15 @@ int do_select(message *UNUSED(m_out))
|
|||
int wantops;
|
||||
|
||||
wantops = (f->filp_select_ops |= ops);
|
||||
r = do_select_request(se, fd, &wantops);
|
||||
if (r != OK && r != SUSPEND)
|
||||
type = se->type[fd];
|
||||
select_lock_filp(f, wantops);
|
||||
r = fdtypes[type].select_request(f, &wantops, se->block);
|
||||
unlock_filp(f);
|
||||
if (r != OK && r != SUSPEND) {
|
||||
se->error = r;
|
||||
se->block = 0; /* Stop blocking to return asap */
|
||||
break; /* Error or bogus return code; abort */
|
||||
}
|
||||
|
||||
/* The select request above might have turned on/off some
|
||||
* operations because they were 'ready' or not meaningful.
|
||||
|
|
@ -236,6 +247,9 @@ int do_select(message *UNUSED(m_out))
|
|||
}
|
||||
}
|
||||
|
||||
/* At this point there won't be any blocking calls anymore. */
|
||||
se->starting = FALSE;
|
||||
|
||||
if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) {
|
||||
/* fd's were found that were ready to go right away, and/or
|
||||
* we were instructed not to block at all. Must return
|
||||
|
|
@ -291,6 +305,9 @@ static int is_deferred(struct selectentry *se)
|
|||
int fd;
|
||||
struct filp *f;
|
||||
|
||||
/* The select call must have finished its initialization at all. */
|
||||
if (se->starting) return(TRUE);
|
||||
|
||||
for (fd = 0; fd < se->nfds; fd++) {
|
||||
if ((f = se->filps[fd]) == NULL) continue;
|
||||
if (f->filp_select_flags & (FSF_UPDATE|FSF_BUSY)) return(TRUE);
|
||||
|
|
@ -322,7 +339,10 @@ static int is_pipe(struct filp *f)
|
|||
*===========================================================================*/
|
||||
static int is_supported_major(struct filp *f)
|
||||
{
|
||||
/* See if this filp is a handle on a device on which we support select() */
|
||||
/* See if this filp is a handle on a character device on which we support
|
||||
* select(). This function MUST NOT block its calling thread. The given filp
|
||||
* may or may not be locked.
|
||||
*/
|
||||
unsigned int m;
|
||||
|
||||
if (!(f && f->filp_vno)) return(FALSE);
|
||||
|
|
@ -336,13 +356,21 @@ static int is_supported_major(struct filp *f)
|
|||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_request_async *
|
||||
* select_request_major *
|
||||
*===========================================================================*/
|
||||
static int select_request_async(struct filp *f, int *ops, int block)
|
||||
static int select_request_major(struct filp *f, int *ops, int block)
|
||||
{
|
||||
/* Check readiness status on a supported character device. Unless suitable
|
||||
* results are available right now, this will only initiate the polling
|
||||
* process, causing result processing to be deferred. This function MUST NOT
|
||||
* block its calling thread. The given filp may or may not be locked.
|
||||
*/
|
||||
int r, rops, major;
|
||||
struct dmap *dp;
|
||||
|
||||
major = major(f->filp_vno->v_sdev);
|
||||
if (major < 0 || major >= NR_DEVICES) return(ENXIO);
|
||||
|
||||
rops = *ops;
|
||||
|
||||
/* By default, nothing to do */
|
||||
|
|
@ -375,21 +403,16 @@ static int select_request_async(struct filp *f, int *ops, int block)
|
|||
if (f->filp_select_flags & FSF_BUSY)
|
||||
return(SUSPEND);
|
||||
|
||||
major = major(f->filp_vno->v_sdev);
|
||||
if (major < 0 || major >= NR_DEVICES) return(ENXIO);
|
||||
dp = &dmap[major];
|
||||
if (dp->dmap_sel_filp)
|
||||
if (dp->dmap_sel_busy)
|
||||
return(SUSPEND);
|
||||
|
||||
f->filp_select_flags &= ~FSF_UPDATE;
|
||||
r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
|
||||
((u64_t)(0)), 0, 0, FALSE);
|
||||
if (r < 0 && r != SUSPEND)
|
||||
r = dev_select(f->filp_vno->v_sdev, rops);
|
||||
if (r != OK)
|
||||
return(r);
|
||||
|
||||
if (r != SUSPEND)
|
||||
panic("select_request_asynch: expected SUSPEND got: %d", r);
|
||||
|
||||
dp->dmap_sel_busy = TRUE;
|
||||
dp->dmap_sel_filp = f;
|
||||
f->filp_select_flags |= FSF_BUSY;
|
||||
|
||||
|
|
@ -406,47 +429,14 @@ static int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops),
|
|||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_request_major *
|
||||
*===========================================================================*/
|
||||
static int select_request_major(struct filp *f, int *ops, int block)
|
||||
{
|
||||
int major, r;
|
||||
|
||||
major = major(f->filp_vno->v_sdev);
|
||||
if (major < 0 || major >= NR_DEVICES) return(ENXIO);
|
||||
|
||||
if (dmap[major].dmap_style == STYLE_DEVA ||
|
||||
dmap[major].dmap_style == STYLE_CLONE_A)
|
||||
r = select_request_async(f, ops, block);
|
||||
else
|
||||
r = select_request_sync(f, ops, block);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_request_sync *
|
||||
*===========================================================================*/
|
||||
static int select_request_sync(struct filp *f, int *ops, int block)
|
||||
{
|
||||
int rops;
|
||||
|
||||
rops = *ops;
|
||||
if (block) rops |= SEL_NOTIFY;
|
||||
*ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
|
||||
((u64_t)(0)), 0, 0, FALSE);
|
||||
if (*ops < 0)
|
||||
return(*ops);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* select_request_pipe *
|
||||
*===========================================================================*/
|
||||
static int select_request_pipe(struct filp *f, int *ops, int block)
|
||||
{
|
||||
/* Check readiness status on a pipe. The given filp is locked. This function
|
||||
* may block its calling thread if necessary.
|
||||
*/
|
||||
int orig_ops, r = 0, err;
|
||||
|
||||
orig_ops = *ops;
|
||||
|
|
@ -538,6 +528,9 @@ static void ops2tab(int ops, int fd, struct selectentry *e)
|
|||
*===========================================================================*/
|
||||
static int copy_fdsets(struct selectentry *se, int nfds, int direction)
|
||||
{
|
||||
/* Copy FD sets from or to the user process calling select(2). This function
|
||||
* MUST NOT block the calling thread.
|
||||
*/
|
||||
int r;
|
||||
size_t fd_setsize;
|
||||
endpoint_t src_e, dst_e;
|
||||
|
|
@ -589,7 +582,9 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction)
|
|||
*===========================================================================*/
|
||||
static void select_cancel_all(struct selectentry *se)
|
||||
{
|
||||
/* Cancel select. Decrease select usage and cancel timer */
|
||||
/* Cancel select, possibly on success. Decrease select usage and cancel timer.
|
||||
* This function MUST NOT block its calling thread.
|
||||
*/
|
||||
|
||||
int fd;
|
||||
struct filp *f;
|
||||
|
|
@ -613,14 +608,14 @@ static void select_cancel_all(struct selectentry *se)
|
|||
*===========================================================================*/
|
||||
static void select_cancel_filp(struct filp *f)
|
||||
{
|
||||
/* Reduce number of select users of this filp */
|
||||
/* Reduce the number of select users of this filp. This function MUST NOT block
|
||||
* its calling thread.
|
||||
*/
|
||||
dev_t major;
|
||||
|
||||
assert(f);
|
||||
assert(f->filp_selectors >= 0);
|
||||
if (f->filp_selectors == 0) return;
|
||||
if (f->filp_count == 0) return;
|
||||
|
||||
select_lock_filp(f, f->filp_select_ops);
|
||||
assert(f->filp_selectors > 0);
|
||||
assert(f->filp_count > 0);
|
||||
|
||||
f->filp_selectors--;
|
||||
if (f->filp_selectors == 0) {
|
||||
|
|
@ -628,9 +623,18 @@ static void select_cancel_filp(struct filp *f)
|
|||
f->filp_select_ops = 0;
|
||||
f->filp_select_flags = 0;
|
||||
f->filp_pipe_select_ops = 0;
|
||||
}
|
||||
|
||||
unlock_filp(f);
|
||||
/* If this filp is the subject of an ongoing select query to a
|
||||
* character device, mark the query as stale, so that this filp will
|
||||
* not be checked when the result arrives.
|
||||
*/
|
||||
if (is_supported_major(f)) {
|
||||
major = major(f->filp_vno->v_sdev);
|
||||
if (dmap[major].dmap_sel_busy &&
|
||||
dmap[major].dmap_sel_filp == f)
|
||||
dmap[major].dmap_sel_filp = NULL; /* leave _busy set */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
@ -638,6 +642,9 @@ static void select_cancel_filp(struct filp *f)
|
|||
*===========================================================================*/
|
||||
static void select_return(struct selectentry *se)
|
||||
{
|
||||
/* Return the results of a select call to the user process and revive the
|
||||
* process. This function MUST NOT block its calling thread.
|
||||
*/
|
||||
int r, r1;
|
||||
|
||||
assert(!is_deferred(se)); /* Not done yet, first wait for async reply */
|
||||
|
|
@ -661,6 +668,11 @@ static void select_return(struct selectentry *se)
|
|||
*===========================================================================*/
|
||||
void select_callback(struct filp *f, int status)
|
||||
{
|
||||
/* The status of a filp has changed, with the given ready operations or error.
|
||||
* This function is currently called only for pipes, and holds the lock to
|
||||
* the filp.
|
||||
*/
|
||||
|
||||
filp_status(f, status);
|
||||
}
|
||||
|
||||
|
|
@ -679,24 +691,27 @@ void init_select(void)
|
|||
/*===========================================================================*
|
||||
* select_forget *
|
||||
*===========================================================================*/
|
||||
void select_forget(endpoint_t proc_e)
|
||||
void select_forget(void)
|
||||
{
|
||||
/* Something has happened (e.g. signal delivered that interrupts select()).
|
||||
* Totally forget about the select(). */
|
||||
|
||||
/* The calling thread's associated process is expected to be unpaused, due to
|
||||
* a signal that is supposed to interrupt the current system call. Totally
|
||||
* forget about the select(). This function may block its calling thread if
|
||||
* necessary (but it doesn't).
|
||||
*/
|
||||
int slot;
|
||||
struct selectentry *se;
|
||||
|
||||
for (slot = 0; slot < MAXSELECTS; slot++) {
|
||||
se = &selecttab[slot];
|
||||
if (se->requestor != NULL && se->req_endpt == proc_e)
|
||||
if (se->requestor == fp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (slot >= MAXSELECTS) return; /* Entry not found */
|
||||
se->error = EINTR;
|
||||
if (is_deferred(se)) return; /* Still awaiting initial reply */
|
||||
|
||||
assert(se->starting == FALSE);
|
||||
|
||||
/* Do NOT test on is_deferred here. We can safely cancel ongoing queries. */
|
||||
select_cancel_all(se);
|
||||
}
|
||||
|
||||
|
|
@ -706,6 +721,9 @@ void select_forget(endpoint_t proc_e)
|
|||
*===========================================================================*/
|
||||
void select_timeout_check(timer_t *timer)
|
||||
{
|
||||
/* An alarm has gone off for one of the select queries. This function MUST NOT
|
||||
* block its calling thread.
|
||||
*/
|
||||
int s;
|
||||
struct selectentry *se;
|
||||
|
||||
|
|
@ -714,7 +732,6 @@ void select_timeout_check(timer_t *timer)
|
|||
|
||||
se = &selecttab[s];
|
||||
if (se->requestor == NULL) return;
|
||||
fp = se->requestor;
|
||||
if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */
|
||||
se->expiry = 0;
|
||||
if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */
|
||||
|
|
@ -769,8 +786,9 @@ endpoint_t driver_e;
|
|||
int minor;
|
||||
int status;
|
||||
{
|
||||
/* Handle reply to DEV_SELECT request */
|
||||
|
||||
/* Handle the initial reply to DEV_SELECT request. This function MUST NOT
|
||||
* block its calling thread.
|
||||
*/
|
||||
int major;
|
||||
dev_t dev;
|
||||
struct filp *f;
|
||||
|
|
@ -784,20 +802,25 @@ int status;
|
|||
dev = makedev(major, minor);
|
||||
|
||||
/* Get filp belonging to character special file */
|
||||
if ((f = dp->dmap_sel_filp) == NULL) {
|
||||
if (!dp->dmap_sel_busy) {
|
||||
printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n",
|
||||
__FILE__, __LINE__, major);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is the filp still in use and busy waiting for a reply? The owner might
|
||||
* have vanished before the driver was able to reply. */
|
||||
if (f->filp_count >= 1 && (f->filp_select_flags & FSF_BUSY)) {
|
||||
/* The select filp may have been set to NULL if the requestor has been
|
||||
* unpaused in the meantime. In that case, we ignore the result, but we do
|
||||
* look for other filps to restart later.
|
||||
*/
|
||||
if ((f = dp->dmap_sel_filp) != NULL) {
|
||||
/* Find vnode and check we got a reply from the device we expected */
|
||||
vp = f->filp_vno;
|
||||
assert(vp != NULL);
|
||||
assert(S_ISCHR(vp->v_mode));
|
||||
if (vp->v_sdev != dev) {
|
||||
/* This should never happen. The driver may be misbehaving.
|
||||
* For now we assume that the reply we want will arrive later..
|
||||
*/
|
||||
printf("VFS (%s:%d): expected reply from dev %d not %d\n",
|
||||
__FILE__, __LINE__, vp->v_sdev, dev);
|
||||
return;
|
||||
|
|
@ -805,13 +828,14 @@ int status;
|
|||
}
|
||||
|
||||
/* No longer waiting for a reply from this device */
|
||||
dp->dmap_sel_busy = FALSE;
|
||||
dp->dmap_sel_filp = NULL;
|
||||
|
||||
/* Process select result only if requestor is still around. That is, the
|
||||
* corresponding filp is still in use.
|
||||
*/
|
||||
if (f->filp_count >= 1) {
|
||||
select_lock_filp(f, f->filp_select_ops);
|
||||
/* Process the select result only if the filp is valid. */
|
||||
if (f != NULL) {
|
||||
assert(f->filp_count >= 1);
|
||||
assert(f->filp_select_flags & FSF_BUSY);
|
||||
|
||||
f->filp_select_flags &= ~FSF_BUSY;
|
||||
|
||||
/* The select call is done now, except when
|
||||
|
|
@ -845,7 +869,6 @@ int status;
|
|||
}
|
||||
}
|
||||
|
||||
unlock_filp(f);
|
||||
filp_status(f, status); /* Tell filp owners about the results */
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +885,9 @@ int minor;
|
|||
int status;
|
||||
{
|
||||
/* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when
|
||||
* the select request is 'blocking' until an operation becomes ready. */
|
||||
* the select request is 'blocking' until an operation becomes ready. This
|
||||
* function MUST NOT block its calling thread.
|
||||
*/
|
||||
int major, slot, fd;
|
||||
dev_t dev;
|
||||
struct filp *f;
|
||||
|
|
@ -896,7 +921,6 @@ int status;
|
|||
if (!S_ISCHR(vp->v_mode)) continue;
|
||||
if (vp->v_sdev != dev) continue;
|
||||
|
||||
select_lock_filp(f, f->filp_select_ops);
|
||||
if (status > 0) { /* Operations ready */
|
||||
/* Clear the replied bits from the request
|
||||
* mask unless FSF_UPDATE is set.
|
||||
|
|
@ -915,7 +939,6 @@ int status;
|
|||
f->filp_select_flags &= ~FSF_BLOCKED;
|
||||
ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se);
|
||||
}
|
||||
unlock_filp(f);
|
||||
if (se->nreadyfds > 0) restart_proc(se);
|
||||
}
|
||||
}
|
||||
|
|
@ -926,11 +949,14 @@ int status;
|
|||
/*===========================================================================*
|
||||
* select_restart_filps *
|
||||
*===========================================================================*/
|
||||
static void select_restart_filps()
|
||||
static void select_restart_filps(void)
|
||||
{
|
||||
/* We got a result from a character driver, and now we need to check if we can
|
||||
* restart deferred polling operations. This function MUST NOT block its
|
||||
* calling thread.
|
||||
*/
|
||||
int fd, slot;
|
||||
struct filp *f;
|
||||
struct vnode *vp;
|
||||
struct selectentry *se;
|
||||
|
||||
/* Locate filps that can be restarted */
|
||||
|
|
@ -954,44 +980,25 @@ static void select_restart_filps()
|
|||
if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */
|
||||
continue; /* 'update' state */
|
||||
|
||||
/* This function is suitable only for character devices. In
|
||||
* particular, checking pipes the same way would introduce a
|
||||
* serious locking problem.
|
||||
*/
|
||||
assert(is_supported_major(f));
|
||||
|
||||
wantops = ops = f->filp_select_ops;
|
||||
vp = f->filp_vno;
|
||||
assert(S_ISCHR(vp->v_mode));
|
||||
r = do_select_request(se, fd, &wantops);
|
||||
if (r != OK && r != SUSPEND)
|
||||
r = select_request_major(f, &wantops, se->block);
|
||||
if (r != OK && r != SUSPEND) {
|
||||
se->error = r;
|
||||
se->block = 0; /* Stop blocking to return asap */
|
||||
restart_proc(se);
|
||||
break; /* Error or bogus return code; abort */
|
||||
}
|
||||
if (wantops & ops) ops2tab(wantops, fd, se);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_select_request *
|
||||
*===========================================================================*/
|
||||
static int do_select_request(se, fd, ops)
|
||||
struct selectentry *se;
|
||||
int fd;
|
||||
int *ops;
|
||||
{
|
||||
/* Perform actual select request for file descriptor fd */
|
||||
|
||||
int r, type;
|
||||
struct filp *f;
|
||||
|
||||
type = se->type[fd];
|
||||
f = se->filps[fd];
|
||||
select_lock_filp(f, *ops);
|
||||
r = fdtypes[type].select_request(f, ops, se->block);
|
||||
unlock_filp(f);
|
||||
if (r != OK && r != SUSPEND) {
|
||||
se->error = EINTR;
|
||||
se->block = 0; /* Stop blocking to return asap */
|
||||
if (!is_deferred(se)) select_cancel_all(se);
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* filp_status *
|
||||
*===========================================================================*/
|
||||
|
|
@ -999,7 +1006,9 @@ static void filp_status(f, status)
|
|||
struct filp *f;
|
||||
int status;
|
||||
{
|
||||
/* Tell processes that need to know about the status of this filp */
|
||||
/* Tell processes that need to know about the status of this filp. This
|
||||
* function MUST NOT block its calling thread.
|
||||
*/
|
||||
int fd, slot;
|
||||
struct selectentry *se;
|
||||
|
||||
|
|
@ -1025,7 +1034,8 @@ static void restart_proc(se)
|
|||
struct selectentry *se;
|
||||
{
|
||||
/* Tell process about select results (if any) unless there are still results
|
||||
* pending. */
|
||||
* pending. This function MUST NOT block its calling thread.
|
||||
*/
|
||||
|
||||
if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se))
|
||||
select_return(se);
|
||||
|
|
@ -1055,8 +1065,10 @@ static void wipe_select(struct selectentry *se)
|
|||
*===========================================================================*/
|
||||
static void select_lock_filp(struct filp *f, int ops)
|
||||
{
|
||||
/* Lock a filp and vnode based on which operations are requested */
|
||||
tll_access_t locktype;;
|
||||
/* Lock a filp and vnode based on which operations are requested. This function
|
||||
* may block its calling thread, obviously.
|
||||
*/
|
||||
tll_access_t locktype;
|
||||
|
||||
locktype = VNODE_READ; /* By default */
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <minix/u64.h>
|
||||
#include <string.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
#include "param.h"
|
||||
#include <minix/vfsif.h>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <minix/callnr.h>
|
||||
#include <minix/com.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "lock.h"
|
||||
#include "scratchpad.h"
|
||||
#include "vnode.h"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef __VFS_WORKERS_H__
|
||||
#define __VFS_WORKERS_H__
|
||||
#include <minix/mthread.h>
|
||||
#include "job.h"
|
||||
|
||||
#define thread_t mthread_thread_t
|
||||
#define mutex_t mthread_mutex_t
|
||||
|
|
@ -23,12 +22,15 @@
|
|||
#define cond_wait mthread_cond_wait
|
||||
#define cond_signal mthread_cond_signal
|
||||
|
||||
struct fproc;
|
||||
|
||||
struct worker_thread {
|
||||
thread_t w_tid;
|
||||
mutex_t w_event_mutex;
|
||||
cond_t w_event;
|
||||
struct job w_job;
|
||||
struct fproc *w_fp;
|
||||
message w_msg;
|
||||
int w_err_code;
|
||||
message *w_fs_sendrec;
|
||||
message *w_drv_sendrec;
|
||||
endpoint_t w_task;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "path.h"
|
||||
#include "param.h"
|
||||
#include "vnode.h"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include "file.h"
|
||||
#include "fproc.h"
|
||||
#include "param.h"
|
||||
#include "vmnt.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@
|
|||
*/
|
||||
|
||||
#include "fs.h"
|
||||
#include "threads.h"
|
||||
#include "vmnt.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "fproc.h"
|
||||
|
||||
static int is_vmnt_locked(struct vmnt *vmp);
|
||||
static void clear_vmnt(struct vmnt *vmp);
|
||||
|
|
|
|||
|
|
@ -9,10 +9,8 @@
|
|||
*/
|
||||
|
||||
#include "fs.h"
|
||||
#include "threads.h"
|
||||
#include "vnode.h"
|
||||
#include "vmnt.h"
|
||||
#include "fproc.h"
|
||||
#include "file.h"
|
||||
#include <minix/vfsif.h>
|
||||
#include <assert.h>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
#include "fs.h"
|
||||
#include "glo.h"
|
||||
#include "fproc.h"
|
||||
#include "threads.h"
|
||||
#include "job.h"
|
||||
#include <assert.h>
|
||||
|
||||
static void append_job(struct job *job, void *(*func)(void *arg));
|
||||
static void get_work(struct worker_thread *worker);
|
||||
static void worker_get_work(void);
|
||||
static void *worker_main(void *arg);
|
||||
static void worker_sleep(struct worker_thread *worker);
|
||||
static void worker_sleep(void);
|
||||
static void worker_wake(struct worker_thread *worker);
|
||||
static int worker_waiting_for(struct worker_thread *worker, endpoint_t
|
||||
proc_e);
|
||||
static int init = 0;
|
||||
static mthread_attr_t tattr;
|
||||
|
||||
#ifdef MKCOVERAGE
|
||||
|
|
@ -21,66 +13,60 @@ static mthread_attr_t tattr;
|
|||
# define TH_STACKSIZE (28 * 1024)
|
||||
#endif
|
||||
|
||||
#define ASSERTW(w) assert((w) == &sys_worker || (w) == &dl_worker || \
|
||||
((w) >= &workers[0] && (w) < &workers[NR_WTHREADS]));
|
||||
#define ASSERTW(w) assert((w) >= &workers[0] && (w) < &workers[NR_WTHREADS])
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_init *
|
||||
*===========================================================================*/
|
||||
void worker_init(struct worker_thread *wp)
|
||||
void worker_init(void)
|
||||
{
|
||||
/* Initialize worker thread */
|
||||
if (!init) {
|
||||
threads_init();
|
||||
if (mthread_attr_init(&tattr) != 0)
|
||||
panic("failed to initialize attribute");
|
||||
if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0)
|
||||
panic("couldn't set default thread stack size");
|
||||
if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0)
|
||||
panic("couldn't set default thread detach state");
|
||||
invalid_thread_id = mthread_self(); /* Assuming we're the main thread*/
|
||||
pending = 0;
|
||||
init = 1;
|
||||
struct worker_thread *wp;
|
||||
int i;
|
||||
|
||||
threads_init();
|
||||
if (mthread_attr_init(&tattr) != 0)
|
||||
panic("failed to initialize attribute");
|
||||
if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0)
|
||||
panic("couldn't set default thread stack size");
|
||||
if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0)
|
||||
panic("couldn't set default thread detach state");
|
||||
pending = 0;
|
||||
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
wp = &workers[i];
|
||||
|
||||
wp->w_fp = NULL; /* Mark not in use */
|
||||
wp->w_next = NULL;
|
||||
if (mutex_init(&wp->w_event_mutex, NULL) != 0)
|
||||
panic("failed to initialize mutex");
|
||||
if (cond_init(&wp->w_event, NULL) != 0)
|
||||
panic("failed to initialize conditional variable");
|
||||
if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0)
|
||||
panic("unable to start thread");
|
||||
}
|
||||
|
||||
ASSERTW(wp);
|
||||
|
||||
wp->w_job.j_func = NULL; /* Mark not in use */
|
||||
wp->w_next = NULL;
|
||||
if (mutex_init(&wp->w_event_mutex, NULL) != 0)
|
||||
panic("failed to initialize mutex");
|
||||
if (cond_init(&wp->w_event, NULL) != 0)
|
||||
panic("failed to initialize conditional variable");
|
||||
if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0)
|
||||
panic("unable to start thread");
|
||||
yield();
|
||||
/* Let all threads get ready to accept work. */
|
||||
yield_all();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* get_work *
|
||||
* worker_get_work *
|
||||
*===========================================================================*/
|
||||
static void get_work(struct worker_thread *worker)
|
||||
static void worker_get_work(void)
|
||||
{
|
||||
/* Find new work to do. Work can be 'queued', 'pending', or absent. In the
|
||||
* latter case wait for new work to come in. */
|
||||
|
||||
struct job *new_job;
|
||||
* latter case wait for new work to come in.
|
||||
*/
|
||||
struct fproc *rfp;
|
||||
|
||||
ASSERTW(worker);
|
||||
self = worker;
|
||||
|
||||
/* Do we have queued work to do? */
|
||||
if ((new_job = worker->w_job.j_next) != NULL) {
|
||||
worker->w_job = *new_job;
|
||||
free(new_job);
|
||||
return;
|
||||
} else if (worker != &sys_worker && worker != &dl_worker && pending > 0) {
|
||||
if (pending > 0) {
|
||||
/* Find pending work */
|
||||
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
|
||||
if (rfp->fp_flags & FP_PENDING) {
|
||||
worker->w_job = rfp->fp_job;
|
||||
rfp->fp_job.j_func = NULL;
|
||||
self->w_fp = rfp;
|
||||
rfp->fp_worker = self;
|
||||
rfp->fp_flags &= ~FP_PENDING; /* No longer pending */
|
||||
pending--;
|
||||
assert(pending >= 0);
|
||||
|
|
@ -91,11 +77,11 @@ static void get_work(struct worker_thread *worker)
|
|||
}
|
||||
|
||||
/* Wait for work to come to us */
|
||||
worker_sleep(worker);
|
||||
worker_sleep();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_available *
|
||||
* worker_available *
|
||||
*===========================================================================*/
|
||||
int worker_available(void)
|
||||
{
|
||||
|
|
@ -103,7 +89,7 @@ int worker_available(void)
|
|||
|
||||
busy = 0;
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
if (workers[i].w_job.j_func != NULL)
|
||||
if (workers[i].w_fp != NULL)
|
||||
busy++;
|
||||
}
|
||||
|
||||
|
|
@ -116,151 +102,207 @@ int worker_available(void)
|
|||
static void *worker_main(void *arg)
|
||||
{
|
||||
/* Worker thread main loop */
|
||||
struct worker_thread *me;
|
||||
|
||||
me = (struct worker_thread *) arg;
|
||||
ASSERTW(me);
|
||||
self = (struct worker_thread *) arg;
|
||||
ASSERTW(self);
|
||||
|
||||
while(TRUE) {
|
||||
get_work(me);
|
||||
worker_get_work();
|
||||
|
||||
/* Register ourselves in fproc table if possible */
|
||||
if (me->w_job.j_fp != NULL) {
|
||||
me->w_job.j_fp->fp_wtid = me->w_tid;
|
||||
fp = self->w_fp;
|
||||
assert(fp->fp_worker == self);
|
||||
|
||||
/* Lock the process. */
|
||||
lock_proc(fp);
|
||||
|
||||
/* The following two blocks could be run in a loop until both the
|
||||
* conditions are no longer met, but it is currently impossible that
|
||||
* more normal work is present after postponed PM work has been done.
|
||||
*/
|
||||
|
||||
/* Perform normal work, if any. */
|
||||
if (fp->fp_func != NULL) {
|
||||
self->w_msg = fp->fp_msg;
|
||||
err_code = OK;
|
||||
|
||||
fp->fp_func();
|
||||
|
||||
fp->fp_func = NULL; /* deliberately unset AFTER the call */
|
||||
}
|
||||
|
||||
/* Carry out work */
|
||||
me->w_job.j_func(&me->w_job);
|
||||
/* Perform postponed PM work, if any. */
|
||||
if (fp->fp_flags & FP_PM_WORK) {
|
||||
self->w_msg = fp->fp_pm_msg;
|
||||
|
||||
/* Deregister if possible */
|
||||
if (me->w_job.j_fp != NULL) {
|
||||
me->w_job.j_fp->fp_wtid = invalid_thread_id;
|
||||
service_pm_postponed();
|
||||
|
||||
fp->fp_flags &= ~FP_PM_WORK;
|
||||
}
|
||||
|
||||
/* Mark ourselves as done */
|
||||
me->w_job.j_func = NULL;
|
||||
me->w_job.j_fp = NULL;
|
||||
/* Perform cleanup actions. */
|
||||
thread_cleanup();
|
||||
|
||||
unlock_proc(fp);
|
||||
|
||||
fp->fp_worker = NULL;
|
||||
self->w_fp = NULL;
|
||||
}
|
||||
|
||||
return(NULL); /* Unreachable */
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* dl_worker_start *
|
||||
* worker_can_start *
|
||||
*===========================================================================*/
|
||||
void dl_worker_start(void *(*func)(void *arg))
|
||||
int worker_can_start(struct fproc *rfp)
|
||||
{
|
||||
/* Start the deadlock resolving worker. This worker is reserved to run in case
|
||||
* all other workers are busy and we have to have an additional worker to come
|
||||
* to the rescue. */
|
||||
assert(dl_worker.w_job.j_func == NULL);
|
||||
/* Return whether normal (non-PM) work can be started for the given process.
|
||||
* This function is used to serialize invocation of "special" procedures, and
|
||||
* not entirely safe for other cases, as explained in the comments below.
|
||||
*/
|
||||
int is_pending, is_active, has_normal_work, has_pm_work;
|
||||
|
||||
if (dl_worker.w_job.j_func == NULL) {
|
||||
dl_worker.w_job.j_fp = fp;
|
||||
dl_worker.w_job.j_m_in = m_in;
|
||||
dl_worker.w_job.j_func = func;
|
||||
worker_wake(&dl_worker);
|
||||
}
|
||||
is_pending = (rfp->fp_flags & FP_PENDING);
|
||||
is_active = (rfp->fp_worker != NULL);
|
||||
has_normal_work = (rfp->fp_func != NULL);
|
||||
has_pm_work = (rfp->fp_flags & FP_PM_WORK);
|
||||
|
||||
/* If there is no work scheduled for the process, we can start work. */
|
||||
if (!is_pending && !is_active) return TRUE;
|
||||
|
||||
/* If there is already normal work scheduled for the process, we cannot add
|
||||
* more, since we support only one normal job per process.
|
||||
*/
|
||||
if (has_normal_work) return FALSE;
|
||||
|
||||
/* If this process has pending PM work but no normal work, we can add the
|
||||
* normal work for execution before the worker will start.
|
||||
*/
|
||||
if (is_pending) return TRUE;
|
||||
|
||||
/* However, if a worker is active for PM work, we cannot add normal work
|
||||
* either, because the work will not be considered. For this reason, we can
|
||||
* not use this function for processes that can possibly get postponed PM
|
||||
* work. It is still safe for core system processes, though.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sys_worker_start *
|
||||
* worker_try_activate *
|
||||
*===========================================================================*/
|
||||
void sys_worker_start(void *(*func)(void *arg))
|
||||
static void worker_try_activate(struct fproc *rfp, int use_spare)
|
||||
{
|
||||
/* Carry out work for the system (i.e., kernel or PM). If this thread is idle
|
||||
* do it right away, else create new job and append it to the queue. */
|
||||
|
||||
if (sys_worker.w_job.j_func == NULL) {
|
||||
sys_worker.w_job.j_fp = fp;
|
||||
sys_worker.w_job.j_m_in = m_in;
|
||||
sys_worker.w_job.j_func = func;
|
||||
worker_wake(&sys_worker);
|
||||
} else {
|
||||
append_job(&sys_worker.w_job, func);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* append_job *
|
||||
*===========================================================================*/
|
||||
static void append_job(struct job *job, void *(*func)(void *arg))
|
||||
{
|
||||
/* Append a job */
|
||||
|
||||
struct job *new_job, *tail;
|
||||
|
||||
/* Create new job */
|
||||
new_job = calloc(1, sizeof(struct job));
|
||||
assert(new_job != NULL);
|
||||
new_job->j_fp = fp;
|
||||
new_job->j_m_in = m_in;
|
||||
new_job->j_func = func;
|
||||
new_job->j_next = NULL;
|
||||
new_job->j_err_code = OK;
|
||||
|
||||
/* Append to queue */
|
||||
tail = job;
|
||||
while (tail->j_next != NULL) tail = tail->j_next;
|
||||
tail->j_next = new_job;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_start *
|
||||
*===========================================================================*/
|
||||
void worker_start(void *(*func)(void *arg))
|
||||
{
|
||||
/* Find an available worker or wait for one */
|
||||
int i;
|
||||
/* See if we can wake up a thread to do the work scheduled for the given
|
||||
* process. If not, mark the process as having pending work for later.
|
||||
*/
|
||||
int i, available, needed;
|
||||
struct worker_thread *worker;
|
||||
|
||||
if (fp->fp_flags & FP_DROP_WORK) {
|
||||
return; /* This process is not allowed to accept new work */
|
||||
}
|
||||
/* Use the last available thread only if requested. Otherwise, leave at least
|
||||
* one spare thread for deadlock resolution.
|
||||
*/
|
||||
needed = use_spare ? 1 : 2;
|
||||
|
||||
worker = NULL;
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
if (workers[i].w_job.j_func == NULL) {
|
||||
worker = &workers[i];
|
||||
break;
|
||||
for (i = available = 0; i < NR_WTHREADS; i++) {
|
||||
if (workers[i].w_fp == NULL) {
|
||||
if (worker == NULL)
|
||||
worker = &workers[i];
|
||||
if (++available >= needed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (worker != NULL) {
|
||||
worker->w_job.j_fp = fp;
|
||||
worker->w_job.j_m_in = m_in;
|
||||
worker->w_job.j_func = func;
|
||||
worker->w_job.j_next = NULL;
|
||||
worker->w_job.j_err_code = OK;
|
||||
if (available >= needed) {
|
||||
assert(worker != NULL);
|
||||
rfp->fp_worker = worker;
|
||||
worker->w_fp = rfp;
|
||||
worker_wake(worker);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No worker threads available, let's wait for one to finish. */
|
||||
/* If this process already has a job scheduled, forget about this new
|
||||
* job;
|
||||
* - the new job is do_dummy and we have already scheduled an actual job
|
||||
* - the new job is an actual job and we have already scheduled do_dummy in
|
||||
* order to exit this proc, so doing the new job is pointless. */
|
||||
if (fp->fp_job.j_func == NULL) {
|
||||
assert(!(fp->fp_flags & FP_PENDING));
|
||||
fp->fp_job.j_fp = fp;
|
||||
fp->fp_job.j_m_in = m_in;
|
||||
fp->fp_job.j_func = func;
|
||||
fp->fp_job.j_next = NULL;
|
||||
fp->fp_job.j_err_code = OK;
|
||||
fp->fp_flags |= FP_PENDING;
|
||||
} else {
|
||||
rfp->fp_flags |= FP_PENDING;
|
||||
pending++;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_start *
|
||||
*===========================================================================*/
|
||||
void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr,
|
||||
int use_spare)
|
||||
{
|
||||
/* Schedule work to be done by a worker thread. The work is bound to the given
|
||||
* process. If a function pointer is given, the work is considered normal work,
|
||||
* and the function will be called to handle it. If the function pointer is
|
||||
* NULL, the work is considered postponed PM work, and service_pm_postponed
|
||||
* will be called to handle it. The input message will be a copy of the given
|
||||
* message. Optionally, the last spare (deadlock-resolving) thread may be used
|
||||
* to execute the work immediately.
|
||||
*/
|
||||
int is_pm_work, is_pending, is_active, has_normal_work, has_pm_work;
|
||||
|
||||
assert(rfp != NULL);
|
||||
|
||||
is_pm_work = (func == NULL);
|
||||
is_pending = (rfp->fp_flags & FP_PENDING);
|
||||
is_active = (rfp->fp_worker != NULL);
|
||||
has_normal_work = (rfp->fp_func != NULL);
|
||||
has_pm_work = (rfp->fp_flags & FP_PM_WORK);
|
||||
|
||||
/* Sanity checks. If any of these trigger, someone messed up badly! */
|
||||
if (is_pending || is_active) {
|
||||
if (is_pending && is_active)
|
||||
panic("work cannot be both pending and active");
|
||||
|
||||
/* The process cannot make more than one call at once. */
|
||||
if (!is_pm_work && has_normal_work)
|
||||
panic("process has two calls (%x, %x)",
|
||||
rfp->fp_msg.m_type, m_ptr->m_type);
|
||||
|
||||
/* PM will not send more than one job per process to us at once. */
|
||||
if (is_pm_work && has_pm_work)
|
||||
panic("got two calls from PM (%x, %x)",
|
||||
rfp->fp_pm_msg.m_type, m_ptr->m_type);
|
||||
|
||||
/* Despite PM's sys_delay_stop() system, it is possible that normal
|
||||
* work (in particular, do_pending_pipe) arrives after postponed PM
|
||||
* work has been scheduled for execution, so we don't check for that.
|
||||
*/
|
||||
#if 0
|
||||
printf("VFS: adding %s work to %s thread\n",
|
||||
is_pm_work ? "PM" : "normal",
|
||||
is_pending ? "pending" : "active");
|
||||
#endif
|
||||
} else {
|
||||
/* Some cleanup step forgotten somewhere? */
|
||||
if (has_normal_work || has_pm_work)
|
||||
panic("worker administration error");
|
||||
}
|
||||
|
||||
/* Save the work to be performed. */
|
||||
if (!is_pm_work) {
|
||||
rfp->fp_msg = *m_ptr;
|
||||
rfp->fp_func = func;
|
||||
} else {
|
||||
rfp->fp_pm_msg = *m_ptr;
|
||||
rfp->fp_flags |= FP_PM_WORK;
|
||||
}
|
||||
|
||||
/* If we have not only added to existing work, go look for a free thread.
|
||||
* Note that we won't be using the spare thread for normal work if there is
|
||||
* already PM work pending, but that situation will never occur in practice.
|
||||
*/
|
||||
if (!is_pending && !is_active)
|
||||
worker_try_activate(rfp, use_spare);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_sleep *
|
||||
*===========================================================================*/
|
||||
static void worker_sleep(struct worker_thread *worker)
|
||||
static void worker_sleep(void)
|
||||
{
|
||||
struct worker_thread *worker = self;
|
||||
ASSERTW(worker);
|
||||
assert(self == worker);
|
||||
if (mutex_lock(&worker->w_event_mutex) != 0)
|
||||
panic("unable to lock event mutex");
|
||||
if (cond_wait(&worker->w_event, &worker->w_event_mutex) != 0)
|
||||
|
|
@ -285,16 +327,55 @@ static void worker_wake(struct worker_thread *worker)
|
|||
panic("unable to unlock event mutex");
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_suspend *
|
||||
*===========================================================================*/
|
||||
struct worker_thread *worker_suspend(void)
|
||||
{
|
||||
/* Suspend the current thread, saving certain thread variables. Return a
|
||||
* pointer to the thread's worker structure for later resumption.
|
||||
*/
|
||||
|
||||
ASSERTW(self);
|
||||
assert(fp != NULL);
|
||||
assert(self->w_fp == fp);
|
||||
assert(fp->fp_worker == self);
|
||||
|
||||
self->w_err_code = err_code;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_resume *
|
||||
*===========================================================================*/
|
||||
void worker_resume(struct worker_thread *org_self)
|
||||
{
|
||||
/* Resume the current thread after suspension, restoring thread variables. */
|
||||
|
||||
ASSERTW(org_self);
|
||||
|
||||
self = org_self;
|
||||
|
||||
fp = self->w_fp;
|
||||
assert(fp != NULL);
|
||||
|
||||
err_code = self->w_err_code;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_wait *
|
||||
*===========================================================================*/
|
||||
void worker_wait(void)
|
||||
{
|
||||
self->w_job.j_err_code = err_code;
|
||||
worker_sleep(self);
|
||||
/* Put the current thread to sleep until woken up by the main thread. */
|
||||
|
||||
(void) worker_suspend(); /* worker_sleep already saves and restores 'self' */
|
||||
|
||||
worker_sleep();
|
||||
|
||||
/* We continue here after waking up */
|
||||
fp = self->w_job.j_fp; /* Restore global data */
|
||||
err_code = self->w_job.j_err_code;
|
||||
worker_resume(self);
|
||||
assert(self->w_next == NULL);
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +404,9 @@ void worker_stop(struct worker_thread *worker)
|
|||
panic("reply storage consistency error"); /* Oh dear */
|
||||
}
|
||||
} else {
|
||||
worker->w_job.j_m_in.m_type = EIO;
|
||||
/* This shouldn't happen at all... */
|
||||
printf("VFS: stopping worker not blocked on any task?\n");
|
||||
util_stacktrace();
|
||||
}
|
||||
worker_wake(worker);
|
||||
}
|
||||
|
|
@ -338,12 +421,9 @@ void worker_stop_by_endpt(endpoint_t proc_e)
|
|||
|
||||
if (proc_e == NONE) return;
|
||||
|
||||
if (worker_waiting_for(&sys_worker, proc_e)) worker_stop(&sys_worker);
|
||||
if (worker_waiting_for(&dl_worker, proc_e)) worker_stop(&dl_worker);
|
||||
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
worker = &workers[i];
|
||||
if (worker_waiting_for(worker, proc_e))
|
||||
if (worker->w_fp != NULL && worker->w_task == proc_e)
|
||||
worker_stop(worker);
|
||||
}
|
||||
}
|
||||
|
|
@ -354,52 +434,36 @@ void worker_stop_by_endpt(endpoint_t proc_e)
|
|||
struct worker_thread *worker_get(thread_t worker_tid)
|
||||
{
|
||||
int i;
|
||||
struct worker_thread *worker;
|
||||
|
||||
worker = NULL;
|
||||
if (worker_tid == sys_worker.w_tid)
|
||||
worker = &sys_worker;
|
||||
else if (worker_tid == dl_worker.w_tid)
|
||||
worker = &dl_worker;
|
||||
else {
|
||||
for (i = 0; i < NR_WTHREADS; i++) {
|
||||
if (workers[i].w_tid == worker_tid) {
|
||||
worker = &workers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(worker);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_getjob *
|
||||
*===========================================================================*/
|
||||
struct job *worker_getjob(thread_t worker_tid)
|
||||
{
|
||||
struct worker_thread *worker;
|
||||
|
||||
if ((worker = worker_get(worker_tid)) != NULL)
|
||||
return(&worker->w_job);
|
||||
for (i = 0; i < NR_WTHREADS; i++)
|
||||
if (workers[i].w_tid == worker_tid)
|
||||
return(&workers[i]);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* worker_waiting_for *
|
||||
* worker_set_proc *
|
||||
*===========================================================================*/
|
||||
static int worker_waiting_for(struct worker_thread *worker, endpoint_t proc_e)
|
||||
void worker_set_proc(struct fproc *rfp)
|
||||
{
|
||||
ASSERTW(worker); /* Make sure we have a valid thread */
|
||||
/* Perform an incredibly ugly action that completely violates the threading
|
||||
* model: change the current working thread's process context to another
|
||||
* process. The caller is expected to hold the lock to both the calling and the
|
||||
* target process, and neither process is expected to continue regular
|
||||
* operation when done. This code is here *only* and *strictly* for the reboot
|
||||
* code, and *must not* be used for anything else.
|
||||
*/
|
||||
|
||||
if (worker->w_job.j_func != NULL) {
|
||||
if (worker->w_task != NONE)
|
||||
return(worker->w_task == proc_e);
|
||||
else if (worker->w_job.j_fp != NULL) {
|
||||
return(worker->w_job.j_fp->fp_task == proc_e);
|
||||
}
|
||||
}
|
||||
if (fp == rfp) return;
|
||||
|
||||
return(0);
|
||||
if (rfp->fp_worker != NULL)
|
||||
panic("worker_set_proc: target process not idle");
|
||||
|
||||
fp->fp_worker = NULL;
|
||||
|
||||
fp = rfp;
|
||||
|
||||
self->w_fp = rfp;
|
||||
fp->fp_worker = self;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#define T_SETOPT 13 /* set trace options */
|
||||
#define T_GETRANGE 14 /* get range of values */
|
||||
#define T_SETRANGE 15 /* set range of values */
|
||||
#define T_DUMPCORE 16 /* dumps the core for the process with the given pid */
|
||||
|
||||
#define T_READB_INS 100 /* Read a byte from the text segment of an
|
||||
* untraced process (only for root)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ COPTS.test68.c= -O0
|
|||
|
||||
# Some have special libraries
|
||||
LDADD.test59= -lmthread
|
||||
LDADD.test76= -lutil
|
||||
LDADD.test77= -lutil
|
||||
|
||||
# Some have an extra file
|
||||
OBJS.test57= test57loop.o
|
||||
|
|
@ -53,7 +55,7 @@ MINIX_TESTS= \
|
|||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
||||
61 64 65 66 67 68 69 70 71 72 73 74 75
|
||||
61 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
||||
|
||||
.if ${MACHINE_ARCH} == "i386"
|
||||
MINIX_TESTS+= \
|
||||
|
|
@ -111,7 +113,6 @@ OBJS.${o} += common.o
|
|||
|
||||
# LSC Make sure there is not leftover after a failed testrun
|
||||
clean: .PHONY .MAKE
|
||||
$(MAKE) -C select clean
|
||||
rm -rf DIR*
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
|||
4
test/run
4
test/run
|
|
@ -19,12 +19,12 @@ badones= # list of tests that failed
|
|||
|
||||
# Tests which require setuid
|
||||
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
|
||||
test69" # test73"
|
||||
test69 test76 test77" # test73"
|
||||
|
||||
alltests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||
61 62 63 64 65 66 67 68 69 70 71 72 75 \
|
||||
61 62 63 64 65 66 67 68 69 70 71 72 75 76 77 \
|
||||
sh1.sh sh2.sh interp.sh"
|
||||
tests_no=`expr 0`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
# Makefile for the tests
|
||||
|
||||
CC = exec cc
|
||||
CFLAGS = -Wall
|
||||
|
||||
PROG = speed test00 test01 test02 test03 test04_srv test04_cli test05_srv \
|
||||
test05_cli test06_srv test06_cli test07_srv test07_cli test08_srv \
|
||||
test08_cli test09 test10 test11 test12 test13a test13b test14
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
$(PROG):
|
||||
$(CC) $(CFLAGS) -o $@ $@.c -lutil
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROG)
|
||||
|
||||
speed: speed.c
|
||||
test00: test00.c
|
||||
test01: test01.c
|
||||
test02: test02.c
|
||||
test03: test03.c
|
||||
test04_cli: test04_cli.c
|
||||
test04_srv: test04_srv.c
|
||||
test05_cli: test05_cli.c
|
||||
test05_srv: test05_srv.c
|
||||
test06_cli: test06_cli.c
|
||||
test06_srv: test06_srv.c
|
||||
test07_cli: test07_cli.c
|
||||
test07_srv: test07_srv.c
|
||||
test08_cli: test08_cli.c
|
||||
test08_srv: test08_srv.c
|
||||
test09: test09.c
|
||||
test10: test10.c
|
||||
test11: test11.c
|
||||
test12: test12.c
|
||||
test13a: test13a.c
|
||||
test13b: test13b.c
|
||||
test14: test14.c
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Test name: speed.c
|
||||
*
|
||||
* Objetive: Test the time it takes for select to run.
|
||||
*
|
||||
* Description: This tests creates a number of udp connections and performs
|
||||
* a select call waiting on them for reading with timeout of 0.
|
||||
* This is done 10,000 thousands of times and then the average time it takes
|
||||
* is computed
|
||||
*
|
||||
* Jose M. Gomez
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/asynchio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <net/netlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define NUMBER 12
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *udp_device;
|
||||
int fd[NUMBER];
|
||||
fd_set fds_write;
|
||||
struct timeval timeout;
|
||||
time_t start_time, end_time;
|
||||
int i;
|
||||
|
||||
FD_ZERO(&fds_write);
|
||||
for (i = 0; i < NUMBER; i++) {
|
||||
fd[i] = open("/dev/tty", O_RDWR);
|
||||
if (fd[i] < 0) {
|
||||
fprintf(stderr, "Error opening tty %d\n", i);
|
||||
exit(-1);
|
||||
}
|
||||
FD_SET(fd[i], &fds_write);
|
||||
}
|
||||
|
||||
printf("Select will send 1 msg to terminal and %d to inet: \n", NUMBER);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
/* get initial time */
|
||||
start_time = time(NULL);
|
||||
for (i = 0; i < 32000; i++) {
|
||||
select(NUMBER + 4, NULL, &fds_write, NULL, &timeout);
|
||||
}
|
||||
/* get final time */
|
||||
end_time = time(NULL);
|
||||
printf("The select call took on average: %f\n", (float)(end_time - start_time) / 32000.0);
|
||||
for (i = 0; i < NUMBER; i++) {
|
||||
close(fd[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Test name: test00.c
|
||||
*
|
||||
* Objetive: The purpose of this test is to make sure that the bitmap
|
||||
* manipulation macros work without problems.
|
||||
*
|
||||
* Description: This tests first fills a fd_set bit by bit, and shows it, then
|
||||
* it clears the fd_set bit by bit as well.
|
||||
*
|
||||
* Jose M. Gomez
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
fd_set fds;
|
||||
int i,j;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
for (i=0;i<FD_SETSIZE;i++) {
|
||||
/* see if SET works */
|
||||
FD_SET(i, &fds);
|
||||
if(!FD_ISSET(i, &fds))
|
||||
return 1;
|
||||
}
|
||||
FD_ZERO(&fds);
|
||||
for (i=0;i<FD_SETSIZE;i++) {
|
||||
/* see if ZERO works */
|
||||
if(FD_ISSET(i, &fds))
|
||||
return 1;
|
||||
}
|
||||
for (i=0;i<FD_SETSIZE;i++) {
|
||||
FD_SET(i, &fds);
|
||||
for(j = 0; j <= i; j++)
|
||||
if(!FD_ISSET(j, &fds))
|
||||
return 1;
|
||||
for(; j < FD_SETSIZE; j++)
|
||||
if(FD_ISSET(j, &fds))
|
||||
return 1;
|
||||
}
|
||||
for (i=0;i<FD_SETSIZE;i++) {
|
||||
FD_CLR(i, &fds);
|
||||
for(j = 0; j <= i; j++)
|
||||
if(FD_ISSET(j, &fds))
|
||||
return 1;
|
||||
for(; j < FD_SETSIZE; j++)
|
||||
if(!FD_ISSET(j, &fds))
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Test name: test01.c
|
||||
*
|
||||
* Objective: The purpose of this test is to make sure that the timeout mechanisms
|
||||
* work without errors.
|
||||
*
|
||||
* Description: Executes a select as if it was a sleep and compares the time it
|
||||
* has been actually sleeping against the specified time in the select call.
|
||||
* Three cases are tested: first, a timeout specified in seconds, second, a timeout in
|
||||
* microseconds, and third, a timeout with more precision than seconds.
|
||||
*
|
||||
* Jose M. Gomez
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SECONDS 3
|
||||
#define USECONDS 3000000L
|
||||
|
||||
int main(void) {
|
||||
int r;
|
||||
time_t start, end; /* variables for timing */
|
||||
struct timeval timeout; /* timeout structure */
|
||||
|
||||
/* Set timeout for 3 seconds */
|
||||
timeout.tv_sec = SECONDS;
|
||||
timeout.tv_usec = 0;
|
||||
printf("Sleeping now for %d seconds...\n", SECONDS);
|
||||
/* Record time before starting */
|
||||
start = time(NULL);
|
||||
r = select(0, NULL, NULL, NULL, &timeout);
|
||||
printf("select return code: %d error: %s\n",
|
||||
r, strerror(errno));
|
||||
end = time(NULL);
|
||||
printf("For a timeout with select of %d seconds, it took %d actual seconds\n",
|
||||
SECONDS, end-start);
|
||||
|
||||
/* Set timeout for 3 seconds , but specified in microseconds */
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = USECONDS;
|
||||
printf("\n***************************\n");
|
||||
printf("Sleeping now for %ld microseconds...\n", USECONDS);
|
||||
/* Record time before starting */
|
||||
start = time(NULL);
|
||||
r = select(0, NULL, NULL, NULL, &timeout);
|
||||
printf("select return code: %d error: %s\n",
|
||||
r, strerror(errno));
|
||||
end = time(NULL);
|
||||
printf("For a timeout with select of %ld useconds, it took %d actual seconds\n",
|
||||
USECONDS, end-start);
|
||||
|
||||
/* Set timeout for 1.5 seconds, but specified in microseconds */
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = USECONDS/2;
|
||||
printf("\n***************************\n");
|
||||
printf("Sleeping now for %ld microseconds...\n", USECONDS/2);
|
||||
/* Record time before starting */
|
||||
start = time(NULL);
|
||||
r = select(0, NULL, NULL, NULL, &timeout);
|
||||
printf("select return code: %d error: %s\n",
|
||||
r, strerror(errno));
|
||||
end = time(NULL);
|
||||
printf("For a timeout with select of %ld useconds, it took %d actual seconds\n",
|
||||
USECONDS/2, end-start);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Test name: test02.c
|
||||
*
|
||||
* Objetive: The purpose of this test is to make sure that select works
|
||||
* when working with files.
|
||||
*
|
||||
* Description: This tests first creates six dummy files with different
|
||||
* modes and performs select calls on them evaluating the input and resulting
|
||||
* bitmaps.
|
||||
*
|
||||
* Jose M. Gomez
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
void dump_fdset(fd_set *set) {
|
||||
int i;
|
||||
for (i = 0; i < OPEN_MAX; i++)
|
||||
if (FD_ISSET(i, set))
|
||||
printf(" %d->1 ", i);
|
||||
else
|
||||
printf(" %d->0 ", i);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */
|
||||
fd_set fds_read, fds_write;
|
||||
int retval;
|
||||
|
||||
/* Creates the dummy files with different modes */
|
||||
fd1 = open("dummy1.txt", O_CREAT | O_RDONLY);
|
||||
if (fd1 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fd2 = open("dummy2.txt", O_CREAT | O_RDONLY);
|
||||
if (fd2 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fd3 = open("dummy3.txt", O_CREAT | O_WRONLY);
|
||||
if (fd3 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fd4 = open("dummy4.txt", O_CREAT | O_WRONLY);
|
||||
if (fd4 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fd5 = open("dummy5.txt", O_CREAT | O_RDWR);
|
||||
if (fd5 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fd6 = open("dummy6.txt", O_CREAT | O_RDWR);
|
||||
if (fd6 < 0) {
|
||||
perror("Error opening file");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Create the fd_set structures */
|
||||
FD_ZERO(&fds_read);
|
||||
FD_ZERO(&fds_write);
|
||||
FD_SET(fd1, &fds_read); /* fd1 => O_RDONLY */
|
||||
FD_SET(fd2, &fds_read); /* fd2 => O_RDONLY */
|
||||
FD_SET(fd3, &fds_write); /* fd3 => O_WRONLY */
|
||||
FD_SET(fd4, &fds_write); /* fd4 => O_WRONLY */
|
||||
FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */
|
||||
FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */
|
||||
FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */
|
||||
FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */
|
||||
|
||||
printf("* Dump INPUT fds_read:\n");
|
||||
dump_fdset(&fds_read);
|
||||
printf("* Dump INPUT fds_write:\n");
|
||||
dump_fdset(&fds_write);
|
||||
|
||||
retval=select(9, &fds_read, &fds_write, NULL, NULL);
|
||||
printf("\n***********************\n");
|
||||
printf("After select: \n");
|
||||
printf("Return value: %d\n", retval);
|
||||
printf("* Dump RESULTING fds_read:\n");
|
||||
dump_fdset(&fds_read);
|
||||
printf("* Dump RESULTING fds_write:\n");
|
||||
dump_fdset(&fds_write);
|
||||
/* close and delete dummy files */
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
close(fd3);
|
||||
close(fd4);
|
||||
close(fd5);
|
||||
close(fd6);
|
||||
unlink("dummy1.txt");
|
||||
unlink("dummy2.txt");
|
||||
unlink("dummy3.txt");
|
||||
unlink("dummy4.txt");
|
||||
unlink("dummy5.txt");
|
||||
unlink("dummy6.txt");
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user