Unused, remove.

This commit is contained in:
Markus Armbruster 2004-09-07 08:47:00 +00:00
parent 5bd904f825
commit 532d3051b6
4 changed files with 0 additions and 389 deletions

View file

@ -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*/
}

View file

@ -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.

View file

@ -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}