mirror of
https://github.com/aap/pdp6.git
synced 2026-02-07 17:01:50 +00:00
lots of additions and changes
This commit is contained in:
@@ -477,6 +477,8 @@ cpu_printflags(void)
|
||||
|
||||
void fe_svc(void) {}
|
||||
|
||||
void initcrt(const char *host) {}
|
||||
|
||||
void
|
||||
init6(void)
|
||||
{
|
||||
|
||||
105
fe6/6/real6.c
105
fe6/6/real6.c
@@ -81,12 +81,17 @@ enum
|
||||
REG6_PTR = 035,
|
||||
REG6_PTR_LT = 036,
|
||||
REG6_PTR_RT = 037,
|
||||
|
||||
REG6_DIS1 = 040,
|
||||
REG6_DIS2 = 041,
|
||||
REG6_DIS3 = 042,
|
||||
};
|
||||
|
||||
enum {
|
||||
FEREG_REQ = 0,
|
||||
FEREG_PTR,
|
||||
FEREG_PTP
|
||||
FEREG_PTP,
|
||||
FEREG_DIS
|
||||
};
|
||||
|
||||
|
||||
@@ -106,6 +111,7 @@ static volatile u32 *h2f_cmemif, *h2f_cmemif2;
|
||||
static volatile u32 *h2f_fmemif, *h2f_fmemif2;
|
||||
static volatile u32 *h2f_apr;
|
||||
static volatile u32 *h2f_fe;
|
||||
static volatile u32 *h2f_csl;
|
||||
static volatile u32 *h2f_lw_led_addr;
|
||||
static volatile u32 *h2f_lw_sw_addr;
|
||||
|
||||
@@ -137,13 +143,16 @@ deposit(hword a, word w)
|
||||
h2f_fmemif[1] = w & RT;
|
||||
h2f_fmemif[2] = (w >> 18) & RT;
|
||||
}else if(a < 01000020){
|
||||
void dep64(u32, u64);
|
||||
if(0 && a < 01000){
|
||||
printf("dep %o %llo\r\n", a, w);
|
||||
fflush(stdout);
|
||||
}
|
||||
// dep64(a, w);
|
||||
|
||||
h2f_cmemif[0] = a & RT;
|
||||
h2f_cmemif[1] = w & RT;
|
||||
h2f_cmemif[2] = (w >> 18) & RT;
|
||||
}else if(a >= 02000000){
|
||||
h2f_cmemif2[0] = a & 01777777;
|
||||
h2f_cmemif2[1] = w & RT;
|
||||
h2f_cmemif2[2] = (w >> 18) & RT;
|
||||
}else switch(a){
|
||||
case APR_DS:
|
||||
h2f_apr[REG6_DSLT] = w>>18 & RT;
|
||||
@@ -179,6 +188,8 @@ deposit(hword a, word w)
|
||||
*h2f_lw_led_addr = w;
|
||||
break;
|
||||
}
|
||||
|
||||
// usleep(5);
|
||||
}
|
||||
|
||||
word
|
||||
@@ -217,15 +228,13 @@ examine(hword a)
|
||||
w <<= 18;
|
||||
w |= h2f_fmemif[1] & RT;
|
||||
}else if(a < 01000020){
|
||||
//u64 ex64(u32);
|
||||
// w = ex64(a);
|
||||
|
||||
h2f_cmemif[0] = a & RT;
|
||||
w = h2f_cmemif[2] & RT;
|
||||
w <<= 18;
|
||||
w |= h2f_cmemif[1] & RT;
|
||||
}else if(a >= 02000000){
|
||||
h2f_cmemif2[0] = a & 01777777;
|
||||
w = h2f_cmemif2[2] & RT;
|
||||
w <<= 18;
|
||||
w |= h2f_cmemif2[1] & RT;
|
||||
}else switch(a){
|
||||
case APR_DS:
|
||||
w = h2f_apr[REG6_DSLT];
|
||||
@@ -556,6 +565,33 @@ prflags(const char *fmt, u8 flags)
|
||||
l[!!(flags&02)], l[!!(flags&01)]);
|
||||
}
|
||||
|
||||
void
|
||||
prdis(void)
|
||||
{
|
||||
u32 dis1, dis2, dis3;
|
||||
dis1 = h2f_apr[REG6_DIS1];
|
||||
dis2 = h2f_apr[REG6_DIS2];
|
||||
dis3 = h2f_apr[REG6_DIS3];
|
||||
printf("\r\nDIS\r\n");
|
||||
printf("BR/%06o\r\n", dis1);
|
||||
printf("X/%04o Y/%04o BRM/%03o S/%02o I/%o SZ/%o MODE/%o\r\n",
|
||||
dis2&01777, (dis2>>10)&01777, (dis2>>20)&0177,
|
||||
(dis3>>8)&017, (dis3>>5)&7, (dis3>>3)&3, dis3&7);
|
||||
printf("DATA REQ/%o STOP/%o EDGE/%o LP/%o LP ON/%o LP FIND/%o\r\n",
|
||||
!!(dis3 & 04000000),
|
||||
!!(dis3 & 0400000),
|
||||
!!(dis3 & 02000000),
|
||||
!!(dis3 & 040000),
|
||||
!!(dis3 & 020000),
|
||||
!!(dis3 & 010000));
|
||||
printf("MOVE/%o HALT/%o\r\n",
|
||||
!!(dis3 & 0200000),
|
||||
!!(dis3 & 0100000));
|
||||
|
||||
dis3 = h2f_apr[REG6_DIS3+1];
|
||||
printf("%X\r\n", dis3);
|
||||
}
|
||||
|
||||
void
|
||||
cpu_printflags(void)
|
||||
{
|
||||
@@ -589,6 +625,8 @@ cpu_printflags(void)
|
||||
printf("RUN/%o MEM STOP/%o\r\n",
|
||||
!!(ctl1 & MM6_RUN), !!(ctl1 & MM6_MCSTOP));
|
||||
|
||||
prdis();
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
@@ -628,6 +666,25 @@ fflush(stdout);
|
||||
write(fd, &c, 1);
|
||||
}
|
||||
|
||||
int dis_fd = -1;
|
||||
|
||||
static void
|
||||
svc_dis(void)
|
||||
{
|
||||
u32 pnt;
|
||||
pnt = h2f_fe[FEREG_DIS];
|
||||
if((pnt & 0x80000000) == 0)
|
||||
return;
|
||||
if(dis_fd >= 0)
|
||||
write(dis_fd, &pnt, 4);
|
||||
/*
|
||||
else{
|
||||
printf("%X\r\n", pnt);
|
||||
fflush(stdout);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
fe_svc(void)
|
||||
{
|
||||
@@ -637,8 +694,30 @@ fe_svc(void)
|
||||
|
||||
if(req & 1) svc_ptr();
|
||||
if(req & 2) svc_ptp();
|
||||
// if(req & 4) svc_dis();
|
||||
svc_dis();
|
||||
}
|
||||
|
||||
void*
|
||||
wcsl_thread(void *arg)
|
||||
{
|
||||
u32 ctl;
|
||||
while(readn(dis_fd, &ctl, 4) == 0){
|
||||
// printf("%o\r\n", ctl);
|
||||
// fflush(stdout);
|
||||
h2f_csl[ctl>>24] = ctl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initcrt(const char *host)
|
||||
{
|
||||
dis_fd = dial(host, 3400);
|
||||
if(dis_fd >= 0){
|
||||
printf("display connected\n");
|
||||
threadcreate(wcsl_thread, nil);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init6(void)
|
||||
@@ -668,11 +747,17 @@ init6(void)
|
||||
h2f_fmemif = getLWH2Faddr(0x10010);
|
||||
h2f_fmemif2 = getLWH2Faddr(0x20010);
|
||||
|
||||
// enable sdram bridge (???)
|
||||
*(u32*)((u8*)virtual_base + 0x5080) = 0xFFFF;
|
||||
|
||||
h2f_apr = getLWH2Faddr(0x10100);
|
||||
h2f_fe = getLWH2Faddr(0x20000);
|
||||
h2f_csl = getLWH2Faddr(0x30000);
|
||||
h2f_lw_sw_addr = getLWH2Faddr(0x10020);
|
||||
h2f_lw_led_addr = getLWH2Faddr(0x10040);
|
||||
|
||||
|
||||
// testshit();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
11
fe6/Makefile
11
fe6/Makefile
@@ -1,21 +1,22 @@
|
||||
XX=/u/aap/de0-nano-soc/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
|
||||
CFLAGS=-DTEST
|
||||
LDFLAGS=-lpthread
|
||||
|
||||
SRC=fe.c cmd.c util.c pdp6common.c
|
||||
SRC=fe.c cmd.c util.c netmem.c pdp6common.c threading.c
|
||||
|
||||
all: fe6_emu fe6_fake fe6 feka
|
||||
clean:
|
||||
rm fe6_emu fe6_fake fe6
|
||||
|
||||
fe6: $(SRC) 6/real6.c
|
||||
$(XX)gcc -I6 $(CFLAGS) -o $@ $^
|
||||
$(XX)gcc -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
fe6_fake: $(SRC) fake.c
|
||||
$(CC) -I6 $(CFLAGS) -o $@ $^
|
||||
$(CC) -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
fe6_emu: $(SRC) 6/emu6.c
|
||||
$(CC) -I6 $(CFLAGS) -o $@ $^
|
||||
$(CC) -I6 $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
|
||||
feka: $(SRC) ka/real.c
|
||||
$(XX)gcc -Ika $(CFLAGS) -o $@ $^
|
||||
$(XX)gcc -Ika $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
@@ -114,8 +114,9 @@ sblk:
|
||||
|
||||
chk = (chk<<1 | chk>>35) + w & FW;
|
||||
|
||||
if(d)
|
||||
if(d){
|
||||
deposit(right(iowd), w);
|
||||
}
|
||||
iowd += 01000001;
|
||||
}
|
||||
if(readwits(fp) != chk)
|
||||
|
||||
@@ -188,6 +188,8 @@ cpu_printflags(void)
|
||||
|
||||
void fe_svc(void) {}
|
||||
|
||||
void initcrt(const char *host) {}
|
||||
|
||||
void
|
||||
init6(void)
|
||||
{
|
||||
|
||||
16
fe6/fe.c
16
fe6/fe.c
@@ -87,6 +87,7 @@ enum {
|
||||
MODE_ASCII,
|
||||
MODE_SIXBIT,
|
||||
MODE_SQUOZE,
|
||||
MODE_FLOAT,
|
||||
|
||||
/* flags */
|
||||
CF = 1, // one altmode
|
||||
@@ -404,6 +405,7 @@ prword(int mode, word wd)
|
||||
int i;
|
||||
char c;
|
||||
char s[7];
|
||||
double f;
|
||||
|
||||
switch(mode){
|
||||
case MODE_ASCII:
|
||||
@@ -453,6 +455,12 @@ prword(int mode, word wd)
|
||||
typenum((wd>>18)&0777777);
|
||||
break;
|
||||
|
||||
case MODE_FLOAT:
|
||||
f = pdptod(wd);
|
||||
printf("%lf", f);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
default:
|
||||
typenum(wd);
|
||||
}
|
||||
@@ -553,12 +561,14 @@ quit(void)
|
||||
int started;
|
||||
|
||||
int
|
||||
main()
|
||||
threadmain(int argc, char *argv[])
|
||||
{
|
||||
char chu;
|
||||
word t;
|
||||
|
||||
init6();
|
||||
initcrt("soma");
|
||||
// initnetmem("10.0.0.222", 10006);
|
||||
|
||||
raw(0);
|
||||
erasec = tiosaved.c_cc[VERASE];
|
||||
@@ -603,6 +613,7 @@ main()
|
||||
typestr("/ ");
|
||||
t = examine(t);
|
||||
prword(MODE_SYM, t);
|
||||
q = t;
|
||||
typestr(" ");
|
||||
|
||||
started = 0;
|
||||
@@ -898,6 +909,9 @@ main()
|
||||
case '=':
|
||||
typeout(MODE_NUM);
|
||||
break;
|
||||
case ';':
|
||||
typeout(MODE_FLOAT);
|
||||
break;
|
||||
case '"':
|
||||
if(flags & CF)
|
||||
modechange(MODE_ASCII);
|
||||
|
||||
7
fe6/fe.h
7
fe6/fe.h
@@ -5,6 +5,7 @@
|
||||
#include <ctype.h>
|
||||
#include "util.h"
|
||||
#include "pdp6common.h"
|
||||
#include "threading.h"
|
||||
|
||||
#define nil NULL
|
||||
|
||||
@@ -18,7 +19,8 @@ typedef uint8_t u8;
|
||||
#define FW (LT|RT)
|
||||
#define F0 0400000000000
|
||||
|
||||
#define MAXMEM (16*1024)
|
||||
//#define MAXMEM (16*1024)
|
||||
#define MAXMEM (256*1024)
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
@@ -83,5 +85,8 @@ void cpu_printflags(void);
|
||||
|
||||
void fe_svc(void);
|
||||
|
||||
void initcrt(const char *host);
|
||||
void initnetmem(const char *host, int port);
|
||||
|
||||
void init6(void);
|
||||
void deinit6(void);
|
||||
|
||||
@@ -96,7 +96,8 @@ enum
|
||||
enum {
|
||||
FEREG_REQ = 0,
|
||||
FEREG_PTR,
|
||||
FEREG_PTP
|
||||
FEREG_PTP,
|
||||
FEREG_DIS
|
||||
};
|
||||
|
||||
|
||||
@@ -116,6 +117,7 @@ static volatile u32 *h2f_cmemif;
|
||||
static volatile u32 *h2f_fmemif;
|
||||
static volatile u32 *h2f_apr;
|
||||
static volatile u32 *h2f_fe;
|
||||
static volatile u32 *h2f_csl;
|
||||
|
||||
void
|
||||
deposit(hword a, word w)
|
||||
@@ -661,6 +663,23 @@ fflush(stdout);
|
||||
write(fd, &c, 1);
|
||||
}
|
||||
|
||||
int dis_fd;
|
||||
|
||||
static void
|
||||
svc_dis(void)
|
||||
{
|
||||
u32 pnt;
|
||||
pnt = h2f_fe[FEREG_DIS];
|
||||
if((pnt & 0x80000000) == 0)
|
||||
return;
|
||||
if(dis_fd >= 0)
|
||||
write(dis_fd, &pnt, 4);
|
||||
else{
|
||||
printf("%X\r\n", pnt);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fe_svc(void)
|
||||
{
|
||||
@@ -670,8 +689,30 @@ fe_svc(void)
|
||||
|
||||
if(req & 1) svc_ptr();
|
||||
if(req & 2) svc_ptp();
|
||||
// if(req & 4) svc_dis();
|
||||
svc_dis();
|
||||
}
|
||||
|
||||
void*
|
||||
wcsl_thread(void *arg)
|
||||
{
|
||||
u32 ctl;
|
||||
while(readn(dis_fd, &ctl, 4) == 0){
|
||||
// printf("%o\r\n", ctl);
|
||||
// fflush(stdout);
|
||||
h2f_csl[ctl>>24] = ctl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initcrt(const char *host)
|
||||
{
|
||||
dis_fd = dial(host, 3400);
|
||||
if(dis_fd >= 0){
|
||||
printf("display connected\n");
|
||||
threadcreate(wcsl_thread, nil);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init6(void)
|
||||
@@ -699,6 +740,7 @@ init6(void)
|
||||
h2f_fmemif = getLWH2Faddr(0x10010);
|
||||
h2f_apr = getLWH2Faddr(0x10100);
|
||||
h2f_fe = getLWH2Faddr(0x20000);
|
||||
h2f_csl = getLWH2Faddr(0x30000);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
81
fe6/netmem.c
Normal file
81
fe6/netmem.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "fe.h"
|
||||
#include <unistd.h>
|
||||
|
||||
int netmemfd = -1;
|
||||
|
||||
enum
|
||||
{
|
||||
WRRQ = 1,
|
||||
RDRQ = 2,
|
||||
ACK = 3,
|
||||
ERR = 4,
|
||||
};
|
||||
|
||||
void*
|
||||
netmemthread(void *arg)
|
||||
{
|
||||
u16 len;
|
||||
word a, d;
|
||||
u8 buf[9];
|
||||
|
||||
while(readn(netmemfd, buf, 2) == 0){
|
||||
len = buf[0]<<8 | buf[1];
|
||||
if(len > 9){
|
||||
fprintf(stderr, "netmem botch(%d), closing\n", len);
|
||||
close(netmemfd);
|
||||
netmemfd = -1;
|
||||
return nil;
|
||||
}
|
||||
memset(buf, 0, sizeof(buf));
|
||||
readn(netmemfd, buf, len);
|
||||
|
||||
a = buf[1] | buf[2]<<8 | buf[3]<<16;
|
||||
d = buf[4] | buf[5]<<8 | buf[6]<<16 |
|
||||
(word)buf[7]<<24 | (word)buf[8]<<32;
|
||||
a &= 0777777;
|
||||
d &= 0777777777777;
|
||||
|
||||
switch(buf[0]){
|
||||
case WRRQ:
|
||||
deposit(a, d);
|
||||
printf("write %06lo %012lo\r\n", a, d);
|
||||
fflush(stdout);
|
||||
buf[0] = 0;
|
||||
buf[1] = 1;
|
||||
buf[2] = ACK;
|
||||
writen(netmemfd, buf, buf[1]+2);
|
||||
break;
|
||||
case RDRQ:
|
||||
d = examine(a);
|
||||
printf("read %06lo %012lo\r\n", a, d);
|
||||
fflush(stdout);
|
||||
buf[0] = 0;
|
||||
buf[1] = 6;
|
||||
buf[2] = ACK;
|
||||
buf[3] = d;
|
||||
buf[4] = d>>8;
|
||||
buf[5] = d>>16;
|
||||
buf[6] = d>>24;
|
||||
buf[7] = d>>32;
|
||||
writen(netmemfd, buf, buf[1]+2);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown netmem message %d\n", buf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "netmem fd closed\n");
|
||||
netmemfd = -1;
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
initnetmem(const char *host, int port)
|
||||
{
|
||||
netmemfd = dial(host, port);
|
||||
if(netmemfd >= 0){
|
||||
printf("netmem connected\n");
|
||||
threadcreate(netmemthread, nil);
|
||||
}
|
||||
}
|
||||
|
||||
361
fe6/threading.c
Normal file
361
fe6/threading.c
Normal file
@@ -0,0 +1,361 @@
|
||||
#include "threading.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define USED(x) (void)(x)
|
||||
|
||||
/*
|
||||
* Locks
|
||||
*/
|
||||
|
||||
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void
|
||||
lockinit(Lock *lk)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
pthread_mutex_lock(&initmutex);
|
||||
if(lk->init == 0){
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
pthread_mutex_init(&lk->mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
lk->init = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&initmutex);
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *lk)
|
||||
{
|
||||
if(!lk->init)
|
||||
lockinit(lk);
|
||||
if(pthread_mutex_lock(&lk->mutex) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
int
|
||||
canlock(Lock *lk)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(!lk->init)
|
||||
lockinit(lk);
|
||||
r = pthread_mutex_trylock(&lk->mutex);
|
||||
if(r == 0)
|
||||
return 1;
|
||||
if(r == EBUSY)
|
||||
return 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *lk)
|
||||
{
|
||||
if(pthread_mutex_unlock(&lk->mutex) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
rendinit(Rendez *r)
|
||||
{
|
||||
pthread_condattr_t attr;
|
||||
|
||||
pthread_mutex_lock(&initmutex);
|
||||
if(r->init == 0){
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_cond_init(&r->cond, &attr);
|
||||
pthread_condattr_destroy(&attr);
|
||||
r->init = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&initmutex);
|
||||
}
|
||||
|
||||
void
|
||||
rsleep(Rendez *r)
|
||||
{
|
||||
if(!r->init)
|
||||
rendinit(r);
|
||||
if(pthread_cond_wait(&r->cond, &r->l->mutex) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
rwakeup(Rendez *r)
|
||||
{
|
||||
if(!r->init)
|
||||
return;
|
||||
if(pthread_cond_signal(&r->cond) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
rwakeupall(Rendez *r)
|
||||
{
|
||||
if(!r->init)
|
||||
return;
|
||||
if(pthread_cond_broadcast(&r->cond) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Threads
|
||||
*/
|
||||
|
||||
|
||||
static Lock idlock;
|
||||
static pthread_t *threads;
|
||||
static int numthreads;
|
||||
static int maxthreads;
|
||||
|
||||
static __thread int myid;
|
||||
static __thread void *mypointer;
|
||||
|
||||
static int
|
||||
addthreadid(void)
|
||||
{
|
||||
int id;
|
||||
|
||||
if(numthreads >= maxthreads){
|
||||
maxthreads += 64;
|
||||
threads = realloc(threads, maxthreads*sizeof(*threads));
|
||||
}
|
||||
id = numthreads++;
|
||||
threads[id] = 0;
|
||||
return id;
|
||||
}
|
||||
|
||||
static pthread_t
|
||||
gethandle(int id)
|
||||
{
|
||||
pthread_t th;
|
||||
lock(&idlock);
|
||||
th = threads[id];
|
||||
unlock(&idlock);
|
||||
return th;
|
||||
}
|
||||
|
||||
struct ThreadArg
|
||||
{
|
||||
int id;
|
||||
void *(*f)(void*);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void*
|
||||
trampoline(void *p)
|
||||
{
|
||||
struct ThreadArg *args;
|
||||
void *(*f)(void*);
|
||||
void *arg;
|
||||
|
||||
args = p;
|
||||
myid = args->id;
|
||||
f = args->f;
|
||||
arg = args->arg;
|
||||
free(args);
|
||||
return f(arg);
|
||||
}
|
||||
|
||||
int
|
||||
threadcreate(void *(*f)(void*), void *arg)
|
||||
{
|
||||
struct ThreadArg *args;
|
||||
int id;
|
||||
|
||||
lock(&idlock);
|
||||
id = addthreadid();
|
||||
args = malloc(sizeof(*args));
|
||||
args->id = id;
|
||||
args->f = f;
|
||||
args->arg = arg;
|
||||
pthread_create(&threads[id], nil, trampoline, args);
|
||||
unlock(&idlock);
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
threadexits(void *ret)
|
||||
{
|
||||
pthread_exit(ret);
|
||||
}
|
||||
|
||||
int
|
||||
threadid(void)
|
||||
{
|
||||
return myid;
|
||||
}
|
||||
|
||||
void**
|
||||
threaddata(void)
|
||||
{
|
||||
return &mypointer;
|
||||
}
|
||||
|
||||
void
|
||||
threadkill(int id)
|
||||
{
|
||||
assert(id >= 0 && id < numthreads);
|
||||
pthread_cancel(gethandle(id));
|
||||
}
|
||||
|
||||
void
|
||||
threadwait(int id)
|
||||
{
|
||||
pthread_join(gethandle(id), nil);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int id;
|
||||
|
||||
id = addthreadid();
|
||||
threads[id] = pthread_self();
|
||||
return threadmain(argc, argv);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Channels
|
||||
*/
|
||||
|
||||
|
||||
Channel*
|
||||
chancreate(int elemsize, int bufsize)
|
||||
{
|
||||
Channel *c;
|
||||
|
||||
c = malloc(sizeof(Channel) + bufsize*elemsize);
|
||||
if(c == nil)
|
||||
return nil;
|
||||
memset(c, 0, sizeof(Channel));
|
||||
c->elemsize = elemsize;
|
||||
c->bufsize = bufsize;
|
||||
c->nbuf = 0;
|
||||
c->buf = (uchar*)(c+1);
|
||||
c->full.l = &c->lock;
|
||||
c->empty.l = &c->lock;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
chanclose(Channel *c)
|
||||
{
|
||||
lock(&c->lock);
|
||||
c->closed = 1;
|
||||
rwakeupall(&c->full);
|
||||
rwakeupall(&c->empty);
|
||||
unlock(&c->lock);
|
||||
}
|
||||
|
||||
void
|
||||
chanfree(Channel *c)
|
||||
{
|
||||
// TODO: don't free chans still in use
|
||||
free(c);
|
||||
}
|
||||
|
||||
static int cansend(Channel *c) { return c->nbuf < c->bufsize; }
|
||||
static int canrecv(Channel *c) { return c->nbuf > 0; }
|
||||
|
||||
static void
|
||||
chansend_(Channel *c, void *p)
|
||||
{
|
||||
uchar *pp;
|
||||
|
||||
assert(cansend(c));
|
||||
pp = c->buf + (c->off+c->nbuf)%c->bufsize * c->elemsize;
|
||||
memmove(pp, p, c->elemsize);
|
||||
c->nbuf++;
|
||||
}
|
||||
|
||||
static void
|
||||
chanrecv_(Channel *c, void *p)
|
||||
{
|
||||
uchar *pp;
|
||||
|
||||
assert(canrecv(c));
|
||||
pp = c->buf + c->off*c->elemsize;
|
||||
memmove(p, pp, c->elemsize);
|
||||
c->nbuf--;
|
||||
if(++c->off == c->bufsize)
|
||||
c->off = 0;
|
||||
}
|
||||
|
||||
int
|
||||
chansend(Channel *c, void *p)
|
||||
{
|
||||
lock(&c->lock);
|
||||
while(!(c->closed || cansend(c)))
|
||||
rsleep(&c->full);
|
||||
/* closed or can send */
|
||||
if(c->closed){
|
||||
/* can never send to closed chan */
|
||||
unlock(&c->lock);
|
||||
return -1;
|
||||
}
|
||||
chansend_(c, p);
|
||||
rwakeup(&c->empty);
|
||||
unlock(&c->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
chanrecv(Channel *c, void *p)
|
||||
{
|
||||
lock(&c->lock);
|
||||
while(!(c->closed || canrecv(c)))
|
||||
rsleep(&c->empty);
|
||||
/* closed or can receive */
|
||||
if(canrecv(c)){
|
||||
/* can still receive from closed chan */
|
||||
chanrecv_(c, p);
|
||||
rwakeup(&c->full);
|
||||
unlock(&c->lock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&c->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
channbsend(Channel *c, void *p)
|
||||
{
|
||||
lock(&c->lock);
|
||||
if(c->closed){
|
||||
/* can never send to closed chan */
|
||||
unlock(&c->lock);
|
||||
return -1;
|
||||
}
|
||||
if(cansend(c)){
|
||||
chansend_(c, p);
|
||||
rwakeup(&c->empty);
|
||||
unlock(&c->lock);
|
||||
return 1;
|
||||
}
|
||||
unlock(&c->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
channbrecv(Channel *c, void *p)
|
||||
{
|
||||
lock(&c->lock);
|
||||
if(canrecv(c)){
|
||||
/* can still receive from closed chan */
|
||||
chanrecv_(c, p);
|
||||
rwakeup(&c->full);
|
||||
unlock(&c->lock);
|
||||
return 1;
|
||||
}
|
||||
if(c->closed){
|
||||
unlock(&c->lock);
|
||||
return -1;
|
||||
}
|
||||
unlock(&c->lock);
|
||||
return 0;
|
||||
}
|
||||
60
fe6/threading.h
Normal file
60
fe6/threading.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define nil NULL
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef struct Lock Lock;
|
||||
struct Lock
|
||||
{
|
||||
int init;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
void lock(Lock *lk);
|
||||
int canlock(Lock *lk);
|
||||
void unlock(Lock *lk);
|
||||
|
||||
|
||||
typedef struct Rendez Rendez;
|
||||
struct Rendez
|
||||
{
|
||||
int init;
|
||||
Lock *l;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
void rsleep(Rendez *r);
|
||||
void rwakeup(Rendez *r);
|
||||
void rwakeupall(Rendez *r);
|
||||
|
||||
|
||||
typedef struct Channel Channel;
|
||||
struct Channel
|
||||
{
|
||||
int bufsize;
|
||||
int elemsize;
|
||||
uchar *buf;
|
||||
int nbuf;
|
||||
int off;
|
||||
|
||||
int closed;
|
||||
Lock lock;
|
||||
Rendez full, empty;
|
||||
};
|
||||
Channel *chancreate(int elemsize, int bufsize);
|
||||
void chanclose(Channel *chan);
|
||||
void chanfree(Channel *c);
|
||||
int chansend(Channel *c, void *p);
|
||||
int chanrecv(Channel *c, void *p);
|
||||
int channbsend(Channel *c, void *p);
|
||||
int channbrecv(Channel *c, void *p);
|
||||
|
||||
int threadmain(int argc, char *argv[]);
|
||||
int threadcreate(void *(*f)(void*), void *arg);
|
||||
void threadexits(void *ret);
|
||||
int threadid(void);
|
||||
void **threaddata(void);
|
||||
void threadkill(int id);
|
||||
void threadwait(int id);
|
||||
@@ -2,6 +2,8 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
|
||||
Reference in New Issue
Block a user