Unused, remove.
This commit is contained in:
parent
5bd904f825
commit
532d3051b6
4 changed files with 0 additions and 389 deletions
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* server.c
|
||||
*
|
||||
* lwp (echo) connection handler server
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define SP_ACCEPT 3
|
||||
#define SP_READER 3
|
||||
|
||||
#include "lwp.h"
|
||||
|
||||
struct context {
|
||||
struct lwpProc *us;
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
readConn(argc, argv, ud)
|
||||
int argc;
|
||||
char **argv;
|
||||
void *ud;
|
||||
{
|
||||
struct context *ctx = (struct context *)ud;
|
||||
char buf[1024];
|
||||
int n;
|
||||
|
||||
while (1) {
|
||||
printf("sleeping\n");
|
||||
lwpSleepFd(ctx->fd, LWP_FD_READ);
|
||||
printf("waiting to read\n");
|
||||
if ((n = read(ctx->fd, buf, sizeof(buf))) <= 0)
|
||||
break;
|
||||
printf("got %d char\n", n);
|
||||
lwpSleepFd(ctx->fd, LWP_FD_WRITE);
|
||||
printf("waiting to write\n");
|
||||
if (write(ctx->fd, buf, n) < 0)
|
||||
break;
|
||||
printf("wrote %d char\n", n);
|
||||
}
|
||||
printf("process/fd %d exiting\n", ctx->fd);
|
||||
close(ctx->fd);
|
||||
lwpExit();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int
|
||||
acceptConn(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int s;
|
||||
int ns;
|
||||
int len;
|
||||
int maxfd;
|
||||
struct context *ctx;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s port\n", *argv);
|
||||
exit(-1);
|
||||
}
|
||||
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("inet socket");
|
||||
exit(-1);
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(atoi(argv[1]));
|
||||
sin.sin_addr.s_addr = 0;
|
||||
if (bind(s, &sin, sizeof(sin)) < 0) {
|
||||
perror("inet socket bind");
|
||||
exit(-1);
|
||||
}
|
||||
if (listen(s, LISTENMAXCONN) < 0) {
|
||||
perror("inet socket listen");
|
||||
exit(-1);
|
||||
}
|
||||
maxfd = getdtablesize() - 1;
|
||||
while (1) {
|
||||
lwpSleepFd(s, LWP_FD_READ);
|
||||
len = sizeof(sin);
|
||||
ns = accept(s, &sin, &len);
|
||||
if (ns < 0) {
|
||||
perror("accept");
|
||||
exit(-1);
|
||||
}
|
||||
if (ns == maxfd) {
|
||||
fprintf(stderr, "no more connections");
|
||||
close(ns);
|
||||
}
|
||||
printf("got connection from %s\n", inet_ntoa(sin.sin_addr));
|
||||
ctx = (struct context *)malloc(sizeof(*ctx));
|
||||
ctx->addr = sin;
|
||||
ctx->fd = ns;
|
||||
ctx->us = lwpCreate(SP_READER, readConn, 8192, 0, 0, ctx);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
lwpInitSystem(1);
|
||||
lwpCreate(SP_ACCEPT, acceptConn, 8192, argc, argv, 0);
|
||||
lwpReschedule();
|
||||
/*NOTREACHED*/
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* lwp.h -- prototypes and structures for lightweight processes
|
||||
* Copyright (C) 1991-3 Stephen Crane.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* author: Stephen Crane, (jsc@doc.ic.ac.uk), Department of Computing,
|
||||
* Imperial College of Science, Technology and Medicine, 180 Queen's
|
||||
* Gate, London SW7 2BZ, England.
|
||||
*/
|
||||
#ifndef _LWP_H
|
||||
#define _LWP_H
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* process control block. do *not* change the position of context */
|
||||
struct lwpProc {
|
||||
jmp_buf context; /* processor context area */
|
||||
void *sbtm; /* bottom of stack attached to it */
|
||||
int size; /* size of stack */
|
||||
void (*entry) (); /* entry point */
|
||||
int dead; /* whether the process can be rescheduled */
|
||||
int pri; /* which scheduling queue we're on */
|
||||
long runtime; /* time at which process is restarted */
|
||||
int fd; /* fd we're blocking on */
|
||||
int argc; /* initial arguments */
|
||||
char **argv;
|
||||
void *ud; /* user data */
|
||||
struct lwpProc *next;
|
||||
};
|
||||
|
||||
/* queue */
|
||||
struct lwpQueue {
|
||||
struct lwpProc *head;
|
||||
struct lwpProc *tail;
|
||||
};
|
||||
|
||||
/* semaphore */
|
||||
struct lwpSem {
|
||||
int count;
|
||||
struct lwpQueue q;
|
||||
};
|
||||
|
||||
#define LWP_FD_READ 0x1
|
||||
#define LWP_FD_WRITE 0x2
|
||||
|
||||
#define LWP_MAX_PRIO 8
|
||||
|
||||
struct lwpProc *lwpInitSystem(int);
|
||||
struct lwpProc *lwpCreate(int, void (*)(void *), int, int, char **, void *);
|
||||
void lwpExit(void);
|
||||
void lwpTerminate(struct lwpProc *);
|
||||
void lwpYield(void);
|
||||
void lwpSleepFd(int fd, int flags);
|
||||
void lwpSleepUntil(long until);
|
||||
void lwpWakeupFd(struct lwpProc *);
|
||||
void *lwpGetUD(struct lwpProc *);
|
||||
void lwpSetUD(struct lwpProc *, char *);
|
||||
int lwpSetPriority(int);
|
||||
void lwpReschedule();
|
||||
|
||||
struct lwpSem *lwpCreateSem(int);
|
||||
void lwpSignal(struct lwpSem *);
|
||||
void lwpWait(struct lwpSem *);
|
||||
void lwpSelect(int argc, char **argv);
|
||||
|
||||
extern struct lwpProc *LwpCurrent;
|
||||
|
||||
#endif /* _LWP_H */
|
Binary file not shown.
|
@ -1,189 +0,0 @@
|
|||
\documentstyle[tgrind, a4]{article}
|
||||
\title{The {\sc Rex} lightweight process library}
|
||||
\author{Stephen Crane\\ (jsc@doc.ic.ac.uk)\thanks{Thanks to Mark Little
|
||||
(m.c.little@ncl.ac.uk) for the Linux port}}
|
||||
\begin{document}
|
||||
\maketitle
|
||||
This document describes the interface to and the behaviour underlying
|
||||
my threads library for Rex.\footnote{Available as lwp.tar.gz by anonymous
|
||||
ftp from gummo.doc.ic.ac.uk:/rex. Rex (Esprit project 2080) was
|
||||
axed by Men in Suits.} It has been tested on Sun-3, Sun-4,
|
||||
Mips, 386-BSD and Linux systems. Counting semi-colons, it is
|
||||
260 lines long, including support for the different architectures (this
|
||||
figure includes variable- but not function-declarations).
|
||||
|
||||
A word from our sponsor:
|
||||
\begin{quote}
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but {\sc WITHOUT ANY WARRANTY}; without even the implied warranty of
|
||||
{\sc MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE}. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
\end{quote}
|
||||
|
||||
(Note that while this library is protected by the GNU copyleft, it is not
|
||||
supported by the Free Software Foundation.)
|
||||
|
||||
\section{Threads}
|
||||
Threads are prioritised and
|
||||
non-preemptive. Operations supported on threads are:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{struct} pcb *initlp (\K{int} priority)}}
|
||||
\L{\LB{}\Tab{8}{\K{struct} pcb *creatp (priority, entry, size, argc, argv, envp)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} readyp (\K{struct} pcb *p)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} yieldp (\K{void})}}
|
||||
\L{\LB{}\Tab{8}{\K{void} *getenvp (\K{struct} pcb *p)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} setenvp (\K{struct} pcb *p, \K{void} *)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} suicidep (\K{void})}}
|
||||
\L{\LB{}\Tab{8}{\K{void} destroyp (\K{struct} pcb *p)}}
|
||||
\end{tgrind}
|
||||
\begin{description}
|
||||
\item[initlp] initialises the threads runtime, creating a thread with
|
||||
specified priority for the invoker.
|
||||
\item[creatp] creates a new thread with specified {\em priority}, {\em
|
||||
entry} point, with a stack of {\em size}, {\em argc} arguments in {\em
|
||||
argv} and a user-defined environment pointer.
|
||||
\item[getenvp] returns the environment pointer associated with the given
|
||||
thread. If the thread is null, the current thread is assumed.
|
||||
\item[setenvp] reassigns the environment pointer associated with the
|
||||
given thread.
|
||||
\item[readyp] makes the specified thread ready to run, or the current
|
||||
thread if null.
|
||||
\item[yieldp] makes the current thread ready to run. If no thread of
|
||||
higher priority is runnable, the current thread will run.
|
||||
\item[suicidep] marks the invoking thread as dead. It will never be
|
||||
rescheduled.
|
||||
\item[destroyp] marks the specified thread as dead. It will be removed
|
||||
at the next reschedule. If it is currently running, it will be
|
||||
unaffected until the next reschedule.
|
||||
\end{description}
|
||||
|
||||
\section{Semaphores}
|
||||
For synchronisation, counting semaphores are provided. Available
|
||||
operations are:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{struct} sem *creats (\K{int} count)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} signals (\K{struct} sem *s)}}
|
||||
\L{\LB{}\Tab{8}{\K{void} waits (\K{struct} sem *s)}}
|
||||
\end{tgrind}
|
||||
\begin{description}
|
||||
\item[creats] allocates a new semaphore from the heap and initialises its
|
||||
count.
|
||||
\item[signals] increments the semaphore's count, makes a waiting process
|
||||
ready if there is one. If the readied process's priority is greater than
|
||||
that of the signaller, a reschedule is done.
|
||||
\item[waits] decrements the semaphore's count. If it becomes negative,
|
||||
the current process is suspended and a reschedule is done.
|
||||
\end{description}
|
||||
|
||||
\section{Signals}
|
||||
The library is concerned with two types of signal, {\sc sigio} and {\sc
|
||||
sigalrm}. These signals are normally blocked until the null process is
|
||||
scheduled. It uses {\tt sigpause()} to reenable them and wait for one
|
||||
to arrive. While awaiting a signal, the null process `runs' at maximum
|
||||
priority. Thus users will not be able to cause a reschedule from
|
||||
their handlers. When {\tt sigpause()} returns, the signal will have
|
||||
been handled and the null process drops back down to the lowest priority
|
||||
and yields to any thread which has been made ready to run from the
|
||||
user-level handler.
|
||||
|
||||
These semantics make the library rather unresponsive to signals in the
|
||||
presence of busy processes. If a more responsive system is required,
|
||||
the constant {\sc LCOUNT} may be changed. This value determines the
|
||||
number of times the {\tt reschedp ()} function must be called before
|
||||
signals are re-enabled. If given a value of {\tt 1}, it will affect
|
||||
context-switching time by about 50\%. Its default value is {\tt -1}.
|
||||
|
||||
\subsection{Input and output}
|
||||
Input and output present a problem to threads, because they require
|
||||
calls to the underlying {\sc Unix} system, which will block not only
|
||||
the invoking thread, but also all others in the process. Thus, in
|
||||
general, a thread must wait until the descriptor on which I/O is to
|
||||
be done becomes ready for the operation. This is done by trapping
|
||||
{\sc sigio}. Two routines are provided:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{int} sigioset (\K{int} fd, \K{void} (*han) (\K{void}
|
||||
*, \K{int}), \K{void} *ctx)}}
|
||||
\L{\LB{}\Tab{8}{\K{int} sigioclr (\K{int} fd)}}
|
||||
\end{tgrind}
|
||||
The general model adopted for processing {\sc sigio} is to install a
|
||||
{\em handler} routine for the I/O descriptor using {\em sigioset} and
|
||||
remove it using {\em sigioclr}. The user is responsible for setting up
|
||||
the device correctly to generate {\sc sigio}. When {\sc sigio} arrives
|
||||
for the descriptor, the handler will be called with a context pointer
|
||||
as its argument. (In C++, this context is the instance pointer of the
|
||||
invoking thread.)
|
||||
|
||||
\subsection{The timer}
|
||||
A single routine is provided to block the invoking thread for the
|
||||
specified time:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{void} delayp (\K{int} n)}}
|
||||
\end{tgrind}
|
||||
This routine blocks the invoker for {\em at least\/} the time specified.
|
||||
If this is zero, a reschedule is done. Delays are implemented as a
|
||||
delta queue, using {\sc sigalrm}. $n$ specifies a microsecond delay
|
||||
which is of limited utility in practice.
|
||||
|
||||
\section{Performance}
|
||||
\begin{figure}[htb]
|
||||
\begin{center}
|
||||
\begin{tabular}{||l|c|c|c||} \hline
|
||||
Arch & ctxsw & creat & comment \\ \hline
|
||||
sun3 & 308 & 778 & 3/240 \\ \hline
|
||||
386bsd & 186 & 464 & 486/33 \\ \hline
|
||||
sun4 & 96 & 436 & IPX \\ \hline
|
||||
sun4 & 59 & 212 & Sparc-10 \\ \hline
|
||||
linux & 56 & 382 & 486-DX2/50 \\ \hline
|
||||
mips & 17 & 85 & Decstation \\ \hline
|
||||
\end{tabular}
|
||||
\caption{Performance with architecture (times in microseconds).}
|
||||
\end{center}
|
||||
\end{figure}
|
||||
\begin{description}
|
||||
\item[sun3] has very lightweight process initialisation, compared with
|
||||
context switching.
|
||||
\item[sun4] has a high context switch time as a result of {\tt setjmp ()} and
|
||||
{\tt longjmp ()} implementations. Process initialisation is also relatively
|
||||
heavyweight: it requires two calls to {\tt setjmp ()} and one to {\tt longjmp
|
||||
()}.
|
||||
\item[mips] provides its own context switching in assembly language.
|
||||
\end{description}
|
||||
|
||||
\section{Porting to another architecture}
|
||||
Although the threads library is quite portable, a few guidelines should
|
||||
be observed when moving to a new architecture.
|
||||
|
||||
\begin{itemize}
|
||||
\item Create two new files for your architecture/kernel (e.g. {\tt sun4.c}
|
||||
and {\tt sun4.h}).
|
||||
The `.c' file should contain any routines which your version of {\sc Unix} is
|
||||
missing and a thread initialisation routine:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{void} initp (\K{struct} pcb *, \K{void} *)}}
|
||||
\end{tgrind}
|
||||
The `.h' file contains any machine-specific definitions.
|
||||
\item If {\tt setjmp ()} and {\tt longjmp ()} don't work on your machine
|
||||
(for example the {\sc Ultrix} {\tt longjmp ()} implementation checks that
|
||||
the frame being jumped to is an ancestor of the current one), you will
|
||||
have to write {\tt savep ()} and {\tt restorep ()} and put the following
|
||||
define into your machine-specific header file:
|
||||
\begin{tgrind}
|
||||
\L{\LB{}\Tab{8}{\K{\#define} OWN\_CONTEXT\_SWITCH}}
|
||||
\end{tgrind}
|
||||
\item Compile and run the three test programs: {\tt producer.c}, {\tt
|
||||
timer.c} and {\tt bm.c}.
|
||||
\item Add the name of the architecture to `config'.
|
||||
\item Send {\tt new-arch.[ch]}, any context diffs for the rest of the
|
||||
library and the output of {\tt bm.c} to {\tt jsc@doc.ic.ac.uk}. Also
|
||||
please let me know where you got the library from.
|
||||
\end{itemize}
|
||||
\end{document}
|
Loading…
Add table
Add a link
Reference in a new issue