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