ref: 50d01b2e88713afb5a1276849b1ae75389263986
parent: a93a7fbe83b91c2275b84796a7e6b1fbb4e69656
author: halfwit <michaelmisch1985@gmail.com>
date: Mon Dec 1 20:29:02 EST 2025
Rebase over modern drawterm for libs and kernel
--- a/TODO
+++ b/TODO
@@ -2,8 +2,8 @@
- [ ] Some people probably want aan?
- [ ] gui-cocoa try to capture the windows we create so we can send mouse/keyboard to it, plist for launchd
+ - [ ] Use ScreenCaptureKit to get at the video/audio. Handle resizes the other direction
- [ ] gui-wl cannibalize the wayland shims
- - [ ] Use ScreenCaptureKit to get at the video/audio. Handle resizes the other direction
- [ ] define the gui interface
- [ ] Fully fledged note handling
- [x] up->parent integration into /proc
@@ -14,8 +14,8 @@
- [x] devcons - #c: /dev/cons
- [x] devenv - #e:/env
- [x] devfs - #U: needed, local files
- - [x] devip - #I: needed, networking
- - [ ] /net/icmpv6 and friends
+ - [-] devip - #I: needed, networking
+ - [ ] /net/icmpv6, /net/tls and friends
- [x] devlfd - #L: needed, local fd
- [x] devmnt - #M: needed, client shares
- [x] devpipe - #|: needed, for pipes
@@ -22,6 +22,6 @@
- [x] devroot - #/: needed, base of stack
- [x] devssl - #D: needed, ssl
- [x] devtls - #a: needed, tls
- - [ ] devproc - #p: needed, /proc, overlay any existing
+ - [-] devproc - #p: needed, /proc, overlay any existing
+ - [x] devcap - #¤: needed, caphash/capuse for factotum
- [x] devtab - # meta: needed add/remove any devices that we add/remove, from here as well
- - [ ] devcap - #¤: needed, caphash/capuse for factotum
--- a/include/draw.h
+++ b/include/draw.h
@@ -4,7 +4,7 @@
typedef struct Display Display;
typedef struct Font Font;
typedef struct Fontchar Fontchar;
-typedef struct Img Img;
+typedef struct Image Image;
typedef struct Mouse Mouse;
typedef struct Point Point;
typedef struct Rectangle Rectangle;
@@ -11,6 +11,7 @@
typedef struct RGB RGB;
typedef struct Screen Screen;
typedef struct Subfont Subfont;
+typedef long Warp[3][3];
extern int Rfmt(Fmt*);
extern int Pfmt(Fmt*);
@@ -155,14 +156,14 @@
Point max;
};
-typedef void (*Reffn)(Img*, Rectangle, void*);
+typedef void (*Reffn)(Image*, Rectangle, void*);
struct Screen
{Display *display; /* display holding data */
int id; /* id of system-held Screen */
- Img *image; /* unused; for reference only */
- Img *fill; /* color to paint behind windows */
+ Image *image; /* unused; for reference only */
+ Image *fill; /* color to paint behind windows */
};
struct Display
@@ -180,25 +181,25 @@
char *windir;
char oldlabel[64];
ulong dataqid;
- Img *white;
- Img *black;
- Img *opaque;
- Img *transparent;
- Img *image;
+ Image *white;
+ Image *black;
+ Image *opaque;
+ Image *transparent;
+ Image *image;
uchar *buf;
int bufsize;
uchar *bufp;
Font *defaultfont;
Subfont *defaultsubfont;
- Img *windows;
- Img *screenimage;
+ Image *windows;
+ Image *screenimage;
int _isnewdisplay;
};
-struct Img
+struct Image
{Display *display; /* display holding data */
- int id; /* id of system-held Img */
+ int id; /* id of system-held Image */
Rectangle r; /* rectangle in data area, local coords */
Rectangle clipr; /* clipping region */
int depth; /* number of bits per pixel */
@@ -205,7 +206,7 @@
ulong chan;
int repl; /* flag: data replicates to tile clipr */
Screen *screen; /* 0 if not a window */
- Img *next; /* next in list of windows */
+ Image *next; /* next in list of windows */
};
struct RGB
@@ -224,7 +225,7 @@
* p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
* color, f->bits, Pt(i->x, i->top));
* p.x += i->width;
- * to draw characters in the specified color (itself an Img) in Img b.
+ * to draw characters in the specified color (itself an Image) in Image b.
*/
struct Fontchar
@@ -243,7 +244,7 @@
uchar height; /* height of image */
char ascent; /* top of image to baseline */
Fontchar *info; /* n+1 character descriptors */
- Img *bits; /* of font */
+ Image *bits; /* of font */
int ref;
};
@@ -304,7 +305,7 @@
Cacheinfo *cache;
Cachesubf *subf;
Cachefont **sub; /* as read from file */
- Img *cacheimage;
+ Image *cacheimage;
};
#define Dx(r) ((r).max.x-(r).min.x)
@@ -311,33 +312,33 @@
#define Dy(r) ((r).max.y-(r).min.y)
/*
- * Img management
+ * Image management
*/
-extern Img* _allocimage(Img*, Display*, Rectangle, ulong, int, ulong, int, int);
-extern Img* allocimage(Display*, Rectangle, ulong, int, ulong);
+extern Image* _allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int);
+extern Image* allocimage(Display*, Rectangle, ulong, int, ulong);
extern uchar* bufimage(Display*, int);
extern int bytesperline(Rectangle, int);
extern void closedisplay(Display*);
extern void drawerror(Display*, char*);
extern int flushimage(Display*, int);
-extern int freeimage(Img*);
-extern int _freeimage1(Img*);
+extern int freeimage(Image*);
+extern int _freeimage1(Image*);
extern int geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
extern int initdraw(void(*)(Display*, char*), char*, char*);
extern int newwindow(char*);
extern Display* initdisplay(char*, char*, void(*)(Display*, char*));
-extern int loadimage(Img*, Rectangle, uchar*, int);
-extern int cloadimage(Img*, Rectangle, uchar*, int);
+extern int loadimage(Image*, Rectangle, uchar*, int);
+extern int cloadimage(Image*, Rectangle, uchar*, int);
extern int getwindow(Display*, int);
-extern int gengetwindow(Display*, char*, Img**, Screen**, int);
-extern Img* readimage(Display*, int, int);
-extern Img* creadimage(Display*, int, int);
-extern int unloadimage(Img*, Rectangle, uchar*, int);
+extern int gengetwindow(Display*, char*, Image**, Screen**, int);
+extern Image* readimage(Display*, int, int);
+extern Image* creadimage(Display*, int, int);
+extern int unloadimage(Image*, Rectangle, uchar*, int);
extern int wordsperline(Rectangle, int);
-extern int writeimage(int, Img*, int);
-extern Img* namedimage(Display*, char*);
-extern int nameimage(Img*, char*, int);
-extern Img* allocimagemix(Display*, ulong, ulong);
+extern int writeimage(int, Image*, int);
+extern Image* namedimage(Display*, char*);
+extern int nameimage(Image*, char*, int);
+extern Image* allocimagemix(Display*, ulong, ulong);
/*
* Colors
@@ -349,16 +350,16 @@
/*
* Windows
*/
-extern Screen* allocscreen(Img*, Img*, int);
-extern Img* _allocwindow(Img*, Screen*, Rectangle, int, ulong);
-extern Img* allocwindow(Screen*, Rectangle, int, ulong);
-extern void bottomnwindows(Img**, int);
-extern void bottomwindow(Img*);
+extern Screen* allocscreen(Image*, Image*, int);
+extern Image* _allocwindow(Image*, Screen*, Rectangle, int, ulong);
+extern Image* allocwindow(Screen*, Rectangle, int, ulong);
+extern void bottomnwindows(Image**, int);
+extern void bottomwindow(Image*);
extern int freescreen(Screen*);
extern Screen* publicscreen(Display*, int, ulong);
-extern void topnwindows(Img**, int);
-extern void topwindow(Img*);
-extern int originwindow(Img*, Point, Point);
+extern void topnwindows(Image**, int);
+extern void topwindow(Image*);
+extern int originwindow(Image*, Point, Point);
/*
* Geometry
@@ -381,7 +382,7 @@
extern void combinerect(Rectangle*, Rectangle);
extern int rectclip(Rectangle*, Rectangle);
extern int ptinrect(Point, Rectangle);
-extern void replclipr(Img*, int, Rectangle);
+extern void replclipr(Image*, int, Rectangle);
extern int drawreplxy(int, int, int); /* used to be drawsetxy */
extern Point drawrepl(Rectangle, Point);
extern int rgb2cmap(int, int, int);
@@ -394,53 +395,55 @@
/*
* Graphics
*/
-extern void draw(Img*, Rectangle, Img*, Img*, Point);
-extern void drawop(Img*, Rectangle, Img*, Img*, Point, Drawop);
-extern void gendraw(Img*, Rectangle, Img*, Point, Img*, Point);
-extern void gendrawop(Img*, Rectangle, Img*, Point, Img*, Point, Drawop);
-extern void line(Img*, Point, Point, int, int, int, Img*, Point);
-extern void lineop(Img*, Point, Point, int, int, int, Img*, Point, Drawop);
-extern void poly(Img*, Point*, int, int, int, int, Img*, Point);
-extern void polyop(Img*, Point*, int, int, int, int, Img*, Point, Drawop);
-extern void fillpoly(Img*, Point*, int, int, Img*, Point);
-extern void fillpolyop(Img*, Point*, int, int, Img*, Point, Drawop);
-extern Point string(Img*, Point, Img*, Point, Font*, char*);
-extern Point stringop(Img*, Point, Img*, Point, Font*, char*, Drawop);
-extern Point stringn(Img*, Point, Img*, Point, Font*, char*, int);
-extern Point stringnop(Img*, Point, Img*, Point, Font*, char*, int, Drawop);
-extern Point runestring(Img*, Point, Img*, Point, Font*, Rune*);
-extern Point runestringop(Img*, Point, Img*, Point, Font*, Rune*, Drawop);
-extern Point runestringn(Img*, Point, Img*, Point, Font*, Rune*, int);
-extern Point runestringnop(Img*, Point, Img*, Point, Font*, Rune*, int, Drawop);
-extern Point stringbg(Img*, Point, Img*, Point, Font*, char*, Img*, Point);
-extern Point stringbgop(Img*, Point, Img*, Point, Font*, char*, Img*, Point, Drawop);
-extern Point stringnbg(Img*, Point, Img*, Point, Font*, char*, int, Img*, Point);
-extern Point stringnbgop(Img*, Point, Img*, Point, Font*, char*, int, Img*, Point, Drawop);
-extern Point runestringbg(Img*, Point, Img*, Point, Font*, Rune*, Img*, Point);
-extern Point runestringbgop(Img*, Point, Img*, Point, Font*, Rune*, Img*, Point, Drawop);
-extern Point runestringnbg(Img*, Point, Img*, Point, Font*, Rune*, int, Img*, Point);
-extern Point runestringnbgop(Img*, Point, Img*, Point, Font*, Rune*, int, Img*, Point, Drawop);
-extern Point _string(Img*, Point, Img*, Point, Font*, char*, Rune*, int, Rectangle, Img*, Point, Drawop);
-extern Point stringsubfont(Img*, Point, Img*, Subfont*, char*);
-extern int bezier(Img*, Point, Point, Point, Point, int, int, int, Img*, Point);
-extern int bezierop(Img*, Point, Point, Point, Point, int, int, int, Img*, Point, Drawop);
-extern int bezspline(Img*, Point*, int, int, int, int, Img*, Point);
-extern int bezsplineop(Img*, Point*, int, int, int, int, Img*, Point, Drawop);
+extern void draw(Image*, Rectangle, Image*, Image*, Point);
+extern void drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
+extern void gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
+extern void gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
+extern void line(Image*, Point, Point, int, int, int, Image*, Point);
+extern void lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
+extern void poly(Image*, Point*, int, int, int, int, Image*, Point);
+extern void polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
+extern void fillpoly(Image*, Point*, int, int, Image*, Point);
+extern void fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern Point string(Image*, Point, Image*, Point, Font*, char*);
+extern Point stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
+extern Point stringn(Image*, Point, Image*, Point, Font*, char*, int);
+extern Point stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
+extern Point runestring(Image*, Point, Image*, Point, Font*, Rune*);
+extern Point runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
+extern Point runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
+extern Point runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
+extern Point stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
+extern Point stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
+extern Point stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
+extern Point stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
+extern Point runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
+extern Point runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
+extern Point runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
+extern Point runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
+extern Point _string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
+extern Point stringsubfont(Image*, Point, Image*, Subfont*, char*);
+extern int bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
+extern int bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
+extern int bezspline(Image*, Point*, int, int, int, int, Image*, Point);
+extern int bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
extern int bezsplinepts(Point*, int, Point**);
-extern int fillbezier(Img*, Point, Point, Point, Point, int, Img*, Point);
-extern int fillbezierop(Img*, Point, Point, Point, Point, int, Img*, Point, Drawop);
-extern int fillbezspline(Img*, Point*, int, int, Img*, Point);
-extern int fillbezsplineop(Img*, Point*, int, int, Img*, Point, Drawop);
-extern void ellipse(Img*, Point, int, int, int, Img*, Point);
-extern void ellipseop(Img*, Point, int, int, int, Img*, Point, Drawop);
-extern void fillellipse(Img*, Point, int, int, Img*, Point);
-extern void fillellipseop(Img*, Point, int, int, Img*, Point, Drawop);
-extern void arc(Img*, Point, int, int, int, Img*, Point, int, int);
-extern void arcop(Img*, Point, int, int, int, Img*, Point, int, int, Drawop);
-extern void fillarc(Img*, Point, int, int, Img*, Point, int, int);
-extern void fillarcop(Img*, Point, int, int, Img*, Point, int, int, Drawop);
-extern void border(Img*, Rectangle, int, Img*, Point);
-extern void borderop(Img*, Rectangle, int, Img*, Point, Drawop);
+extern int fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
+extern int fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
+extern int fillbezspline(Image*, Point*, int, int, Image*, Point);
+extern int fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern void ellipse(Image*, Point, int, int, int, Image*, Point);
+extern void ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
+extern void fillellipse(Image*, Point, int, int, Image*, Point);
+extern void fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
+extern void arc(Image*, Point, int, int, int, Image*, Point, int, int);
+extern void arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
+extern void fillarc(Image*, Point, int, int, Image*, Point, int, int);
+extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
+extern void border(Image*, Rectangle, int, Image*, Point);
+extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+extern void mkwarp(Warp, double[3][3]);
+extern void affinewarp(Image*, Rectangle, Image*, Point, Warp, int);
/*
* Font management
@@ -451,13 +454,13 @@
extern Font* mkfont(Subfont*, Rune);
extern int cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
extern void agefont(Font*);
-extern Subfont* allocsubfont(char*, int, int, int, Fontchar*, Img*);
+extern Subfont* allocsubfont(char*, int, int, int, Fontchar*, Image*);
extern Subfont* lookupsubfont(Display*, char*);
extern void installsubfont(char*, Subfont*);
extern void uninstallsubfont(Subfont*);
extern void freesubfont(Subfont*);
extern Subfont* readsubfont(Display*, char*, int, int);
-extern Subfont* readsubfonti(Display*, char*, int, Img*, int);
+extern Subfont* readsubfonti(Display*, char*, int, Image*, int);
extern int writesubfont(int, Subfont*);
extern void _unpackinfo(Fontchar*, uchar*, int);
extern Point stringsize(Font*, char*);
@@ -487,7 +490,7 @@
*/
extern Display *display;
extern Font *font;
-// extern Img *screen;
+// extern Image *screen;
extern Screen *_screen;
extern int _cursorfd;
extern void _setdrawop(Display*, Drawop);
--- a/include/lib.h
+++ b/include/lib.h
@@ -350,8 +350,6 @@
extern double __Inf(int);
extern int __isInf(double, int);
-extern int (*fmtdoquote)(int);
-
/*
* Time-of-day
*/
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -35,7 +35,6 @@
postnote.$O\
procinit.$O\
notify.$O\
- rendez.$O\
rwlock.$O\
seg.$O\
sema.$O\
--- a/kern/chan.c
+++ b/kern/chan.c
@@ -506,9 +506,9 @@
* - the mhead in chans returned from createdir:
* used in the open/create race protect, which is gone.
*
- * The RWlock in the Mhead protects the mount list it contains.
+ * The RWLock in the Mhead protects the mount list it contains.
* The mount list is deleted in cunmount() and closepgrp().
- * The RWlock ensures that nothing is using the mount list at that time.
+ * The RWLock ensures that nothing is using the mount list at that time.
*
* It is okay to replace c->mh with whatever you want as
* long as you are sure you have a unique reference to it.
@@ -830,7 +830,6 @@
* Either walks all the way or not at all. No partial results in *cp.
* *nerror is the number of names to display in an error message.
*/
-static char Edoesnotexist[] = "does not exist";
int
walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
{@@ -946,7 +945,7 @@
if(wq->nqid == 0 || (wq->qid[wq->nqid-1].type&QTDIR) != 0){if(nerror)
*nerror = nhave+wq->nqid+1;
- kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
+ kstrcpy(up->errstr, Enonexist, ERRMAX);
}else{if(nerror)
*nerror = nhave+wq->nqid;
@@ -1084,7 +1083,7 @@
}
}
-static void
+void
namelenerror(char *aname, int len, char *err)
{char *ename, *name, *next;
@@ -1127,16 +1126,10 @@
snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
utfnlen(name, ename-name), name);
}
- snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
+ snprint(up->errstr, ERRMAX, "%s: %#q", err, up->genbuf);
nexterror();
}
-void
-nameerror(char *name, char *err)
-{- namelenerror(name, strlen(name), err);
-}
-
/*
* Turn a name into a channel.
* &name[0] is known to be a valid address. It may be a kernel address.
@@ -1158,7 +1151,7 @@
{int len, n, t, nomount;
Chan *c;
- Chan */*volatile*/ cnew;
+ Chan * cnew;
Path */*volatile*/ path;
Elemlist e;
Rune r;
@@ -1189,7 +1182,6 @@
case '#':
nomount = 1;
- up->genbuf[0] = '\0';
n = 0;
while(*name != '\0' && (*name != '/' || n < 2)){if(n >= sizeof(up->genbuf)-1)
@@ -1212,7 +1204,7 @@
n = chartorune(&r, up->genbuf+1)+1;
if(up->pgrp->noattach && utfrune("|decp", r)==nil)error(Enoattach);
- t = devno(r, 1);
+ t = devno(r);
if(t == -1)
error(Ebadsharp);
c = devtab[t]->attach(up->genbuf+n);
@@ -1285,6 +1277,14 @@
error("cannot exec directory"); switch(amode){+ case Aunmount:
+ /*
+ * When unmounting, the channel must be opend when not a directory
+ * in order to get the real chan from something like /srv/cs or /fd/0.
+ */
+ if((c->qid.type&QTDIR) == 0)
+ goto Open;
+ /* wet floor */
case Abind:
/* no need to maintain path - cannot dotdot an Abind */
m = nil;
@@ -1337,6 +1337,7 @@
case Aopen:
case Acreate:
+ case Aunmount:
/* only save the mount head if it's a multiple element union */
if(m != nil) {rlock(&m->lock);
@@ -1471,6 +1472,7 @@
/* create failed */
+ cclose(cnew);
putmhead(m);
if(omode & OEXCL)
nexterror();
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -30,7 +30,7 @@
typedef struct Ref Ref;
typedef struct Rendez Rendez;
typedef struct Rgrp Rgrp;
-typedef struct RWlock RWlock;
+typedef struct RWLock RWLock;
typedef struct Segment Segment;
typedef struct Ureg Ureg;
typedef struct Waitq Waitq;
@@ -69,7 +69,7 @@
Proc *p;
};
-struct RWlock /* changed from kernel */
+struct RWLock /* changed from kernel */
{int readers;
Lock lk;
@@ -101,6 +101,7 @@
Amount, /* to be mounted or mounted upon */
Acreate, /* is to be created */
Aremove, /* will be removed by caller */
+ Aunmount, /* unmount arg */
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
@@ -260,7 +261,7 @@
struct Mhead
{Ref ref;
- RWlock lock;
+ RWLock lock;
Chan* from; /* channel mounted upon */
Mount* mount; /* what's mounted upon it */
Mhead* hash; /* Hash chain */
@@ -311,7 +312,7 @@
Ref ref; /* also used as a lock when mounting */
int noattach;
QLock debug; /* single access via devproc.c */
- RWlock ns; /* Namespace n read/one write lock */
+ RWLock ns; /* Namespace n read/one write lock */
Mhead *mnthash[MNTHASH];
u64int notallowed[4];
};
@@ -352,7 +353,7 @@
struct Egrp
{Ref ref;
- RWlock lk;
+ RWLock lk;
Evalue **ent;
int nent;
int ment;
@@ -376,7 +377,7 @@
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
int exceed; /* debugging */
- RWlock lk;
+ RWLock lk;
};
enum
@@ -433,7 +434,7 @@
struct Fd
{- RWlock rw;
+ RWLock rw;
Ref ref;
uint *fds;
int nfds;
@@ -457,7 +458,7 @@
Lock rlock; /* sync sleep/wakeup with postnote */
Lock exl; /* rfork, etc */
Rendez *r; /* rendezvous point slept on */
- Rendez rsleep; /* place for syssleep/debug */
+ Rendez sleep; /* place for syssleep/debug */
int notepending; /* note issued but not acted on */
int kp; /* true if a kernel process */
@@ -522,7 +523,7 @@
struct Segment {Ref ref;
int flags;
- RWlock rw; /* lock for SEGFLLOCK segments */
+ RWLock rw; /* lock for SEGFLLOCK segments */
u32int start, size;
void *data;
Ref *dref;
@@ -539,7 +540,6 @@
READSTR = 1000, /* temporary buffer size for device reads */
};
-extern int cpuserver;
extern Dev* devtab[];
extern char *eve;
extern char hostdomain[];
--- a/kern/data.c
+++ b/kern/data.c
@@ -4,6 +4,7 @@
#include "fns.h"
#include "error.h"
+// TODO: Actually get this information
Conf conf =
{1, /* processors */
@@ -13,5 +14,4 @@
char *eve = "eve";
ulong kerndate;
-int cpuserver;
char hostdomain[] = "9front";
--- a/kern/dev.c
+++ b/kern/dev.c
@@ -15,7 +15,7 @@
}
int
-devno(int c, int user)
+devno(int c)
{int i;
@@ -23,9 +23,6 @@
if(devtab[i]->dc == c)
return i;
}
- if(user == 0)
- panic("devno %C %#ux", c, c);-
return -1;
}
@@ -130,7 +127,7 @@
c = newchan();
mkqid(&c->qid, 0, 0, QTDIR);
- c->type = devno(tc, 0);
+ c->type = devno(tc);
if(spec == nil)
spec = "";
n = 1+UTFmax+strlen(spec)+1;
--- a/kern/devcons.c
+++ b/kern/devcons.c
@@ -6,6 +6,8 @@
#include "keyboard.h"
+#include <authsrv.h>
+
#undef write
#undef read
@@ -180,6 +182,14 @@
return n;
}
+static void
+hang(void)
+{+ Rendez z = {0};+ while(up == nil) osyield();
+ for(;;) sleep(&z, return0, 0);
+}
+
void
panic(char *fmt, ...)
{@@ -189,8 +199,7 @@
kprintoq = nil; /* don't try to write to /dev/kprint */
- if(panicking++)
- for(;;) osyield();
+ if(panicking++) hang();
splhi();
strcpy(buf, "panic: ");
va_start(arg, fmt);
@@ -199,8 +208,7 @@
buf[n] = '\n';
spllo();
putstrn(buf, n+1);
- while(screenputs != 0)
- osyield();
+ if(screenputs) hang();
setterm(0);
exit(1);
}
@@ -363,7 +371,7 @@
"cons", {Qcons}, 0, 0660, "consctl", {Qconsctl}, 0, 0220, "drivers", {Qdrivers}, 0, 0444,- "hostdomain", {Qhostdomain}, 48, 0664,+ "hostdomain", {Qhostdomain}, DOMLEN, 0664, "hostowner", {Qhostowner}, 0, 0664, "kmesg", {Qkmesg}, 0, 0440, "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,--- a/kern/devfs-posix.c
+++ b/kern/devfs-posix.c
@@ -231,7 +231,12 @@
}
}
else {- int m = fsomode(omode & 3) | O_CREAT | O_TRUNC;
+ int m = omode & 3;
+ /*
+ * POSIX specifies that O_TRUNC with O_RDONLY is undefined.
+ * OpenBSD chooses to return an error.
+ */
+ m = fsomode(m == OREAD ? ORDWR : m) | O_CREAT | O_TRUNC;
if(mode & OEXCL)
m |= O_EXCL;
if((fd = open(path, m, uif->mode & perm & 0777)) < 0)
--- a/kern/devip.c
+++ b/kern/devip.c
@@ -40,6 +40,8 @@
#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
#define ipzero(x) memset(x, 0, IPaddrlen)
+#define DEVDOT -2
+
typedef struct Proto Proto;
typedef struct Conv Conv;
struct Conv
@@ -55,6 +57,7 @@
uchar raddr[IPaddrlen];
ushort rport;
int restricted;
+ ulong ctime;
char cerr[KNAMELEN];
Proto* p;
};
@@ -94,13 +97,13 @@
return -1;
case Qctl:
devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
- return 1;
+ goto done;
case Qdata:
devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
- return 1;
+ goto done;
case Qlisten:
devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
- return 1;
+ goto done;
case Qlocal:
p = "local";
break;
@@ -112,6 +115,8 @@
break;
}
devdir(c, q, p, 0, cv->owner, 0444, dp);
+done:
+ dp->mtime = cv->ctime;
return 1;
}
@@ -159,7 +164,7 @@
switch(TYPE(c->qid)) {case Qtopdir:
- if(s == DEVDOTDOT){+ if(s == DEVDOTDOT || s == DEVDOT){mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
devdir(c, q, up->genbuf, 0, network, 0555, dp);
@@ -166,6 +171,7 @@
return 1;
}
if(s < np) {+ Protodir:
mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
devdir(c, q, proto[s].name, 0, network, 0555, dp);
return 1;
@@ -181,11 +187,17 @@
devdir(c, q, up->genbuf, 0, network, 0555, dp);
return 1;
}
+ if(s == DEVDOT){+ s = PROTO(c->qid);
+ goto Protodir;
+ }
if(s < proto[PROTO(c->qid)].nc) {+ Convdir:
cv = proto[PROTO(c->qid)].conv[s];
snprint(up->genbuf, sizeof up->genbuf, "%d", s);
mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
+ dp->mtime = cv->ctime;
return 1;
}
s -= proto[PROTO(c->qid)].nc;
@@ -199,6 +211,10 @@
devdir(c, q, proto[s].name, 0, network, 0555, dp);
return 1;
}
+ if(s == DEVDOT){+ s = CONV(c->qid);
+ goto Convdir;
+ }
return ip3gen(c, s+Qconvbase, dp);
case Qctl:
case Qdata:
@@ -269,6 +285,16 @@
int
ipstat(Chan *c, uchar *dp, int n)
{+ Dir d;
+
+ if(c->qid.type == QTDIR){+ ipgen(c, nil, nil, 0, DEVDOT, &d);
+ n = convD2M(&d, dp, n);
+ if(n == 0)
+ error(Ebadarg);
+ return n;
+ }
+
return devstat(c, dp, n, 0, 0, ipgen);
}
@@ -631,6 +657,7 @@
c->lport = 0;
c->rport = 0;
c->sfd = nfd;
+ c->ctime = seconds();
unlock(&c->r.lk);
unlock(&p->l);
--- a/kern/devlfd-posix.c
+++ b/kern/devlfd-posix.c
@@ -14,7 +14,7 @@
Chan *c;
c = newchan();
- c->type = devno('L', 0);+ c->type = devno('L');c->aux = fd;
c->path = newpath("/fd");c->mode = ORDWR;
--- a/kern/devlfd-win32.c
+++ b/kern/devlfd-win32.c
@@ -11,7 +11,7 @@
Chan *c;
c = newchan();
- c->type = devno('L', 0);+ c->type = devno('L');c->aux = fd;
c->path = newpath("/fd");c->mode = ORDWR;
--- a/kern/devmnt.c
+++ b/kern/devmnt.c
@@ -744,7 +744,7 @@
}
lock(&m->lk);
- r->z = &up->rsleep;
+ r->z = &up->sleep;
r->m = m;
r->list = m->queue;
m->queue = r;
@@ -821,8 +821,8 @@
/* read in the rest of the message, avoid ridiculous (for now) message sizes */
len = GBIT32(nb->rp);
- if(len > m->msize){- qdiscard(m->q, qlen(m->q));
+ if(len < BIT32SZ+BIT8SZ+BIT16SZ || len > m->msize){+ qflush(m->q);
return -1;
}
if(doread(m, len) < 0)
--- a/kern/exportfs.c
+++ /dev/null
@@ -1,821 +1,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-typedef struct Fid Fid;
-typedef struct Export Export;
-typedef struct Exq Exq;
-
-#define nil ((void*)0)
-
-enum
-{- Nfidhash = 1,
- MAXRPC = MAXMSG+MAXFDATA,
- MAXDIRREAD = (MAXFDATA/DIRLEN)*DIRLEN
-};
-
-struct Export
-{- Ref r;
- Exq* work;
- Lock fidlock;
- Fid* fid[Nfidhash];
- Chan* root;
- Chan* io;
- Pgrp* pgrp;
- int npart;
- char part[MAXRPC];
-};
-
-struct Fid
-{- Fid* next;
- Fid** last;
- Chan* chan;
- long offset;
- int fid;
- int ref; /* fcalls using the fid; locked by Export.Lock */
- int attached; /* fid attached or cloned but not clunked */
-};
-
-struct Exq
-{- Lock lk;
- int nointr;
- int noresponse; /* don't respond to this one */
- Exq* next;
- int shut; /* has been noted for shutdown */
- Export* export;
- void* slave;
- Fcall rpc;
- char buf[MAXRPC];
-};
-
-struct
-{- Lock l;
- Qlock qwait;
- Rendez rwait;
- Exq *head; /* work waiting for a slave */
- Exq *tail;
-}exq;
-
-static void exshutdown(Export*);
-static void exflush(Export*, int, int);
-static void exslave(void*);
-static void exfree(Export*);
-static void exportproc(Export*);
-
-static char* Exauth(Export*, Fcall*);
-static char* Exattach(Export*, Fcall*);
-static char* Exclunk(Export*, Fcall*);
-static char* Excreate(Export*, Fcall*);
-static char* Exopen(Export*, Fcall*);
-static char* Exread(Export*, Fcall*);
-static char* Exremove(Export*, Fcall*);
-static char* Exstat(Export*, Fcall*);
-static char* Exwalk(Export*, Fcall*);
-static char* Exwrite(Export*, Fcall*);
-static char* Exwstat(Export*, Fcall*);
-static char* Exversion(Export*, Fcall*);
-
-static char *(*fcalls[Tmax])(Export*, Fcall*);
-
-static char Enofid[] = "no such fid";
-static char Eseekdir[] = "can't seek on a directory";
-static char Ereaddir[] = "unaligned read of a directory";
-static int exdebug = 0;
-
-int
-sysexport(int fd)
-{- Chan *c;
- Export *fs;
-
- if(waserror())
- return -1;
-
- c = fdtochan(fd, ORDWR, 1, 1);
- poperror();
- c->flag |= CMSG;
-
- fs = mallocz(sizeof(Export));
- fs->r.ref = 1;
- fs->pgrp = up->pgrp;
- refinc(&fs->pgrp->r);
- refinc(&up->slash->r);
- fs->root = up->slash;
- refinc(&fs->root->r);
- fs->root = domount(fs->root);
- fs->io = c;
-
- exportproc(fs);
-
- return 0;
-}
-
-static void
-exportinit(void)
-{- lock(&exq.l);
- if(fcalls[Tversion] != nil) {- unlock(&exq.l);
- return;
- }
-
- fmtinstall('F', fcallfmt);- fmtinstall('D', dirfmt);- fmtinstall('M', dirmodefmt);- fcalls[Tversion] = Exversion;
- fcalls[Tauth] = Exauth;
- fcalls[Tattach] = Exattach;
- fcalls[Twalk] = Exwalk;
- fcalls[Topen] = Exopen;
- fcalls[Tcreate] = Excreate;
- fcalls[Tread] = Exread;
- fcalls[Twrite] = Exwrite;
- fcalls[Tclunk] = Exclunk;
- fcalls[Tremove] = Exremove;
- fcalls[Tstat] = Exstat;
- fcalls[Twstat] = Exwstat;
- unlock(&exq.l);
-}
-
-void
-exportproc(Export *fs)
-{- Exq *q;
- char *buf;
- int n, cn, len;
-
- exportinit();
-
- for(;;){- q = mallocz(sizeof(Exq));
- if(q == 0)
- panic("no memory");-
- q->rpc.data = q->buf + MAXMSG;
-
- buf = q->buf;
- len = MAXRPC;
- if(fs->npart) {- memmove(buf, fs->part, fs->npart);
- buf += fs->npart;
- len -= fs->npart;
- goto chk;
- }
- for(;;) {- if(waserror())
- goto bad;
-
- n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0);
- poperror();
-
- if(n <= 0)
- goto bad;
-
- buf += n;
- len -= n;
- chk:
- n = buf - q->buf;
-
- /* convM2S returns size of correctly decoded message */
- cn = convM2S(q->buf, &q->rpc, n);
- if(cn < 0){- iprint("bad message type in devmnt\n");- goto bad;
- }
- if(cn > 0) {- n -= cn;
- if(n < 0){- iprint("negative size in devmnt");- goto bad;
- }
- fs->npart = n;
- if(n != 0)
- memmove(fs->part, q->buf+cn, n);
- break;
- }
- }
- if(exdebug)
- iprint("export %d <- %F\n", getpid(), &q->rpc);-
- if(q->rpc.type == Tflush){- exflush(fs, q->rpc.tag, q->rpc.oldtag);
- free(q);
- continue;
- }
-
- q->export = fs;
- refinc(&fs->r);
-
- lock(&exq.l);
- if(exq.head == nil)
- exq.head = q;
- else
- exq.tail->next = q;
- q->next = nil;
- exq.tail = q;
- unlock(&exq.l);
- if(exq.qwait.first == nil) {- n = thread("exportfs", exslave, nil);-/* iprint("launch export (pid=%ux)\n", n); */- }
- rendwakeup(&exq.rwait);
- }
-bad:
- free(q);
- exshutdown(fs);
- exfree(fs);
-}
-
-void
-exflush(Export *fs, int flushtag, int tag)
-{- Exq *q, **last;
- int n;
- Fcall fc;
- char buf[MAXMSG];
-
- /* hasn't been started? */
- lock(&exq.l);
- last = &exq.head;
- for(q = exq.head; q != nil; q = q->next){- if(q->export == fs && q->rpc.tag == tag){- *last = q->next;
- unlock(&exq.l);
- exfree(fs);
- free(q);
- goto Respond;
- }
- last = &q->next;
- }
- unlock(&exq.l);
-
- /* in progress? */
- lock(&fs->r.l);
- for(q = fs->work; q != nil; q = q->next){- if(q->rpc.tag == tag && !q->noresponse){- lock(&q->lk);
- q->noresponse = 1;
- if(!q->nointr)
- intr(q->slave);
- unlock(&q->lk);
- unlock(&fs->r.l);
- goto Respond;
- return;
- }
- }
- unlock(&fs->r.l);
-
-if(exdebug) iprint("exflush: did not find rpc: %d\n", tag);-
-Respond:
- fc.type = Rflush;
- fc.tag = flushtag;
- n = convS2M(&fc, buf);
-if(exdebug) iprint("exflush -> %F\n", &fc);- if(!waserror()){- (*devtab[fs->io->type].write)(fs->io, buf, n, 0);
- poperror();
- }
-}
-
-void
-exshutdown(Export *fs)
-{- Exq *q, **last;
-
- lock(&exq.l);
- last = &exq.head;
- for(q = exq.head; q != nil; q = *last){- if(q->export == fs){- *last = q->next;
- exfree(fs);
- free(q);
- continue;
- }
- last = &q->next;
- }
- unlock(&exq.l);
-
- lock(&fs->r.l);
- q = fs->work;
- while(q != nil){- if(q->shut){- q = q->next;
- continue;
- }
- q->shut = 1;
- unlock(&fs->r.l);
- /* postnote(q->slave, 1, "interrupted", NUser); */
- iprint("postnote 2!\n");- lock(&fs->r.l);
- q = fs->work;
- }
- unlock(&fs->r.l);
-}
-
-void
-exfree(Export *fs)
-{- Fid *f, *n;
- int i;
-
- if(refdec(&fs->r) != 0)
- return;
- closepgrp(fs->pgrp);
- cclose(fs->root);
- cclose(fs->io);
- for(i = 0; i < Nfidhash; i++){- for(f = fs->fid[i]; f != nil; f = n){- if(f->chan != nil)
- cclose(f->chan);
- n = f->next;
- free(f);
- }
- }
- free(fs);
-}
-
-int
-exwork(void *a)
-{- return exq.head != nil;
-}
-
-void
-exslave(void *a)
-{- Export *fs;
- Exq *q, *t, **last;
- char *err;
- int n;
-/*
- closepgrp(up->pgrp);
- up->pgrp = nil;
-*/
- for(;;){- qlock(&exq.qwait);
- rendsleep(&exq.rwait, exwork, nil);
-
- lock(&exq.l);
- q = exq.head;
- if(q == nil) {- unlock(&exq.l);
- qunlock(&exq.qwait);
- continue;
- }
- exq.head = q->next;
- q->slave = curthread();
- unlock(&exq.l);
-
- qunlock(&exq.qwait);
-
- q->noresponse = 0;
- q->nointr = 0;
- fs = q->export;
- lock(&fs->r.l);
- q->next = fs->work;
- fs->work = q;
- unlock(&fs->r.l);
-
- up->pgrp = q->export->pgrp;
-
- if(exdebug > 1)
- iprint("exslave dispatch %d %F\n", getpid(), &q->rpc);-
- if(waserror()){- iprint("exslave err %r\n");- err = up->errstr;
- goto Err;
- }
- if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
- err = "bad fcall type";
- else
- err = (*fcalls[q->rpc.type])(fs, &q->rpc);
-
- poperror();
- Err:;
- q->rpc.type++;
- if(err){- q->rpc.type = Rerror;
- strncpy(q->rpc.ename, err, ERRLEN);
- }
- n = convS2M(&q->rpc, q->buf);
-
- if(exdebug)
- iprint("exslve %d -> %F\n", getpid(), &q->rpc);-
- lock(&q->lk);
- if(q->noresponse == 0){- q->nointr = 1;
- clearintr();
- if(!waserror()){- (*devtab[fs->io->type].write)(fs->io, q->buf, n, 0);
- poperror();
- }
- }
- unlock(&q->lk);
-
- /*
- * exflush might set noresponse at this point, but
- * setting noresponse means don't send a response now;
- * it's okay that we sent a response already.
- */
- if(exdebug > 1)
- iprint("exslave %d written %d\n", getpid(), q->rpc.tag);-
- lock(&fs->r.l);
- last = &fs->work;
- for(t = fs->work; t != nil; t = t->next){- if(t == q){- *last = q->next;
- break;
- }
- last = &t->next;
- }
- unlock(&fs->r.l);
-
- exfree(q->export);
- free(q);
- }
- iprint("exslave shut down");- threadexit();
-}
-
-Fid*
-Exmkfid(Export *fs, int fid)
-{- ulong h;
- Fid *f, *nf;
-
- nf = mallocz(sizeof(Fid));
- if(nf == nil)
- return nil;
- lock(&fs->fidlock);
- h = fid % Nfidhash;
- for(f = fs->fid[h]; f != nil; f = f->next){- if(f->fid == fid){- unlock(&fs->fidlock);
- free(nf);
- return nil;
- }
- }
-
- nf->next = fs->fid[h];
- if(nf->next != nil)
- nf->next->last = &nf->next;
- nf->last = &fs->fid[h];
- fs->fid[h] = nf;
-
- nf->fid = fid;
- nf->ref = 1;
- nf->attached = 1;
- nf->offset = 0;
- nf->chan = nil;
- unlock(&fs->fidlock);
- return nf;
-}
-
-Fid*
-Exgetfid(Export *fs, int fid)
-{- Fid *f;
- ulong h;
-
- lock(&fs->fidlock);
- h = fid % Nfidhash;
- for(f = fs->fid[h]; f; f = f->next) {- if(f->fid == fid){- if(f->attached == 0)
- break;
- f->ref++;
- unlock(&fs->fidlock);
- return f;
- }
- }
- unlock(&fs->fidlock);
- return nil;
-}
-
-void
-Exputfid(Export *fs, Fid *f)
-{- lock(&fs->fidlock);
- f->ref--;
- if(f->ref == 0 && f->attached == 0){- if(f->chan != nil)
- cclose(f->chan);
- f->chan = nil;
- *f->last = f->next;
- if(f->next != nil)
- f->next->last = f->last;
- unlock(&fs->fidlock);
- free(f);
- return;
- }
- unlock(&fs->fidlock);
-}
-
-char*
-Exsession(Export *e, Fcall *rpc)
-{- memset(rpc->authid, 0, sizeof(rpc->authid));
- memset(rpc->authdom, 0, sizeof(rpc->authdom));
- memset(rpc->chal, 0, sizeof(rpc->chal));
- return nil;
-}
-
-char*
-Exauth(Export *e, Fcall *f)
-{- return "authentication not required";
-}
-
-char*
-Exattach(Export *fs, Fcall *rpc)
-{- Fid *f;
-
- f = Exmkfid(fs, rpc->fid);
- if(f == nil)
- return Einuse;
- if(waserror()){- f->attached = 0;
- Exputfid(fs, f);
- return up->errstr;
- }
- f->chan = clone(fs->root, nil);
- poperror();
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exclone(Export *fs, Fcall *rpc)
-{- Fid *f, *nf;
-
- if(rpc->fid == rpc->newfid)
- return Einuse;
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- nf = Exmkfid(fs, rpc->newfid);
- if(nf == nil){- Exputfid(fs, f);
- return Einuse;
- }
- if(waserror()){- Exputfid(fs, f);
- Exputfid(fs, nf);
- return up->errstr;
- }
- nf->chan = clone(f->chan, nil);
- poperror();
- Exputfid(fs, f);
- Exputfid(fs, nf);
- return nil;
-}
-
-char*
-Exclunk(Export *fs, Fcall *rpc)
-{- Fid *f;
-
- f = Exgetfid(fs, rpc->fid);
- if(f != nil){- f->attached = 0;
- Exputfid(fs, f);
- }
- return nil;
-}
-
-char*
-Exwalk(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = walk(f->chan, rpc->name, 1);
- if(c == nil)
- error(Enonexist);
- poperror();
-
- f->chan = c;
- rpc->qid = c->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exopen(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- c = (*devtab[c->type].open)(c, rpc->mode);
- poperror();
-
- f->chan = c;
- f->offset = 0;
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Excreate(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- if(c->mnt && !(c->flag&CCREATE))
- c = createdir(c);
- c = (*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm);
- poperror();
-
- f->chan = c;
- rpc->qid = f->chan->qid;
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exread(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
- long off;
- int dir, n, seek;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
-
- c = f->chan;
- dir = c->qid.path & CHDIR;
- if(dir){- rpc->count -= rpc->count%DIRLEN;
- if(rpc->offset%DIRLEN || rpc->count==0){- Exputfid(fs, f);
- return Ereaddir;
- }
- if(f->offset > rpc->offset){- Exputfid(fs, f);
- return Eseekdir;
- }
- }
-
- if(waserror()) {- Exputfid(fs, f);
- return up->errstr;
- }
-
- for(;;){- n = rpc->count;
- seek = 0;
- off = rpc->offset;
- if(dir && f->offset != off){- off = f->offset;
- n = rpc->offset - off;
- if(n > MAXDIRREAD)
- n = MAXDIRREAD;
- seek = 1;
- }
- if(dir && c->mnt != nil)
- n = unionread(c, rpc->data, n);
- else{- c->offset = off;
- n = (*devtab[c->type].read)(c, rpc->data, n, off);
- }
- if(n == 0 || !seek)
- break;
- f->offset = off + n;
- c->offset += n;
- }
- rpc->count = n;
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exwrite(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- if(c->qid.path & CHDIR)
- error(Eisdir);
- rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exstat(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].stat)(c, rpc->stat);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exwstat(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].wstat)(c, rpc->stat);
- poperror();
- Exputfid(fs, f);
- return nil;
-}
-
-char*
-Exremove(Export *fs, Fcall *rpc)
-{- Fid *f;
- Chan *c;
-
- f = Exgetfid(fs, rpc->fid);
- if(f == nil)
- return Enofid;
- if(waserror()){- Exputfid(fs, f);
- return up->errstr;
- }
- c = f->chan;
- (*devtab[c->type].remove)(c);
- poperror();
-
- /*
- * chan is already clunked by remove.
- * however, we need to recover the chan,
- * and follow sysremove's lead in making to point to root.
- */
- c->type = 0;
-
- f->attached = 0;
- Exputfid(fs, f);
- return nil;
-}
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -10,7 +10,7 @@
int canlock(Lock*);
int canputc(void*);
int canqlock(QLock*);
-int canrlock(RWlock*);
+int canrlock(RWLock*);
void chandevinit(void);
void chandevreset(void);
void chandevshutdown(void);
@@ -45,7 +45,7 @@
long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
Devgen devgen;
void devinit(void);
-int devno(int, int);
+int devno(int);
Chan* devopen(Chan*, int, Dirtab*, int, Devgen*);
void devpermcheck(char*, ulong, int);
void devpower(int);
@@ -71,7 +71,6 @@
void exit(int);
Fd* copyfd(Fd*);
void fddecref(Fd*);
-void fdclose(int, int);
Chan* fdtochan(int, int, int, int);
void fpatransfer(u32int);
void fpaoperation(u32int);
@@ -151,6 +150,7 @@
void pexit(char*, int);
void printinit(void);
int procindex(ulong);
+void procinterrupt(Proc*);
void pgrpcpy(Pgrp*, Pgrp*);
void pgrpnote(ulong, char*, long, int);
Pgrp* pgrptab(int);
@@ -207,8 +207,8 @@
int readnum(ulong, char*, ulong, ulong, int);
int readstr(ulong, char*, ulong, char*);
int return0(void*);
-void rlock(RWlock*);
-void runlock(RWlock*);
+void rlock(RWLock*);
+void runlock(RWLock*);
extern void (*screenputs)(char*, int);
void* secalloc(ulong);
void secfree(void*);
@@ -244,8 +244,8 @@
Proc* wakeup(Rendez*);
int walk(Chan**, char**, int, int, int*);
#define waserror() (setjmp(pwaserror()->buf))
-void wlock(RWlock*);
-void wunlock(RWlock*);
+void wlock(RWLock*);
+void wunlock(RWLock*);
void osyield(void);
void osmsleep(int);
ulong ticks(void);
--- a/kern/notify.c
+++ b/kern/notify.c
@@ -19,6 +19,12 @@
* useful.
*/
+
+ /* TODO: This goes away
+ * The notes here are for taking host notes and delivering to
+ * the kernel. We will be going the other way, from the
+ * rc + kernelspace to the running processes.
+ */
#include <u.h>
#include <signal.h>
#include <lib.h>
--- a/kern/parse.c
+++ b/kern/parse.c
@@ -35,7 +35,7 @@
Cmdbuf*
parsecmd(char *p, int n)
{- Cmdbuf */*volatile*/ cb;
+ Cmdbuf *volatile cb;
int nf;
char *sp;
--- a/kern/posix.c
+++ b/kern/posix.c
@@ -13,19 +13,6 @@
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/select.h>
-
-#if defined (__APPLE__)
-#include <mach/mach.h>
-#include <mach/vm_map.h>
-#include <mach/mach_error.h>
-#include <mach/mach_vm.h>
-#ifdef panic
-#undef panic
-#endif
-mach_port_t task;
-#endif
-
-#include <sys/mman.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
@@ -72,10 +59,6 @@
if(pthread_key_create(&prdakey, 0))
panic("cannot pthread_key_create");-#if defined __APPLE__
- task = mach_task_self();
-#endif
-
signal(SIGPIPE, SIG_IGN);
}
@@ -150,6 +133,7 @@
tramp(void *vp)
{Proc *p;
+
p = vp;
if(pthread_setspecific(prdakey, p))
panic("cannot setspecific");--- a/kern/qio.c
+++ b/kern/qio.c
@@ -4,13 +4,6 @@
#include "fns.h"
#include "error.h"
-static ulong padblockcnt;
-static ulong concatblockcnt;
-static ulong pullupblockcnt;
-static ulong copyblockcnt;
-static ulong consumecnt;
-static ulong producecnt;
-
#define QDEBUG if(0)
/*
@@ -17,28 +10,28 @@
* IO queues
*/
typedef struct Queue Queue;
-
struct Queue
{Lock lk;
+ int state;
+ int dlen; /* data length in bytes */
+ uint rp, wp; /* read/write position (counting BALLOC() bytes) */
+ int limit; /* max BALLOC() bytes in queue */
+ int inilim; /* initial limit */
+ uchar noblock; /* true if writes return immediately when q full */
+ uchar eof; /* number of eofs read by user */
+
Block* bfirst; /* buffer */
Block* blast;
- int len; /* bytes allocated to queue */
- int dlen; /* data bytes in queue */
- int limit; /* max bytes in queue */
- int inilim; /* initial limit */
- int state;
- int noblock; /* true if writes return immediately when q full */
- int eof; /* number of eofs read by user */
-
+ void* arg; /* argument to kick and bypass */
void (*kick)(void*); /* restart output */
void (*bypass)(void*, Block*); /* bypass queue altogether */
- void* arg; /* argument to kick */
QLock rlock; /* mutex for reading processes */
Rendez rr; /* process waiting to read */
+
QLock wlock; /* mutex for writing processes */
Rendez wr; /* process waiting to write */
@@ -68,44 +61,6 @@
}
/*
- * pad a block to the front (or the back if size is negative)
- */
-Block*
-padblock(Block *bp, int size)
-{- int n;
- Block *nbp;
-
- QDEBUG checkb(bp, "padblock 0");
- if(size >= 0){- if(bp->rp - bp->base >= size){- bp->rp -= size;
- return bp;
- }
- n = BLEN(bp);
- nbp = allocb(size+n);
- nbp->rp += size;
- nbp->wp = nbp->rp;
- memmove(nbp->wp, bp->rp, n);
- nbp->wp += n;
- nbp->rp -= size;
- } else {- size = -size;
- if(bp->lim - bp->wp >= size)
- return bp;
- n = BLEN(bp);
- nbp = allocb(n+size);
- memmove(nbp->wp, bp->rp, n);
- nbp->wp += n;
- }
- nbp->next = bp->next;
- freeb(bp);
- padblockcnt++;
- QDEBUG checkb(nbp, "padblock 1");
- return nbp;
-}
-
-/*
* return count of bytes in a string of blocks
*/
int
@@ -122,19 +77,33 @@
}
/*
- * return count of space in blocks
+ * copy the contents of a string of blocks into
+ * memory from an offset. blocklist kept unchanged.
+ * return number of copied bytes.
*/
-int
-blockalloclen(Block *bp)
+long
+readblist(Block *b, uchar *p, long n, ulong o)
{- int len;
+ ulong m, r;
- len = 0;
- while(bp != nil) {- len += BALLOC(bp);
- bp = bp->next;
+ r = 0;
+ while(n > 0 && b != nil){+ m = BLEN(b);
+ if(o >= m)
+ o -= m;
+ else {+ m -= o;
+ if(n < m)
+ m = n;
+ memmove(p, b->rp + o, m);
+ p += m;
+ r += m;
+ n -= m;
+ o = 0;
+ }
+ b = b->next;
}
- return len;
+ return r;
}
/*
@@ -149,7 +118,6 @@
if(bp->next == nil)
return bp;
len = blocklen(bp);
- concatblockcnt += len;
return pullupblock(bp, len);
}
@@ -162,6 +130,8 @@
Block *nbp;
int i;
+ assert(n >= 0);
+
/*
* this should almost always be true, it's
* just to avoid every caller checking.
@@ -184,7 +154,6 @@
*/
n -= BLEN(bp);
while((nbp = bp->next) != nil){- pullupblockcnt++;
i = BLEN(nbp);
if(i > n) {memmove(bp->wp, nbp->rp, n);
@@ -223,6 +192,8 @@
{Block *b;
+ assert(n >= 0);
+
if(BLEN(q->bfirst) >= n)
return q->bfirst;
q->bfirst = pullupblock(q->bfirst, n);
@@ -241,8 +212,14 @@
ulong l;
Block *nb, *startb;
+ assert(len >= 0);
+ assert(offset >= 0);
+
QDEBUG checkb(bp, "trimblock 1");
- if(blocklen(bp) < offset+len) {+ l = blocklen(bp);
+ if(offset == 0 && len == l)
+ return bp;
+ if(l < offset+len) {freeblist(bp);
return nil;
}
@@ -274,6 +251,43 @@
}
/*
+ * pad a block to the front (or the back if size is negative)
+ */
+Block*
+padblock(Block *bp, int size)
+{+ int n;
+ Block *nbp;
+
+ QDEBUG checkb(bp, "padblock 0");
+ if(size >= 0){+ if(bp->rp - bp->base >= size){+ bp->rp -= size;
+ return bp;
+ }
+ n = BLEN(bp);
+ nbp = allocb(size+n);
+ nbp->rp += size;
+ nbp->wp = nbp->rp;
+ memmove(nbp->wp, bp->rp, n);
+ nbp->wp += n;
+ nbp->rp -= size;
+ } else {+ size = -size;
+ if(bp->lim - bp->wp >= size)
+ return bp;
+ n = BLEN(bp);
+ nbp = allocb(n+size);
+ memmove(nbp->wp, bp->rp, n);
+ nbp->wp += n;
+ }
+ nbp->next = bp->next;
+ freeb(bp);
+ QDEBUG checkb(nbp, "padblock 1");
+ return nbp;
+}
+
+/*
* copy 'count' bytes into a new block
*/
Block*
@@ -282,6 +296,8 @@
int l;
Block *nbp;
+ assert(count >= 0);
+
QDEBUG checkb(bp, "copyblock 0");
nbp = allocb(count);
for(; count > 0 && bp != nil; bp = bp->next){@@ -296,7 +312,6 @@
memset(nbp->wp, 0, count);
nbp->wp += count;
}
- copyblockcnt++;
QDEBUG checkb(nbp, "copyblock 1");
return nbp;
@@ -330,7 +345,30 @@
return bp;
}
+/*
+ * if the allocated space is way out of line with the used
+ * space, reallocate to a smaller block
+ */
+Block*
+packblock(Block *bp)
+{+ Block **l, *nbp;
+ int n;
+ for(l = &bp; (nbp = *l) != nil; l = &(*l)->next){+ n = BLEN(nbp);
+ if((n<<2) < BALLOC(nbp)){+ *l = allocb(n);
+ memmove((*l)->wp, nbp->rp, n);
+ (*l)->wp += n;
+ (*l)->next = nbp->next;
+ freeb(nbp);
+ }
+ }
+
+ return bp;
+}
+
/*
* throw away up to count bytes from a
* list of blocks. Return count of bytes
@@ -346,8 +384,8 @@
if(bph == nil)
return 0;
- while(*bph != nil && count != 0) {- bp = *bph;
+ while((bp = *bph) != nil && count > 0) {+ QDEBUG checkb(bp, "pullblock ");
n = BLEN(bp);
if(count < n)
n = count;
@@ -354,7 +392,6 @@
bytes += n;
count -= n;
bp->rp += n;
- QDEBUG checkb(bp, "pullblock ");
if(BLEN(bp) == 0) {*bph = bp->next;
bp->next = nil;
@@ -365,103 +402,145 @@
}
/*
- * get next block from a queue, return null if nothing there
+ * remove a block from the front of the queue
*/
Block*
-qget(Queue *q)
+qremove(Queue *q)
{- int dowakeup;
Block *b;
- /* sync with qwrite */
- ilock(&q->lk);
-
b = q->bfirst;
- if(b == nil){- q->state |= Qstarve;
- iunlock(&q->lk);
+ if(b == nil)
return nil;
- }
- QDEBUG checkb(b, "qget");
+ QDEBUG checkb(b, "qremove");
q->bfirst = b->next;
b->next = nil;
- q->len -= BALLOC(b);
q->dlen -= BLEN(b);
+ q->rp += BALLOC(b);
+ return b;
+}
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
+/*
+ * put a block back to the front of the queue
+ */
+void
+qputback(Queue *q, Block *b)
+{+ QDEBUG checkb(b, "qputback");
+ b->next = q->bfirst;
+ if(q->bfirst == nil)
+ q->blast = b;
+ q->bfirst = b;
+ q->dlen += BLEN(b);
+ q->rp -= BALLOC(b);
+}
+/*
+ * after removing data from the queue,
+ * unlock queue and wakeup blocked writer.
+ * called at interrupt level.
+ */
+static int
+iunlock_consumer(Queue *q)
+{+ int s = q->state;
+
+ /* stop flow control when back at or below the limit */
+ if((int)(q->wp - q->rp) <= q->limit)
+ q->state = s & ~Qflow;
+
iunlock(&q->lk);
- if(dowakeup)
+ if(s & Qflow){+ /*
+ * wakeup flow controlled writers.
+ * note that this is done even when q->state
+ * still has Qflow set, as the unblocking
+ * condition depends on the writers local queuing
+ * position, not on the global queue length.
+ */
wakeup(&q->wr);
-
- return b;
+ }
+ return s;
}
/*
- * throw away the next 'len' bytes in the queue
+ * after removing data from the queue,
+ * unlock queue and wakeup blocked writer.
+ * get output going again when it was blocked.
+ * called at process level.
*/
-int
-qdiscard(Queue *q, int len)
+static int
+iunlock_reader(Queue *q)
{- Block *b, *tofree = nil;
- int dowakeup, n, sofar;
+ int s = iunlock_consumer(q);
- ilock(&q->lk);
- for(sofar = 0; sofar < len; sofar += n){- b = q->bfirst;
- if(b == nil)
- break;
- QDEBUG checkb(b, "qdiscard");
- n = BLEN(b);
- if(n <= len - sofar){- q->bfirst = b->next;
- q->len -= BALLOC(b);
- q->dlen -= BLEN(b);
+ if(q->kick != nil && s & Qflow)
+ (*q->kick)(q->arg);
- /* remember to free this */
- b->next = tofree;
- tofree = b;
- } else {- n = len - sofar;
- b->rp += n;
- q->dlen -= n;
- }
- }
+ return s;
+}
- /*
- * if writer flow controlled, restart
- *
- * This used to be
- * q->len < q->limit/2
- * but it slows down tcp too much for certain write sizes.
- * I really don't understand it completely. It may be
- * due to the queue draining so fast that the transmission
- * stalls waiting for the app to produce more data. - presotto
- */
- if((q->state & Qflow) && q->len < q->limit){- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
+/*
+ * after inserting into queue,
+ * unlock queue and wakeup starved reader.
+ * called at interrupt level.
+ */
+static int
+iunlock_producer(Queue *q)
+{+ int s = q->state;
+ /* start flow control when above the limit */
+ if((int)(q->wp - q->rp) > q->limit)
+ s |= Qflow;
+
+ q->state = s & ~Qstarve;
iunlock(&q->lk);
- if(dowakeup)
- wakeup(&q->wr);
+ if(s & Qstarve)
+ wakeup(&q->rr);
- if(tofree != nil)
- freeblist(tofree);
+ return s;
+}
- return sofar;
+/*
+ * unlock queue and wakeup starved reader.
+ * get output going again when it was starved.
+ * called at process level.
+ */
+static int
+iunlock_writer(Queue *q)
+{+ int s = iunlock_producer(q);
+
+ if(q->kick != nil && s & (Qstarve|Qkick))
+ (*q->kick)(q->arg);
+
+ return s;
}
/*
+ * get next block from a queue, return null if nothing there
+ * called at interrupt level.
+ */
+Block*
+qget(Queue *q)
+{+ Block *b;
+
+ ilock(&q->lk);
+ if((b = qremove(q)) == nil){+ q->state |= Qstarve;
+ iunlock(&q->lk);
+ return nil;
+ }
+ iunlock_consumer(q);
+
+ return b;
+}
+
+/*
* Interrupt level copy out of a queue, return # bytes copied.
*/
int
@@ -468,12 +547,11 @@
qconsume(Queue *q, void *vp, int len)
{Block *b, *tofree = nil;
- int n, dowakeup;
- uchar *p = vp;
+ int n;
- /* sync with qwrite */
- ilock(&q->lk);
+ assert(len >= 0);
+ ilock(&q->lk);
for(;;) {b = q->bfirst;
if(b == nil){@@ -486,8 +564,10 @@
n = BLEN(b);
if(n > 0)
break;
+
+ /* get rid of zero-length blocks */
q->bfirst = b->next;
- q->len -= BALLOC(b);
+ q->rp += BALLOC(b);
/* remember to free this */
b->next = tofree;
@@ -494,10 +574,9 @@
tofree = b;
};
- consumecnt += n;
if(n < len)
len = n;
- memmove(p, b->rp, len);
+ memmove(vp, b->rp, len);
b->rp += len;
q->dlen -= len;
@@ -504,7 +583,7 @@
/* discard the block if we're done with it */
if((q->state & Qmsg) || len == n){q->bfirst = b->next;
- q->len -= BALLOC(b);
+ q->rp += BALLOC(b);
q->dlen -= BLEN(b);
/* remember to free this */
@@ -511,23 +590,40 @@
b->next = tofree;
tofree = b;
}
-
out:
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){- q->state &= ~Qflow;
- dowakeup = 1;
- } else
- dowakeup = 0;
+ iunlock_consumer(q);
- iunlock(&q->lk);
+ freeblist(tofree);
- if(dowakeup)
- wakeup(&q->wr);
+ return len;
+}
- if(tofree != nil)
- freeblist(tofree);
+/*
+ * add a block list to a queue, return bytes added
+ */
+int
+qaddlist(Queue *q, Block *b)
+{+ int len;
+ QDEBUG checkb(b, "qaddlist 1");
+
+ /* queue the block */
+ if(q->bfirst != nil)
+ q->blast->next = b;
+ else
+ q->bfirst = b;
+
+ len = BLEN(b);
+ q->wp += BALLOC(b);
+ while(b->next != nil){+ b = b->next;
+ QDEBUG checkb(b, "qaddlist 2");
+ len += BLEN(b);
+ q->wp += BALLOC(b);
+ }
+ q->dlen += len;
+ q->blast = b;
return len;
}
@@ -534,36 +630,22 @@
int
qpass(Queue *q, Block *b)
{- int len, dowakeup;
+ int len;
- /* sync with qread */
- dowakeup = 0;
ilock(&q->lk);
- if(q->len >= q->limit){+ if(q->state & Qclosed){iunlock(&q->lk);
freeblist(b);
- return -1;
+ return 0;
}
- if(q->state & Qclosed){+ if(q->state & Qflow){iunlock(&q->lk);
freeblist(b);
- return 0;
+ return -1;
}
-
len = qaddlist(q, b);
+ iunlock_producer(q);
- if(q->len >= q->limit/2)
- q->state |= Qflow;
-
- if(q->state & Qstarve){- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
return len;
}
@@ -570,101 +652,36 @@
int
qpassnolim(Queue *q, Block *b)
{- int len, dowakeup;
+ int len;
- /* sync with qread */
- dowakeup = 0;
ilock(&q->lk);
-
if(q->state & Qclosed){iunlock(&q->lk);
freeblist(b);
return 0;
}
-
len = qaddlist(q, b);
+ iunlock_producer(q);
- if(q->len >= q->limit/2)
- q->state |= Qflow;
-
- if(q->state & Qstarve){- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
return len;
}
-/*
- * if the allocated space is way out of line with the used
- * space, reallocate to a smaller block
- */
-Block*
-packblock(Block *bp)
-{- Block **l, *nbp;
- int n;
-
- for(l = &bp; (nbp = *l) != nil; l = &(*l)->next){- n = BLEN(nbp);
- if((n<<2) < BALLOC(nbp)){- *l = allocb(n);
- memmove((*l)->wp, nbp->rp, n);
- (*l)->wp += n;
- (*l)->next = nbp->next;
- freeb(nbp);
- }
- }
-
- return bp;
-}
-
int
qproduce(Queue *q, void *vp, int len)
{Block *b;
- int dowakeup;
- uchar *p = vp;
+ assert(len >= 0);
+
b = iallocb(len);
if(b == nil)
return 0;
- /* sync with qread */
- dowakeup = 0;
- ilock(&q->lk);
-
- /* no waiting receivers, room in buffer? */
- if(q->len >= q->limit){- q->state |= Qflow;
- iunlock(&q->lk);
- freeb(b);
- return -1;
- }
- producecnt += len;
-
/* save in buffer */
- memmove(b->wp, p, len);
+ memmove(b->wp, vp, len);
b->wp += len;
- qaddlist(q, b);
- if(q->state & Qstarve){- q->state &= ~Qstarve;
- dowakeup = 1;
- }
-
- if(q->len >= q->limit)
- q->state |= Qflow;
- iunlock(&q->lk);
-
- if(dowakeup)
- wakeup(&q->rr);
-
- return len;
+ return qpass(q, b);
}
/*
@@ -675,6 +692,8 @@
{Block *b;
+ assert(len >= 0);
+
b = allocb(len);
ilock(&q->lk);
b->wp += readblist(q->bfirst, b->wp, len, offset);
@@ -690,16 +709,18 @@
{Queue *q;
+ assert(limit >= 0);
+
q = malloc(sizeof(Queue));
if(q == nil)
return nil;
+ q->dlen = 0;
+ q->wp = q->rp = 0;
q->limit = q->inilim = limit;
q->kick = kick;
q->arg = arg;
- q->state = msg;
-
- q->state |= Qstarve;
+ q->state = msg | Qstarve;
q->eof = 0;
q->noblock = 0;
@@ -716,10 +737,14 @@
if(q == nil)
return nil;
+ q->dlen = 0;
+ q->wp = q->rp = 0;
q->limit = 0;
q->arg = arg;
q->bypass = bypass;
q->state = 0;
+ q->eof = 0;
+ q->noblock = 0;
return q;
}
@@ -729,7 +754,7 @@
{Queue *q = a;
- return (q->state & Qclosed) || q->bfirst != nil;
+ return q->bfirst != nil || (q->state & Qclosed);
}
/*
@@ -745,10 +770,9 @@
break;
if(q->state & Qclosed){- if(++q->eof > 3)
+ if(q->eof >= 3 || (*q->err && strcmp(q->err, Ehungup) != 0))
return -1;
- if(*q->err && strcmp(q->err, Ehungup) != 0)
- return -1;
+ q->eof++;
return 0;
}
@@ -761,101 +785,6 @@
}
/*
- * add a block list to a queue, return bytes added
- */
-int
-qaddlist(Queue *q, Block *b)
-{- int len, dlen;
-
- QDEBUG checkb(b, "qaddlist 1");
-
- /* queue the block */
- if(q->bfirst != nil)
- q->blast->next = b;
- else
- q->bfirst = b;
-
- len = BALLOC(b);
- dlen = BLEN(b);
- while(b->next != nil){- b = b->next;
- QDEBUG checkb(b, "qaddlist 2");
-
- len += BALLOC(b);
- dlen += BLEN(b);
- }
- q->blast = b;
- q->len += len;
- q->dlen += dlen;
- return dlen;
-}
-
-/*
- * called with q ilocked
- */
-Block*
-qremove(Queue *q)
-{- Block *b;
-
- b = q->bfirst;
- if(b == nil)
- return nil;
- QDEBUG checkb(b, "qremove");
- q->bfirst = b->next;
- b->next = nil;
- q->dlen -= BLEN(b);
- q->len -= BALLOC(b);
- return b;
-}
-
-/*
- * copy the contents of a string of blocks into
- * memory from an offset. blocklist kept unchanged.
- * return number of copied bytes.
- */
-long
-readblist(Block *b, uchar *p, long n, ulong o)
-{- ulong m, r;
-
- r = 0;
- while(n > 0 && b != nil){- m = BLEN(b);
- if(o >= m)
- o -= m;
- else {- m -= o;
- if(n < m)
- m = n;
- memmove(p, b->rp + o, m);
- p += m;
- r += m;
- n -= m;
- o = 0;
- }
- b = b->next;
- }
- return r;
-}
-
-/*
- * put a block back to the front of the queue
- * called with q ilocked
- */
-void
-qputback(Queue *q, Block *b)
-{- b->next = q->bfirst;
- if(q->bfirst == nil)
- q->blast = b;
- q->bfirst = b;
- q->len += BALLOC(b);
- q->dlen += BLEN(b);
-}
-
-/*
* cut off n bytes from the end of *h. return a new
* block with the tail and change *h to refer to the
* head.
@@ -885,31 +814,6 @@
}
/*
- * flow control, get producer going again
- * called with q ilocked
- */
-static void
-qwakeup_iunlock(Queue *q)
-{- int dowakeup = 0;
-
- /* if writer flow controlled, restart */
- if((q->state & Qflow) && q->len < q->limit/2){- q->state &= ~Qflow;
- dowakeup = 1;
- }
-
- iunlock(&q->lk);
-
- /* wakeup flow controlled writers */
- if(dowakeup){- if(q->kick != nil)
- q->kick(q->arg);
- wakeup(&q->wr);
- }
-}
-
-/*
* get next block from a queue (up to a limit)
*/
Block*
@@ -918,6 +822,8 @@
Block *b;
int n;
+ assert(len >= 0);
+
qlock(&q->rlock);
if(waserror()){qunlock(&q->rlock);
@@ -950,10 +856,8 @@
else
b->wp -= n;
}
+ iunlock_reader(q);
- /* restart producer */
- qwakeup_iunlock(q);
-
qunlock(&q->rlock);
poperror();
@@ -970,6 +874,8 @@
Block *b, *first, **last;
int m, n;
+ assert(len >= 0);
+
qlock(&q->rlock);
if(waserror()){qunlock(&q->rlock);
@@ -1001,8 +907,8 @@
freeb(qremove(q));
goto again;
}
-
- /* grab the first block plus as many
+ /*
+ * grab the first block plus as many
* following blocks as will partially
* fit in the read.
*/
@@ -1025,8 +931,7 @@
if(n > len && (q->state & Qmsg) == 0)
qputback(q, splitblock(last, n - len));
- /* restart producer */
- qwakeup_iunlock(q);
+ iunlock_reader(q);
qunlock(&q->rlock);
poperror();
@@ -1042,34 +947,39 @@
return n;
}
+/*
+ * a Flow represens a flow controlled
+ * writer on queue q with position p.
+ */
+typedef struct {+ Queue* q;
+ uint p;
+} Flow;
+
static int
-qnotfull(void *a)
+unblocked(void *a)
{- Queue *q = a;
+ Flow *f = a;
+ Queue *q = f->q;
- return q->len < q->limit || (q->state & Qclosed);
+ return q->noblock || (int)(f->p - q->rp) <= q->limit || (q->state & Qclosed);
}
/*
- * flow control, wait for queue to get below the limit
+ * flow control, wait for queue to drain back to the limit
*/
static void
-qflow(Queue *q)
+qflow(Flow *f)
{- for(;;){- if(q->noblock || qnotfull(q))
- break;
+ Queue *q = f->q;
- ilock(&q->lk);
- q->state |= Qflow;
- iunlock(&q->lk);
-
+ while(!unblocked(f)){qlock(&q->wlock);
if(waserror()){qunlock(&q->wlock);
nexterror();
}
- sleep(&q->wr, qnotfull, q);
+ sleep(&q->wr, unblocked, f);
qunlock(&q->wlock);
poperror();
}
@@ -1081,7 +991,8 @@
long
qbwrite(Queue *q, Block *b)
{- int len, dowakeup;
+ Flow flow;
+ int len;
if(q->bypass != nil){len = blocklen(b);
@@ -1089,7 +1000,6 @@
return len;
}
- dowakeup = 0;
if(waserror()){freeblist(b);
nexterror();
@@ -1101,9 +1011,11 @@
iunlock(&q->lk);
error(q->err);
}
-
- /* don't queue over the limit */
- if(q->len >= q->limit && q->noblock){+ /*
+ * if the queue is full,
+ * silently discard when non-blocking
+ */
+ if(q->state & Qflow && q->noblock){iunlock(&q->lk);
poperror();
len = blocklen(b);
@@ -1110,33 +1022,25 @@
freeblist(b);
return len;
}
-
len = qaddlist(q, b);
-
- /* make sure other end gets awakened */
- if(q->state & Qstarve){- q->state &= ~Qstarve;
- dowakeup = 1;
- }
- iunlock(&q->lk);
poperror();
- /* get output going again */
- if(q->kick != nil && (dowakeup || (q->state&Qkick)))
- q->kick(q->arg);
-
- /* wakeup anyone consuming at the other end */
- if(dowakeup)
- wakeup(&q->rr);
-
/*
- * flow control, before allowing the process to continue and
- * queue more. We do this here so that postnote can only
- * interrupt us after the data has been queued. This means that
- * things like 9p flushes and ssl messages will not be disrupted
- * by software interrupts.
+ * save our current position in queue
+ * for flow control below.
*/
- qflow(q);
+ flow.q = q;
+ flow.p = q->wp;
+ if(iunlock_writer(q) & Qflow){+ /*
+ * flow control, before allowing the process to continue and
+ * queue more. We do this here so that postnote can only
+ * interrupt us after the data has been queued. This means that
+ * things like 9p flushes and ssl messages will not be disrupted
+ * by software interrupts.
+ */
+ qflow(&flow);
+ }
return len;
}
@@ -1151,17 +1055,11 @@
Block *b;
uchar *p = vp;
+ assert(len >= 0);
+
QDEBUG if(!islo())
print("qwrite hi %#p\n", getcallerpc(&q));- /* stop queue bloat before allocating blocks */
- if(q->len/2 >= q->limit && q->noblock == 0 && q->bypass == nil){- while(waserror())
- ;
- qflow(q);
- poperror();
- }
-
sofar = 0;
do {n = len-sofar;
@@ -1190,11 +1088,11 @@
int
qiwrite(Queue *q, void *vp, int len)
{- int n, sofar, dowakeup;
+ int n, sofar;
Block *b;
uchar *p = vp;
- dowakeup = 0;
+ assert(len >= 0);
sofar = 0;
do {@@ -1209,46 +1107,72 @@
b->wp += n;
ilock(&q->lk);
-
- /* we use an artificially high limit for kernel prints since anything
- * over the limit gets dropped
- */
- if((q->state & Qclosed) != 0 || q->len/2 >= q->limit){+ if(q->state & (Qflow|Qclosed)){iunlock(&q->lk);
freeb(b);
break;
}
+ sofar += qaddlist(q, b);
+ iunlock_writer(q);
+ } while(sofar < len && (q->state & Qmsg) == 0);
- qaddlist(q, b);
+ return sofar;
+}
- if(q->state & Qstarve){- q->state &= ~Qstarve;
- dowakeup = 1;
- }
+/*
+ * throw away the next 'len' bytes in the queue
+ */
+int
+qdiscard(Queue *q, int len)
+{+ Block *b, *tofree = nil;
+ int n, sofar;
- iunlock(&q->lk);
+ assert(len >= 0);
- if(dowakeup){- if(q->kick != nil)
- q->kick(q->arg);
- wakeup(&q->rr);
+ ilock(&q->lk);
+ for(sofar = 0; sofar < len; sofar += n){+ b = q->bfirst;
+ if(b == nil)
+ break;
+ QDEBUG checkb(b, "qdiscard");
+ n = BLEN(b);
+ if(n <= len - sofar){+ q->bfirst = b->next;
+ q->rp += BALLOC(b);
+
+ /* remember to free this */
+ b->next = tofree;
+ tofree = b;
+ } else {+ n = len - sofar;
+ b->rp += n;
}
+ q->dlen -= n;
+ }
+ iunlock_consumer(q);
- sofar += n;
- } while(sofar < len && (q->state & Qmsg) == 0);
+ freeblist(tofree);
return sofar;
}
/*
- * be extremely careful when calling this,
- * as there is no reference accounting
+ * flush the output queue
*/
void
-qfree(Queue *q)
+qflush(Queue *q)
{- qclose(q);
- free(q);
+ Block *tofree;
+
+ ilock(&q->lk);
+ tofree = q->bfirst;
+ q->bfirst = nil;
+ q->rp = q->wp;
+ q->dlen = 0;
+ iunlock_consumer(q);
+
+ freeblist(tofree);
}
/*
@@ -1258,32 +1182,42 @@
void
qclose(Queue *q)
{- Block *bfirst;
+ Block *tofree;
if(q == nil)
return;
- /* mark it */
ilock(&q->lk);
q->state |= Qclosed;
q->state &= ~(Qflow|Qstarve);
kstrcpy(q->err, Ehungup, ERRMAX);
- bfirst = q->bfirst;
+ tofree = q->bfirst;
q->bfirst = nil;
- q->len = 0;
+ q->rp = q->wp;
q->dlen = 0;
q->noblock = 0;
iunlock(&q->lk);
- /* free queued blocks */
- freeblist(bfirst);
-
/* wake up readers/writers */
wakeup(&q->rr);
wakeup(&q->wr);
+
+ /* free queued blocks */
+ freeblist(tofree);
}
/*
+ * be extremely careful when calling this,
+ * as there is no reference accounting
+ */
+void
+qfree(Queue *q)
+{+ qclose(q);
+ free(q);
+}
+
+/*
* Mark a queue as closed. Wakeup any readers. Don't remove queued
* blocks.
*/
@@ -1290,7 +1224,6 @@
void
qhangup(Queue *q, char *msg)
{- /* mark it */
ilock(&q->lk);
q->state |= Qclosed;
if(msg == nil || *msg == '\0')
@@ -1336,26 +1269,21 @@
}
/*
- * return space remaining before flow control
+ * return true if we can read without blocking
*/
int
-qwindow(Queue *q)
+qcanread(Queue *q)
{- int l;
-
- l = q->limit - q->len;
- if(l < 0)
- l = 0;
- return l;
+ return q->bfirst != nil;
}
/*
- * return true if we can read without blocking
+ * return non-zero when the queue is full
*/
int
-qcanread(Queue *q)
+qfull(Queue *q)
{- return q->bfirst != nil;
+ return q->state & Qflow;
}
/*
@@ -1364,7 +1292,11 @@
void
qsetlimit(Queue *q, int limit)
{+ assert(limit >= 0);
+
+ ilock(&q->lk);
q->limit = limit;
+ iunlock_consumer(q);
}
/*
@@ -1373,34 +1305,7 @@
void
qnoblock(Queue *q, int onoff)
{- q->noblock = onoff;
-}
-
-/*
- * flush the output queue
- */
-void
-qflush(Queue *q)
-{- Block *bfirst;
-
- /* mark it */
ilock(&q->lk);
- bfirst = q->bfirst;
- q->bfirst = nil;
- q->len = 0;
- q->dlen = 0;
- iunlock(&q->lk);
-
- /* free queued blocks */
- freeblist(bfirst);
-
- /* wake up writers */
- wakeup(&q->wr);
-}
-
-int
-qfull(Queue *q)
-{- return q->state & Qflow;
+ q->noblock = onoff;
+ iunlock_consumer(q);
}
--- a/kern/qlock.c
+++ b/kern/qlock.c
@@ -72,7 +72,7 @@
lock(&q->lk);
/*
- * Can't assert this because of RWlock
+ * Can't assert this because of RWLock
assert(q->hold == CT);
*/
p = dequeue((Proc**)&q->first, (Proc**)&q->last);
--- a/kern/rendez.c
+++ /dev/null
@@ -1,89 +1,0 @@
-#include "u.h"
-#include "lib.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-void
-sleep(Rendez *r, int (*f)(void*), void *arg)
-{- int s;
-
- s = splhi();
-
- lock(&r->lk);
- lock(&up->rlock);
- if(r->p){- print("double sleep %lud %lud\n", r->p->pid, up->pid);- }
-
- /*
- * Wakeup only knows there may be something to do by testing
- * r->p in order to get something to lock on.
- * Flush that information out to memory in case the sleep is
- * committed.
- */
- r->p = up;
-
- if((*f)(arg) || up->notepending){- /*
- * if condition happened or a note is pending
- * never mind
- */
- r->p = nil;
- unlock(&up->rlock);
- unlock(&r->lk);
- } else {- /*
- * now we are committed to
- * change state and call scheduler
- */
- up->state = Wakeme;
- up->r = r;
-
- /* statistics */
- /* m->cs++; */
-
- unlock(&up->rlock);
- unlock(&r->lk);
-
- procsleep();
- }
-
- if(up->notepending) {- up->notepending = 0;
- splx(s);
- error(Eintr);
- }
-
- splx(s);
-}
-
-Proc*
-wakeup(Rendez *r)
-{- Proc *p;
- int s;
-
- s = splhi();
-
- lock(&r->lk);
- p = r->p;
-
- if(p != nil){- lock(&p->rlock);
- if(p->state != Wakeme || p->r != r)
- panic("wakeup: state");- r->p = nil;
- p->r = nil;
- p->state = Running;
- procwakeup(p);
- unlock(&p->rlock);
- }
- unlock(&r->lk);
-
- splx(s);
-
- return p;
-}
-
--- a/kern/rwlock.c
+++ b/kern/rwlock.c
@@ -5,7 +5,7 @@
#include "error.h"
void
-rlock(RWlock *l)
+rlock(RWLock *l)
{qlock(&l->x); /* wait here for writers and exclusion */
lock(&l->lk);
@@ -16,7 +16,7 @@
}
void
-runlock(RWlock *l)
+runlock(RWLock *l)
{lock(&l->lk);
if(--l->readers == 0) /* last reader out allows writers */
@@ -25,7 +25,7 @@
}
void
-wlock(RWlock *l)
+wlock(RWLock *l)
{qlock(&l->x); /* wait here for writers and exclusion */
qlock(&l->k); /* wait here for last reader */
@@ -32,7 +32,7 @@
}
void
-wunlock(RWlock *l)
+wunlock(RWLock *l)
{qunlock(&l->k);
qunlock(&l->x);
--- a/kern/sleep.c
+++ b/kern/sleep.c
@@ -70,20 +70,105 @@
lock(&r->lk);
p = r->p;
- if(p != nil){+ if(p == nil)
+ unlock(&r->lk);
+ else {lock(&p->rlock);
if(p->state != Wakeme || p->r != r)
panic("wakeup: state");+ p->state = Running;
r->p = nil;
p->r = nil;
- p->state = Running;
- procwakeup(p);
unlock(&p->rlock);
+ unlock(&r->lk);
+ procwakeup(p);
}
- unlock(&r->lk);
-
splx(s);
return p;
}
+/*
+ * if waking a sleeping process, this routine must hold both
+ * p->rlock and r->lock. However, it can't know them in
+ * the same order as wakeup causing a possible lock ordering
+ * deadlock. We break the deadlock by giving up the p->rlock
+ * lock if we can't get the r->lock and retrying.
+ */
+void
+procinterrupt(Proc *p)
+{+ int s;
+
+ p->notepending = 1;
+
+ /* this loop is to avoid lock ordering problems. */
+ for(;;){+ Rendez *r;
+
+ s = splhi();
+ lock(&p->rlock);
+ r = p->r;
+
+ /* waiting for a wakeup? */
+ if(r == nil)
+ break; /* no */
+
+ /* try for the second lock */
+ if(canlock(&r->lk)){+ if(p->state != Wakeme || r->p != p)
+ panic("procinterrupt: state %d %d %d",+ r->p != p, p->r != r, p->state);
+ p->r = nil;
+ r->p = nil;
+ unlock(&p->rlock);
+ unlock(&r->lk);
+ /* hands off r */
+ procwakeup(p);
+ splx(s);
+ return;
+ }
+
+ /* give other process time to get out of critical section and try again */
+ unlock(&p->rlock);
+ splx(s);
+
+ osyield();
+ }
+ unlock(&p->rlock);
+ splx(s);
+
+ switch(p->state){+ case Rendezvous:
+ /* Try and pull out of a rendezvous */
+ lock(&p->rgrp->ref.lk);
+ if(p->state == Rendezvous) {+ Proc *d, **l;
+
+ l = &REND(p->rgrp, (uintptr)p->rendtag);
+ for(d = *l; d != nil; d = d->rendhash) {+ if(d == p) {+ *l = p->rendhash;
+ p->rendval = (void*)~(uintptr)0;
+ unlock(&p->rgrp->ref.lk);
+ /* hands off p->rgrp */
+ procwakeup(p);
+ return;
+ }
+ l = &d->rendhash;
+ }
+ }
+ unlock(&p->rgrp->ref.lk);
+ break;
+ }
+}
+
+int
+postnote(Proc *p, int x, char *msg, int flag)
+{+ USED(x);
+ USED(msg);
+ USED(flag);
+ procinterrupt(p);
+ return 0;
+}
--- a/kern/stub.c
+++ b/kern/stub.c
@@ -56,17 +56,6 @@
USED(tag);
}
-/* TODO: We need this very soon */
-int
-postnote(Proc *p, int x, char *msg, int flag)
-{- USED(p);
- USED(x);
- USED(msg);
- USED(flag);
- return 0;
-}
-
void
exhausted(char *s)
{--- a/kern/sysfile.c
+++ b/kern/sysfile.c
@@ -18,8 +18,6 @@
#undef fstat
#undef fwstat
#undef iounit
-#undef validaddr
-#define validaddr(a, b, c)
/*
* The sys*() routines needn't poperror() as they return directly to syscall().
@@ -205,18 +203,16 @@
_syspipe(int fd[2])
{Chan *c[2];
- Dev *d;
static char *datastr[] = {"data", "data1"};- d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0);- c[1] = 0;
+ c[1] = nil;
fd[0] = -1;
fd[1] = -1;
if(waserror()){cclose(c[0]);
- if(c[1])
+ if(c[1] != nil)
cclose(c[1]);
nexterror();
}
@@ -225,8 +221,8 @@
error(Egreg);
if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
error(Egreg);
- c[0] = d->open(c[0], ORDWR);
- c[1] = d->open(c[1], ORDWR);
+ c[0] = devtab[c[0]->type]->open(c[0], ORDWR);
+ c[1] = devtab[c[1]->type]->open(c[1], ORDWR);
if(newfd2(fd, c) < 0)
error(Enofd);
poperror();
@@ -295,8 +291,8 @@
return fd;
}
-void
-fdclose(int fd, int flag)
+static void
+_fdclose(int fd, int flag)
{int i;
Chan *c;
@@ -328,7 +324,7 @@
_sysclose(int fd)
{fdtochan(fd, -1, 0, 0);
- fdclose(fd, 0);
+ _fdclose(fd, 0);
return 0;
}
@@ -591,7 +587,7 @@
uint l;
l = n;
- validaddr((uintptr)buf, l, 1);
+ validaddr(buf, l, 1);
c = fdtochan(fd, -1, 0, 1);
if(waserror()) {cclose(c);
@@ -610,8 +606,8 @@
uint l;
l = n;
- validaddr((uintptr)buf, l, 1);
- validaddr((uintptr)name, 1, 0);
+ validaddr(buf, l, 1);
+ validaddr(name, 1, 0);
c = namec(name, Aaccess, 0, 0);
if(waserror()){cclose(c);
@@ -628,7 +624,7 @@
{Chan *c;
- validaddr((uintptr)name, 1, 0);
+ validaddr(name, 1, 0);
c = namec(name, Atodir, 0, 0);
cclose(up->dot);
@@ -698,7 +694,7 @@
poperror();
cclose(c0);
if(ismount){- fdclose(fd, 0);
+ _fdclose(fd, 0);
poperror();
free(spec);
}
@@ -722,7 +718,7 @@
{Chan *cmount, *cmounted;
- cmounted = 0;
+ cmounted = nil;
cmount = namec(new, Amount, 0, 0);
@@ -731,14 +727,8 @@
cclose(cmount);
nexterror();
}
- validaddr((uintptr)old, 1, 0);
- /*
- * This has to be namec(..., Aopen, ...) because
- * if arg[0] is something like /srv/cs or /fd/0,
- * opening it is the only way to get at the real
- * Chan underneath.
- */
- cmounted = namec(old, Aopen, OREAD, 0);
+ validaddr(old, 1, 0);
+ cmounted = namec(old, Aunmount, OREAD, 0);
poperror();
}
@@ -769,7 +759,7 @@
cclose(c);
nexterror();
}
- validaddr((uintptr)name, 1, 0);
+ validaddr(name, 1, 0);
c = namec(name, Acreate, mode, perm);
fd = newfd(c);
if(fd < 0)
@@ -808,7 +798,7 @@
l = n;
validstat(buf, l);
- validaddr((uintptr)name, 1, 0);
+ validaddr(name, 1, 0);
c = namec(name, Aaccess, 0, 0);
if(waserror()){cclose(c);
@@ -827,7 +817,7 @@
uint l;
l = n;
- validaddr((uintptr)buf, l, 0);
+ validaddr(buf, l, 0);
validstat(buf, l);
c = fdtochan(fd, -1, 1, 1);
if(waserror()) {@@ -851,6 +841,8 @@
{assert(up->nerrlab == 1);
poperror();
+
+ up->notepending = 0; /* theres no popnote */
}
static void
@@ -1253,4 +1245,17 @@
sysgetpid(void)
{return up->pid;
+}
+
+void*
+sysgetkproc(void)
+{+ return (void*)up;
+}
+
+void
+syskprocint(void *p)
+{+ if(p != nil)
+ procinterrupt((Proc*)p);
}
--- a/kern/sysproc.c
+++ b/kern/sysproc.c
@@ -34,7 +34,7 @@
w = sizeof mask[0] * 8;
for(p = devs; *p != '\0';){p += chartorune(&r, p);
- t = devno(r, 1);
+ t = devno(r);
if(t == -1)
continue;
if(invert)
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -11,6 +11,7 @@
convM2S.$O\
convS2M.$O\
ctime.$O\
+ crypt.$O\
dial.$O\
dirfstat.$O\
dirfwstat.$O\
@@ -40,6 +41,8 @@
netmkaddr.$O\
nsec.$O\
pow10.$O\
+ pushssl.$O\
+ pushtls.$O\
read9pmsg.$O\
readn.$O\
rune.$O\
--- /dev/null
+++ b/libc/crypt.c
@@ -1,0 +1,67 @@
+/*
+ * Data Encryption Standard
+ * D.P.Mitchell 83/06/08.
+ *
+ * block_cipher(key, block, decrypting)
+ *
+ * these routines use the non-standard 7 byte format
+ * for DES keys.
+ */
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+
+/*
+ * destructively encrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+encrypt(void *key, void *vbuf, int n)
+{+ ulong ekey[32];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ for(i = 0; i < n; i++){+ block_cipher(ekey, buf, 0);
+ buf += 7;
+ }
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 0);
+ return 1;
+}
+
+/*
+ * destructively decrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+decrypt(void *key, void *vbuf, int n)
+{+ ulong ekey[128];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ buf += n * 7;
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 1);
+ for(i = 0; i < n; i++){+ buf -= 7;
+ block_cipher(ekey, buf, 1);
+ }
+ return 1;
+}
--- a/libc/fmt.c
+++ b/libc/fmt.c
@@ -64,9 +64,6 @@
0, 0,
};
-
-int (*fmtdoquote)(int);
-
/*
* __fmtlock() must be set
*/
--- a/libc/fmtquote.c
+++ b/libc/fmtquote.c
@@ -2,6 +2,16 @@
#include <libc.h>
#include "fmtdef.h"
+static int
+fmtdoquote(int c)
+{+ if(c <= ' ')
+ return 1;
+ if(utfrune("`^#*[]=|\\?${}()'<>&;", c))+ return 1;
+ return 0;
+}
+
/*
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
* How many runes? How much of the input will be consumed?
@@ -51,7 +61,7 @@
break;
}
- if((c <= L' ') || (c == L'\'') || (fmtdoquote!=0 && fmtdoquote(c))){+ if((c <= L' ') || (c == L'\'') || fmtdoquote(c)){ if(!q->quoted){ if(runesout){if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
--- /dev/null
+++ b/libc/pushssl.c
@@ -1,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+
+/*
+ * Since the SSL device uses decimal file descriptors to name channels,
+ * it is impossible for a user-level file server to stand in for the kernel device.
+ * Thus we hard-code #D rather than use /net/ssl.
+ */
+
+int
+pushssl(int fd, char *alg, char *secin, char *secout, int *cfd)
+{+ char buf[8];
+ char dname[64];
+ int n, data, ctl;
+
+ ctl = open("#D/ssl/clone", ORDWR);+ if(ctl < 0)
+ return -1;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0)
+ goto error;
+ buf[n] = 0;
+ sprint(dname, "#D/ssl/%s/data", buf);
+ data = open(dname, ORDWR);
+ if(data < 0)
+ goto error;
+ if(fprint(ctl, "fd %d", fd) < 0 ||
+ fprint(ctl, "secretin %s", secin) < 0 ||
+ fprint(ctl, "secretout %s", secout) < 0 ||
+ fprint(ctl, "alg %s", alg) < 0){+ close(data);
+ goto error;
+ }
+ close(fd);
+ if(cfd != 0)
+ *cfd = ctl;
+ else
+ close(ctl);
+ return data;
+error:
+ close(ctl);
+ return -1;
+}
--- /dev/null
+++ b/libc/pushtls.c
@@ -1,0 +1,99 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <mp.h>
+#include <libsec.h>
+
+enum {+ TLSFinishedLen = 12,
+ HFinished = 20,
+};
+
+static int
+finished(int hand, int isclient)
+{+ int i, n;
+ uchar buf[500], buf2[500];
+
+ buf[0] = HFinished;
+ buf[1] = TLSFinishedLen>>16;
+ buf[2] = TLSFinishedLen>>8;
+ buf[3] = TLSFinishedLen;
+ n = TLSFinishedLen+4;
+
+ for(i=0; i<2; i++){+ if(i==0)
+ memmove(buf+4, "client finished", TLSFinishedLen);
+ else
+ memmove(buf+4, "server finished", TLSFinishedLen);
+ if(isclient == 1-i){+ if(write(hand, buf, n) != n)
+ return -1;
+ }else{+ if(readn(hand, buf2, n) != n || memcmp(buf,buf2,n) != 0)
+ return -1;
+ }
+ }
+ return 1;
+}
+
+
+// given a plain fd and secrets established beforehand, return encrypted connection
+int
+pushtls(int fd, char *hashalg, char *encalg, int isclient, char *secret, char *dir)
+{+ char buf[8];
+ char dname[64];
+ int n, data, ctl, hand;
+
+ // open a new filter; get ctl fd
+ data = hand = -1;
+ // /net/tls uses decimal file descriptors to name channels, hence a
+ // user-level file server can't stand in for #a; may as well hard-code it.
+ ctl = open("#a/tls/clone", ORDWR);+ if(ctl < 0)
+ goto error;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0)
+ goto error;
+ buf[n] = 0;
+ if(dir)
+ sprint(dir, "#a/tls/%s", buf);
+
+ // get application fd
+ sprint(dname, "#a/tls/%s/data", buf);
+ data = open(dname, ORDWR);
+ if(data < 0)
+ goto error;
+
+ // get handshake fd
+ sprint(dname, "#a/tls/%s/hand", buf);
+ hand = open(dname, ORDWR);
+ if(hand < 0)
+ goto error;
+
+ // speak a minimal handshake
+ if(fprint(ctl, "fd %d 0x301", fd) < 0 ||
+ fprint(ctl, "version 0x301") < 0 ||
+ fprint(ctl, "secret %s %s %d %s", hashalg, encalg, isclient, secret) < 0 ||
+ fprint(ctl, "changecipher") < 0 ||
+ finished(hand, isclient) < 0 ||
+ fprint(ctl, "opened") < 0){+ close(hand);
+ hand = -1;
+ goto error;
+ }
+ close(ctl);
+ close(hand);
+ close(fd);
+ return data;
+
+error:
+ if(data>=0)
+ close(data);
+ if(ctl>=0)
+ close(ctl);
+ if(hand>=0)
+ close(hand);
+ return -1;
+}
--- a/libdraw/Makefile
+++ b/libdraw/Makefile
@@ -14,7 +14,9 @@
icossin.$O\
icossin2.$O\
rectclip.$O\
- rgb.$O
+ rgb.$O\
+ warp.$O\
+ mkwarp.$O
default: $(LIB)
$(LIB): $(OFILES)
--- a/libdraw/alloc.c
+++ b/libdraw/alloc.c
@@ -2,10 +2,10 @@
#include <libc.h>
#include <draw.h>
-Img*
+Image*
allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col)
{- Img *i;
+ Image *i;
i = _allocimage(nil, d, r, chan, repl, col, 0, 0);
if(i != nil)
@@ -13,12 +13,12 @@
return i;
}
-Img*
-_allocimage(Img *ai, Display *d, Rectangle r, ulong chan, int repl, ulong col, int screenid, int refresh)
+Image*
+_allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong col, int screenid, int refresh)
{uchar *a;
char *err;
- Img *i;
+ Image *i;
Rectangle clipr;
int id;
int depth;
@@ -80,7 +80,7 @@
if(ai != nil)
i = ai;
else{- i = malloc(sizeof(Img));
+ i = malloc(sizeof(Image));
if(i == nil){a = bufimage(d, 1+4);
if(a != nil){@@ -103,12 +103,12 @@
return i;
}
-Img*
+Image*
namedimage(Display *d, char *name)
{uchar *a;
char *err, buf[12*12+1];
- Img *i;
+ Image *i;
int id, n;
ulong chan;
@@ -144,7 +144,7 @@
goto Error;
buf[12*12] = '\0';
- i = malloc(sizeof(Img));
+ i = malloc(sizeof(Image));
if(i == nil){Error1:
a = bufimage(d, 1+4);
@@ -178,7 +178,7 @@
}
int
-nameimage(Img *i, char *name, int in)
+nameimage(Image *i, char *name, int in)
{uchar *a;
int n;
@@ -198,11 +198,11 @@
}
int
-_freeimage1(Img *i)
+_freeimage1(Image *i)
{uchar *a;
Display *d;
- Img *w;
+ Image *w;
if(i == nil || i->display == nil)
return 0;
@@ -233,7 +233,7 @@
}
int
-freeimage(Img *i)
+freeimage(Image *i)
{int ret;
--- a/libdraw/bytesperline.c
+++ b/libdraw/bytesperline.c
@@ -6,19 +6,9 @@
int
unitsperline(Rectangle r, int d, int bitsperunit)
{- ulong l, t;
-
if(d <= 0 || d > 32) /* being called wrong. d is image depth. */
abort();
-
- if(r.min.x >= 0){- l = (r.max.x*d+bitsperunit-1)/bitsperunit;
- l -= (r.min.x*d)/bitsperunit;
- }else{ /* make positive before divide */- t = (-r.min.x*d+bitsperunit-1)/bitsperunit;
- l = t+(r.max.x*d+bitsperunit-1)/bitsperunit;
- }
- return l;
+ return (r.max.x*d - (r.min.x*d & -bitsperunit) + bitsperunit - 1) / bitsperunit;
}
int
--- a/libdraw/icossin2.c
+++ b/libdraw/icossin2.c
@@ -227,6 +227,7 @@
{int sinsign, cossign, tan, tan10, rem;
short *stp, *ctp;
+ uint ux, uy;
if(x == 0){if(y >= 0)
@@ -238,19 +239,23 @@
sinsign = cossign = 1;
if(x < 0){cossign = -1;
- x = -x;
+ ux = -x;
+ } else {+ ux = x;
}
if(y < 0){sinsign = -1;
- y = -y;
+ uy = -y;
+ } else {+ uy = y;
}
- if(y > x){- tan = 1000*x/y;
+ if(uy > ux){+ tan = 1000*(uvlong)ux/uy;
tan10 = tan/10;
stp = &cosinus[tan10];
ctp = &sinus[tan10];
}else{- tan = 1000*y/x;
+ tan = 1000*(uvlong)uy/ux;
tan10 = tan/10;
stp = &sinus[tan10];
ctp = &cosinus[tan10];
--- /dev/null
+++ b/libdraw/mkwarp.c
@@ -1,0 +1,24 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+typedef double Matrix[3][3];
+
+void invm(Matrix);
+
+/* 25.7 fixed-point number operations */
+
+#define flt2fix(n) ((long)((n)*(1<<7) + ((n) < 0? -0.5: 0.5)))
+
+void
+mkwarp(Warp w, double m0[3][3])
+{+ Matrix m;
+
+ memmove(m, m0, sizeof(Matrix));
+ invm(m);
+
+ w[0][0] = flt2fix(m[0][0]); w[0][1] = flt2fix(m[0][1]); w[0][2] = flt2fix(m[0][2]);
+ w[1][0] = flt2fix(m[1][0]); w[1][1] = flt2fix(m[1][1]); w[1][2] = flt2fix(m[1][2]);
+ w[2][0] = 0; w[2][1] = 0; w[2][2] = 1<<7;
+}
--- /dev/null
+++ b/libdraw/warp.c
@@ -1,0 +1,37 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+static void
+putwarp(uchar *a, Warp w)
+{+ BPLONG(a+0*3*4+0*4, w[0][0]); BPLONG(a+0*3*4+1*4, w[0][1]); BPLONG(a+0*3*4+2*4, w[0][2]);
+ BPLONG(a+1*3*4+0*4, w[1][0]); BPLONG(a+1*3*4+1*4, w[1][1]); BPLONG(a+1*3*4+2*4, w[1][2]);
+ BPLONG(a+2*3*4+0*4, w[2][0]); BPLONG(a+2*3*4+1*4, w[2][1]); BPLONG(a+2*3*4+2*4, w[2][2]);
+}
+
+void
+affinewarp(Image *dst, Rectangle r, Image *src, Point p, Warp w, int smooth)
+{+ uchar *a;
+
+ if(dst == nil || src == nil)
+ return;
+
+ a = bufimage(dst->display, 1+4+4*4+4+2*4+3*3*4+1);
+ if(a == nil){+ fprint(2, "affinewarp: %r\n");
+ return;
+ }
+ a[0] = 'a';
+ BPLONG(a+1, dst->id);
+ BPLONG(a+5, r.min.x);
+ BPLONG(a+9, r.min.y);
+ BPLONG(a+13, r.max.x);
+ BPLONG(a+17, r.max.y);
+ BPLONG(a+21, src->id);
+ BPLONG(a+25, p.x);
+ BPLONG(a+29, p.y);
+ putwarp(a+33, w);
+ a[33+3*3*4] = smooth;
+}
--- a/libmemdraw/Makefile
+++ b/libmemdraw/Makefile
@@ -21,7 +21,8 @@
string.$O\
subfont.$O\
unload.$O\
- write.$O
+ write.$O\
+ warp.$O
default: $(LIB)
$(LIB): $(OFILES)
--- a/libmemdraw/alloc.c
+++ b/libmemdraw/alloc.c
@@ -26,7 +26,6 @@
allocmemimaged(Rectangle r, ulong chan, Memdata *md)
{int d;
- ulong l;
Memimage *i;
if((d = chantodepth(chan)) == 0) {@@ -38,21 +37,15 @@
return nil;
}
- l = wordsperline(r, d);
-
i = mallocz(sizeof(Memimage), 1);
if(i == nil)
return nil;
i->data = md;
- i->zero = sizeof(ulong)*l*r.min.y;
-
- if(r.min.x >= 0)
- i->zero += (r.min.x*d)/8;
- else
- i->zero -= (-r.min.x*d+7)/8;
+ i->width = wordsperline(r, d);
+ i->zero = r.min.y*(int)(sizeof(ulong)*i->width) + ((r.min.x*d) >> 3);
i->zero = -i->zero;
- i->width = l;
+
i->r = r;
i->clipr = r;
i->flags = 0;
@@ -69,8 +62,8 @@
allocmemimage(Rectangle r, ulong chan)
{int d;
+ ulong nw;
uchar *p;
- ulong l, nw;
Memdata *md;
Memimage *i;
@@ -82,10 +75,8 @@
werrstr("bad rectangle %R", r);return nil;
}
+ nw = wordsperline(r, d)*Dy(r);
- l = wordsperline(r, d);
-
- nw = l*Dy(r);
md = malloc(sizeof(Memdata));
if(md == nil)
return nil;
@@ -143,23 +134,8 @@
uchar*
byteaddr(Memimage *i, Point p)
{- uchar *a;
-
- a = i->data->bdata+i->zero+(int)(sizeof(ulong)*p.y*i->width);
- if(i->depth < 8){- /*
- * We need to always round down,
- * but C rounds toward zero.
- */
- int np;
- np = 8/i->depth;
- if(p.x < 0)
- return a+(p.x-np+1)/np;
- else
- return a+p.x/np;
- }
- else
- return a+p.x*(i->depth/8);
+ uchar *a = i->data->bdata+i->zero;
+ return a + p.y*(int)(sizeof(ulong)*i->width) + ((p.x*i->depth) >> 3);
}
int
--- /dev/null
+++ b/libmemdraw/warp.c
@@ -1,0 +1,849 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
+#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
+
+/* 25.7 fixed-point number operations */
+
+#define FMASK ((1<<7) - 1)
+#define flt2fix(n) ((long)((n)*(1<<7) + ((n) < 0? -0.5: 0.5)))
+#define fix2flt(n) ((n)/128.0)
+#define int2fix(n) ((vlong)(n)<<7)
+#define fix2int(n) ((n)>>7)
+#define fixmul(a,b) ((vlong)(a)*(vlong)(b) >> 7)
+#define fixdiv(a,b) (((vlong)(a) << 7)/(vlong)(b))
+#define fixfrac(n) ((n)&FMASK)
+#define lerp(a,b,t) ((a) + ((((b) - (a))*(t))>>7))
+
+#define clamp(a,b,c) ((a)<(b)?(b):((a)>(c)?(c):(a)))
+
+typedef struct Sampler Sampler;
+typedef struct Blitter Blitter;
+
+struct Sampler
+{+ Memimage *i;
+ uchar *a;
+ Rectangle r;
+ int bpl;
+ int cmask;
+ long Δx, Δy;
+ Memimage *k; /* filtering kernel */
+ Point kcp; /* kernel center point */
+ ulong (*fn)(Sampler*, Point);
+};
+
+struct Blitter
+{+ Memimage *i;
+ uchar *a;
+ int bpl;
+ int cmask;
+ void (*fn)(Blitter*, Point, ulong);
+};
+
+static void *getsampfn(ulong);
+static void *getblitfn(ulong);
+
+static void
+initsampler(Sampler *s, Memimage *i)
+{+ s->i = i;
+ s->a = i->data->bdata + i->zero;
+ s->bpl = sizeof(ulong)*i->width;
+ s->cmask = (1ULL << i->depth) - 1;
+ s->fn = getsampfn(i->chan);
+}
+
+static void
+initblitter(Blitter *b, Memimage *i)
+{+ b->i = i;
+ b->a = i->data->bdata + i->zero;
+ b->bpl = sizeof(ulong)*i->width;
+ b->cmask = (1ULL << i->depth) - 1;
+ b->fn = getblitfn(i->chan);
+}
+
+static Point
+xform(Point p, Warp m)
+{+ return (Point){+ fixmul(p.x, m[0][0]) + fixmul(p.y, m[0][1]) + m[0][2],
+ fixmul(p.x, m[1][0]) + fixmul(p.y, m[1][1]) + m[1][2]
+ };
+}
+
+static ulong
+getpixel_k1(Sampler *s, Point pt)
+{+ uchar *p;
+ ulong off, npack, v;
+
+ p = s->a + pt.y*s->bpl + (pt.x >> 3);
+ npack = 8;
+ off = pt.x % npack;
+ v = p[0] >> (npack-1-off) & 0x1;
+ return v*0xFFFFFF00 | 0xFF;
+}
+
+static ulong
+getpixel_k2(Sampler *s, Point pt)
+{+ uchar *p, v;
+ ulong off, npack;
+
+ p = s->a + pt.y*s->bpl + (pt.x*2 >> 3);
+ npack = 8/2;
+ off = pt.x % npack;
+ v = p[0] >> 2*(npack-1-off) & 0x3;
+ return v*0x55555500 | 0xFF;
+}
+
+static ulong
+getpixel_k4(Sampler *s, Point pt)
+{+ uchar *p, v;
+ ulong off, npack;
+
+ p = s->a + pt.y*s->bpl + (pt.x*4 >> 3);
+ npack = 8/4;
+ off = pt.x % npack;
+ v = p[0] >> 4*(npack-1-off) & 0xF;
+ return v*0x11111100 | 0xFF;
+}
+
+static ulong
+getpixel_k8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x;
+ return p[0]*0x01010100 | 0xFF;
+}
+
+static ulong
+getpixel_m8(Sampler *s, Point pt)
+{+ uchar *p, m;
+
+ p = s->a + pt.y*s->bpl + pt.x;
+ m = p[0];
+ p = s->i->cmap->cmap2rgb+3*m;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|0xFF;
+}
+
+static ulong
+getpixel_x1r5g5b5(Sampler *s, Point pt)
+{+ uchar *p, r, g, b;
+ ulong val;
+
+ p = s->a + pt.y*s->bpl + pt.x*2;
+ val = p[0]|(p[1]<<8);
+ b = val&0x1F; b = (b<<3)|(b>>2);
+ val >>= 5;
+ g = val&0x1F; g = (g<<3)|(g>>2);
+ val >>= 5;
+ r = val&0x1F; r = (r<<3)|(r>>2);
+ return (r<<24)|(g<<16)|(b<<8)|0xFF;
+}
+
+static ulong
+getpixel_r5g6b5(Sampler *s, Point pt)
+{+ uchar *p, r, g, b;
+ ulong val;
+
+ p = s->a + pt.y*s->bpl + pt.x*2;
+ val = p[0]|(p[1]<<8);
+ b = val&0x1F; b = (b<<3)|(b>>2);
+ val >>= 5;
+ g = val&0x3F; g = (g<<2)|(g>>4);
+ val >>= 6;
+ r = val&0x1F; r = (r<<3)|(r>>2);
+ return (r<<24)|(g<<16)|(b<<8)|0xFF;
+}
+
+static ulong
+getpixel_r8g8b8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*3;
+ return (p[2]<<24)|(p[1]<<16)|(p[0]<<8)|0xFF;
+}
+
+static ulong
+getpixel_r8g8b8a8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*4;
+ return (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0];
+}
+
+static ulong
+getpixel_a8r8g8b8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*4;
+ return (p[2]<<24)|(p[1]<<16)|(p[0]<<8)|p[3];
+}
+
+static ulong
+getpixel_x8r8g8b8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*4;
+ return (p[2]<<24)|(p[1]<<16)|(p[0]<<8)|0xFF;
+}
+
+static ulong
+getpixel_b8g8r8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*3;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|0xFF;
+}
+
+static ulong
+getpixel_a8b8g8r8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*4;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+}
+
+static ulong
+getpixel_x8b8g8r8(Sampler *s, Point pt)
+{+ uchar *p;
+
+ p = s->a + pt.y*s->bpl + pt.x*4;
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|0xFF;
+}
+
+static ulong
+getpixel(Sampler *s, Point pt)
+{+ uchar *p, r, g, b, a;
+ ulong val, chan, ctype, ov, v;
+ int nb, off, bpp, npack;
+
+ val = 0;
+ a = 0xFF;
+ r = g = b = 0xAA; /* garbage */
+ p = s->a + pt.y*s->bpl + (pt.x*s->i->depth >> 3);
+
+ /* pixelbits() */
+ switch(bpp = s->i->depth){+ case 1:
+ case 2:
+ case 4:
+ npack = 8/bpp;
+ off = pt.x%npack;
+ val = p[0] >> bpp*(npack-1-off);
+ val &= s->cmask;
+ break;
+ case 8:
+ val = p[0];
+ break;
+ case 16:
+ val = p[0]|(p[1]<<8);
+ break;
+ case 24:
+ val = p[0]|(p[1]<<8)|(p[2]<<16);
+ break;
+ case 32:
+ val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+ break;
+ }
+
+ while(bpp < 32){+ val |= val<<bpp;
+ bpp *= 2;
+ }
+
+ /* imgtorgba() */
+ for(chan = s->i->chan; chan; chan >>= 8){+ if((ctype = TYPE(chan)) == CIgnore){+ val >>= s->i->nbits[ctype];
+ continue;
+ }
+ nb = s->i->nbits[ctype];
+ ov = v = val & s->i->mask[ctype];
+ val >>= nb;
+
+ while(nb < 8){+ v |= v<<nb;
+ nb *= 2;
+ }
+ v >>= nb-8;
+
+ switch(ctype){+ case CRed:
+ r = v;
+ break;
+ case CGreen:
+ g = v;
+ break;
+ case CBlue:
+ b = v;
+ break;
+ case CAlpha:
+ a = v;
+ break;
+ case CGrey:
+ r = g = b = v;
+ break;
+ case CMap:
+ p = s->i->cmap->cmap2rgb+3*ov;
+ r = p[0];
+ g = p[1];
+ b = p[2];
+ break;
+ }
+ }
+ return (r<<24)|(g<<16)|(b<<8)|a;
+}
+
+static void
+putpixel_k1(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, m;
+ int off, npack, sh, mask;
+
+ p = blt->a + dp.y*blt->bpl + (dp.x >> 3);
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ m = RGB2K(r,g,b);
+ m >>= 8-1;
+
+ mask = 0x1;
+ npack = 8;
+ off = dp.x%npack;
+ sh = npack-1-off;
+ mask <<= sh;
+ m <<= sh;
+ p[0] = (p[0] ^ m) & mask ^ p[0];
+}
+
+static void
+putpixel_k2(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, m;
+ int off, npack, sh, mask;
+
+ p = blt->a + dp.y*blt->bpl + (dp.x*2 >> 3);
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ m = RGB2K(r,g,b);
+ m >>= 8-2;
+
+ mask = 0x3;
+ npack = 8/2;
+ off = dp.x%npack;
+ sh = 2*(npack-1-off);
+ mask <<= sh;
+ m <<= sh;
+ p[0] = (p[0] ^ m) & mask ^ p[0];
+}
+
+static void
+putpixel_k4(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, m;
+ int off, npack, sh, mask;
+
+ p = blt->a + dp.y*blt->bpl + (dp.x*4 >> 3);
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ m = RGB2K(r,g,b);
+ m >>= 8-4;
+
+ mask = 0xF;
+ npack = 8/4;
+ off = dp.x%npack;
+ sh = 4*(npack-1-off);
+ mask <<= sh;
+ m <<= sh;
+ p[0] = (p[0] ^ m) & mask ^ p[0];
+}
+
+static void
+putpixel_k8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, m;
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ m = RGB2K(r,g,b);
+ p = blt->a + dp.y*blt->bpl + dp.x;
+ p[0] = m;
+}
+
+static void
+putpixel_m8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, m;
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ m = blt->i->cmap->rgb2cmap[(r>>4)*256+(g>>4)*16+(b>>4)];
+ p = blt->a + dp.y*blt->bpl + dp.x;
+ p[0] = m;
+}
+
+static void
+putpixel_x1r5g5b5(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b;
+ ushort v;
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ v = r>>(8-5);
+ v = (v<<5)|(g>>(8-5));
+ v = (v<<5)|(b>>(8-5));
+ p = blt->a + dp.y*blt->bpl + dp.x*2;
+ p[0] = v;
+ p[1] = v>>8;
+}
+
+static void
+putpixel_r5g6b5(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b;
+ ushort v;
+
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ v = r>>(8-5);
+ v = (v<<6)|(g>>(8-6));
+ v = (v<<5)|(b>>(8-5));
+ p = blt->a + dp.y*blt->bpl + dp.x*2;
+ p[0] = v;
+ p[1] = v>>8;
+}
+
+static void
+putpixel_r8g8b8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*3;
+ p[0] = rgba>>8;
+ p[1] = rgba>>16;
+ p[2] = rgba>>24;
+}
+
+static void
+putpixel_r8g8b8a8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*4;
+ p[0] = rgba;
+ p[1] = rgba>>8;
+ p[2] = rgba>>16;
+ p[3] = rgba>>24;
+}
+
+static void
+putpixel_a8r8g8b8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*4;
+ p[0] = rgba>>8;
+ p[1] = rgba>>16;
+ p[2] = rgba>>24;
+ p[3] = rgba;
+}
+
+static void
+putpixel_x8r8g8b8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*4;
+ p[0] = rgba>>8;
+ p[1] = rgba>>16;
+ p[2] = rgba>>24;
+}
+
+static void
+putpixel_b8g8r8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*3;
+ p[0] = rgba>>24;
+ p[1] = rgba>>16;
+ p[2] = rgba>>8;
+}
+
+static void
+putpixel_a8b8g8r8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*4;
+ p[0] = rgba>>24;
+ p[1] = rgba>>16;
+ p[2] = rgba>>8;
+ p[3] = rgba;
+}
+
+static void
+putpixel_x8b8g8r8(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p;
+
+ p = blt->a + dp.y*blt->bpl + dp.x*4;
+ p[0] = rgba>>24;
+ p[1] = rgba>>16;
+ p[2] = rgba>>8;
+}
+
+static void
+putpixel(Blitter *blt, Point dp, ulong rgba)
+{+ uchar *p, r, g, b, a, m;
+ ulong chan, ov, v;
+ int off, npack, sh, mask;
+
+ p = blt->a + dp.y*blt->bpl + (dp.x*blt->i->depth >> 3);
+
+ /* rgbatoimg() */
+ v = 0;
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ a = rgba;
+ for(chan=blt->i->chan; chan; chan>>=8){+ switch(TYPE(chan)){+ case CIgnore:
+ continue;
+ case CRed:
+ v |= (r>>(8-blt->i->nbits[CRed])) << blt->i->shift[CRed];
+ break;
+ case CGreen:
+ v |= (g>>(8-blt->i->nbits[CGreen])) << blt->i->shift[CGreen];
+ break;
+ case CBlue:
+ v |= (b>>(8-blt->i->nbits[CBlue])) << blt->i->shift[CBlue];
+ break;
+ case CAlpha:
+ v |= (a>>(8-blt->i->nbits[CAlpha])) << blt->i->shift[CAlpha];
+ break;
+ case CMap:
+ m = blt->i->cmap->rgb2cmap[(r>>4)*256+(g>>4)*16+(b>>4)];
+ v |= (m>>(8-blt->i->nbits[CMap])) << blt->i->shift[CMap];
+ break;
+ case CGrey:
+ m = RGB2K(r,g,b);
+ v |= (m>>(8-blt->i->nbits[CGrey])) << blt->i->shift[CGrey];
+ break;
+ }
+ }
+
+ /* blit op */
+ ov = p[0]|p[1]<<8|p[2]<<16|p[3]<<24;
+
+ mask = blt->cmask;
+ if(blt->i->depth < 8){+ npack = 8/blt->i->depth;
+ off = dp.x%npack;
+ sh = blt->i->depth*(npack-1-off);
+ mask <<= sh;
+ v <<= sh;
+ }
+ v = (ov ^ v) & mask ^ ov; /* ≡ (ov &~ mask) | (v & mask) */
+ p[0] = v;
+ p[1] = v>>8;
+ p[2] = v>>16;
+ p[3] = v>>24;
+}
+
+static void *
+getsampfn(ulong chan)
+{+ switch(chan){+ case GREY1: return getpixel_k1;
+ case GREY2: return getpixel_k2;
+ case GREY4: return getpixel_k4;
+ case GREY8: return getpixel_k8;
+ case CMAP8: return getpixel_m8;
+ case RGB15: return getpixel_x1r5g5b5;
+ case RGB16: return getpixel_r5g6b5;
+ case RGB24: return getpixel_r8g8b8;
+ case RGBA32: return getpixel_r8g8b8a8;
+ case ARGB32: return getpixel_a8r8g8b8;
+ case XRGB32: return getpixel_x8r8g8b8;
+ case BGR24: return getpixel_b8g8r8;
+ case ABGR32: return getpixel_a8b8g8r8;
+ case XBGR32: return getpixel_x8b8g8r8;
+ }
+ return getpixel;
+}
+
+static void *
+getblitfn(ulong chan)
+{+ switch(chan){+ case GREY1: return putpixel_k1;
+ case GREY2: return putpixel_k2;
+ case GREY4: return putpixel_k4;
+ case GREY8: return putpixel_k8;
+ case CMAP8: return putpixel_m8;
+ case RGB15: return putpixel_x1r5g5b5;
+ case RGB16: return putpixel_r5g6b5;
+ case RGB24: return putpixel_r8g8b8;
+ case RGBA32: return putpixel_r8g8b8a8;
+ case ARGB32: return putpixel_a8r8g8b8;
+ case XRGB32: return putpixel_x8r8g8b8;
+ case BGR24: return putpixel_b8g8r8;
+ case ABGR32: return putpixel_a8b8g8r8;
+ case XBGR32: return putpixel_x8b8g8r8;
+ }
+ return putpixel;
+}
+
+static ulong
+sample1(Sampler *s, Point p)
+{+ if(p.x >= s->r.min.x && p.x < s->r.max.x
+ && p.y >= s->r.min.y && p.y < s->r.max.y)
+ return s->fn(s, p);
+ else if(s->i->flags & Frepl){+ p = drawrepl(s->r, p);
+ return s->fn(s, p);
+ }
+ /* edge handler: constant */
+ return 0;
+}
+
+static ulong
+bilinear(Sampler *s, Point p)
+{+ ulong c00, c01, c10, c11;
+ uchar c0₀, c0₁, c0₂, c0₃, c1₀, c1₁, c1₂, c1₃;
+
+ c00 = sample1(s, p);
+ p.x++;
+ c01 = sample1(s, p);
+ p.x--; p.y++;
+ c10 = sample1(s, p);
+ p.x++;
+ c11 = sample1(s, p);
+
+ c0₀ = c00>>24;
+ c0₁ = c00>>16;
+ c0₂ = c00>>8;
+ c0₃ = c00;
+ c1₀ = c10>>24;
+ c1₁ = c10>>16;
+ c1₂ = c10>>8;
+ c1₃ = c10;
+ c0₀ = lerp(c0₀, c01>>24 & 0xFF, s->Δx);
+ c0₁ = lerp(c0₁, c01>>16 & 0xFF, s->Δx);
+ c0₂ = lerp(c0₂, c01>>8 & 0xFF, s->Δx);
+ c0₃ = lerp(c0₃, c01 & 0xFF, s->Δx);
+ c1₀ = lerp(c1₀, c11>>24 & 0xFF, s->Δx);
+ c1₁ = lerp(c1₁, c11>>16 & 0xFF, s->Δx);
+ c1₂ = lerp(c1₂, c11>>8 & 0xFF, s->Δx);
+ c1₃ = lerp(c1₃, c11 & 0xFF, s->Δx);
+ return (lerp(c0₀, c1₀, s->Δy)) << 24
+ | (lerp(c0₁, c1₁, s->Δy)) << 16
+ | (lerp(c0₂, c1₂, s->Δy)) << 8
+ | (lerp(c0₃, c1₃, s->Δy));
+}
+
+static ulong
+correlate(Sampler *s, Point p)
+{+ Point sp;
+ int r, g, b, a, Σr, Σg, Σb, Σa;
+ long *kp, kv;
+ ulong v;
+
+ kp = (long*)(s->k->data->bdata + s->k->zero);
+ Σr = Σg = Σb = Σa = 0;
+
+ for(sp.y = 0; sp.y < s->k->r.max.y; sp.y++)
+ for(sp.x = 0; sp.x < s->k->r.max.x; sp.x++){+ v = sample1(s, addpt(p, subpt(sp, s->kcp)));
+ r = v>>24 & 0xFF; r = int2fix(r);
+ g = v>>16 & 0xFF; g = int2fix(g);
+ b = v>>8 & 0xFF; b = int2fix(b);
+ a = v>>0 & 0xFF; a = int2fix(a);
+
+ kv = kp[sp.y*s->k->r.max.x + sp.x];
+ r = fixmul(r, kv);
+ g = fixmul(g, kv);
+ b = fixmul(b, kv);
+ a = fixmul(a, kv);
+
+ Σr += r; Σg += g; Σb += b; Σa += a;
+ }
+ r = clamp(fix2int(Σr), 0, 0xFF);
+ g = clamp(fix2int(Σg), 0, 0xFF);
+ b = clamp(fix2int(Σb), 0, 0xFF);
+ a = clamp(fix2int(Σa), 0, 0xFF);
+
+ return r<<24|g<<16|b<<8|a;
+}
+
+int
+memaffinewarp(Memimage *d, Rectangle r, Memimage *s, Point sp0, Warp m, int smooth)
+{+ ulong (*sample)(Sampler*, Point) = sample1;
+ Sampler samp;
+ Blitter blit;
+ Point sp, dp, p2, p2₀;
+ Rectangle dr;
+ ulong c;
+
+ dr = d->clipr;
+ rectclip(&dr, d->r);
+ if(rectclip(&r, dr) == 0)
+ return 0;
+
+ samp.r = s->clipr;
+ if(rectclip(&samp.r, s->r) == 0)
+ return 0;
+
+ if(smooth)
+ sample = bilinear;
+
+ initsampler(&samp, s);
+ initblitter(&blit, d);
+
+ /*
+ * incremental affine warping technique from:
+ * “Fast Affine Transform for Real-Time Machine Vision Applications”,
+ * Lee, S., Lee, GG., Jang, E.S., Kim, WY,
+ * Intelligent Computing. ICIC 2006. LNCS, vol 4113.
+ */
+ p2 = p2₀ = xform((Point){int2fix(r.min.x - dr.min.x) + (1<<6), int2fix(r.min.y - dr.min.y) + (1<<6)}, m);+ for(dp.y = r.min.y; dp.y < r.max.y; dp.y++){+ for(dp.x = r.min.x; dp.x < r.max.x; dp.x++){+ samp.Δx = fixfrac(p2.x);
+ samp.Δy = fixfrac(p2.y);
+
+ sp.x = sp0.x + fix2int(p2.x);
+ sp.y = sp0.y + fix2int(p2.y);
+
+ c = sample(&samp, sp);
+ blit.fn(&blit, dp, c);
+
+ p2.x += m[0][0];
+ p2.y += m[1][0];
+ }
+ p2.x = p2₀.x += m[0][1];
+ p2.y = p2₀.y += m[1][1];
+ }
+ return 0;
+}
+
+static double
+coeffsum(double *m, int len)
+{+ double *e, Σ;
+
+ e = m + len;
+ Σ = 0;
+ while(m < e)
+ Σ += *m++;
+ return Σ;
+}
+
+Memimage *
+allocmemimagekernel(double *k, int dx, int dy, double denom)
+{+ Memimage *ik;
+ long *kern;
+ double t;
+ int x, y;
+
+ ik = allocmemimage(Rect(0,0,dx,dy), RGBA32); /* any 32-bit depth chan would do */
+ if(ik == nil){+ werrstr("could not allocate image kernel: %r");+ return nil;
+ }
+
+ if(denom == 0)
+ denom = coeffsum(k, dx*dy);
+ denom = denom? 1/denom: 1;
+
+ kern = (long*)(ik->data->bdata + ik->zero);
+ for(y = 0; y < dy; y++)
+ for(x = 0; x < dx; x++){+ t = k[y*dx + x];
+ t *= denom;
+ kern[y*dx + x] = flt2fix(t);
+ }
+
+ return ik;
+}
+
+int
+memimagecorrelate(Memimage *d, Rectangle r, Memimage *s, Point sp0, Memimage *k)
+{+ Sampler samp;
+ Blitter blit;
+ Point sp, dp;
+ Rectangle dr;
+ ulong c;
+
+ dr = d->clipr;
+ rectclip(&dr, d->r);
+ if(rectclip(&r, dr) == 0)
+ return 0;
+
+ samp.r = s->clipr;
+ if(rectclip(&samp.r, s->r) == 0)
+ return 0;
+
+ initsampler(&samp, s);
+ initblitter(&blit, d);
+
+ if(k == nil){+ werrstr("kernel image is nil");+ return -1;
+ }
+ if(k->depth != 32){+ werrstr("kernel image depth is not 32");+ return -1;
+ }
+ samp.k = k;
+ samp.kcp = Pt(Dx(k->r)/2, Dy(k->r)/2);
+
+ for(dp.y = r.min.y; dp.y < r.max.y; dp.y++)
+ for(dp.x = r.min.x; dp.x < r.max.x; dp.x++){+ sp.x = sp0.x + dp.x - dr.min.x;
+ sp.y = sp0.y + dp.y - dr.min.y;
+ c = correlate(&samp, sp);
+ blit.fn(&blit, dp, c);
+ }
+ return 0;
+}
--- a/libmemlayer/draw.c
+++ b/libmemlayer/draw.c
@@ -121,7 +121,7 @@
tr.min.x = srcr.min.x;
}
if(srcr.min.y < tr.min.y){- p1.y += tr.min.x - srcr.min.x;
+ p1.y += tr.min.y - srcr.min.y;
tr.min.y = srcr.min.y;
}
if(srcr.max.x > tr.max.x)
--- a/libsec/tlshand.c
+++ b/libsec/tlshand.c
@@ -404,6 +404,7 @@
static void* emalloc(int);
static void* erealloc(void*, int);
+static void put32(uchar *p, u32int);
static void put24(uchar *p, int);
static void put16(uchar *p, int);
static int get24(uchar *p);
@@ -2903,6 +2904,15 @@
sysfatal("out of memory");setrealloctag(ReallocP, getcallerpc(&ReallocP));
return(ReallocP);
+}
+
+static void
+put32(uchar *p, u32int x)
+{+ p[0] = x>>24;
+ p[1] = x>>16;
+ p[2] = x>>8;
+ p[3] = x;
}
static void
--
⑨