| // $ emcc -o richards.html -O2 -s TOTAL_MEMORY=83886080 -g1 -s "EXPORTED_FUNCTIONS=[_setup, _getHoldcount, _scheduleIter, _getQpktcount, _main]" ./richards.c |
| |
| #include <emscripten.h> |
| |
| /* C version of the systems programming language benchmark |
| ** Author: M. J. Jordan Cambridge Computer Laboratory. |
| ** |
| ** Modified by: M. Richards, Nov 1996 |
| ** to be ANSI C and runnable on 64 bit machines + other minor changes |
| ** Modified by: M. Richards, 20 Oct 1998 |
| ** made minor corrections to improve ANSI compliance (suggested |
| ** by David Levine) |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #if 1 |
| #define Count 10000*100 |
| #define Qpktcountval 2326410 |
| #define Holdcountval 930563 |
| #endif |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| #define MAXINT 32767 |
| |
| #define BUFSIZE 3 |
| #define I_IDLE 1 |
| #define I_WORK 2 |
| #define I_HANDLERA 3 |
| #define I_HANDLERB 4 |
| #define I_DEVA 5 |
| #define I_DEVB 6 |
| #define PKTBIT 1 |
| #define WAITBIT 2 |
| #define HOLDBIT 4 |
| #define NOTPKTBIT !1 |
| #define NOTWAITBIT !2 |
| #define NOTHOLDBIT 0XFFFB |
| |
| #define S_RUN 0 |
| #define S_RUNPKT 1 |
| #define S_WAIT 2 |
| #define S_WAITPKT 3 |
| #define S_HOLD 4 |
| #define S_HOLDPKT 5 |
| #define S_HOLDWAIT 6 |
| #define S_HOLDWAITPKT 7 |
| |
| #define K_DEV 1000 |
| #define K_WORK 1001 |
| |
| struct packet |
| { |
| struct packet *p_link; |
| int p_id; |
| int p_kind; |
| int p_a1; |
| char p_a2[BUFSIZE+1]; |
| }; |
| |
| struct task |
| { |
| struct task *t_link; |
| int t_id; |
| int t_pri; |
| struct packet *t_wkq; |
| int t_state; |
| struct task *(*t_fn)(struct packet *); |
| long t_v1; |
| long t_v2; |
| }; |
| |
| char alphabet[28] = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| struct task *tasktab[11] = {(struct task *)10,0,0,0,0,0,0,0,0,0,0}; |
| struct task *tasklist = 0; |
| struct task *tcb; |
| long taskid; |
| long v1; |
| long v2; |
| int qpktcount = 0; |
| int holdcount = 0; |
| int tracing = 0; |
| int layout = 0; |
| |
| void append(struct packet *pkt, struct packet *ptr); |
| |
| void createtask(int id, |
| int pri, |
| struct packet *wkq, |
| int state, |
| struct task *(*fn)(struct packet *), |
| long v1, |
| long v2) |
| { |
| struct task *t = (struct task *)malloc(sizeof(struct task)); |
| |
| tasktab[id] = t; |
| t->t_link = tasklist; |
| t->t_id = id; |
| t->t_pri = pri; |
| t->t_wkq = wkq; |
| t->t_state = state; |
| t->t_fn = fn; |
| t->t_v1 = v1; |
| t->t_v2 = v2; |
| tasklist = t; |
| } |
| |
| struct packet *pkt(struct packet *link, int id, int kind) |
| { |
| int i; |
| struct packet *p = (struct packet *)malloc(sizeof(struct packet)); |
| |
| for (i=0; i<=BUFSIZE; i++) |
| p->p_a2[i] = 0; |
| |
| p->p_link = link; |
| p->p_id = id; |
| p->p_kind = kind; |
| p->p_a1 = 0; |
| |
| return (p); |
| } |
| |
| void trace(char a) |
| { |
| if ( --layout <= 0 ) |
| { |
| layout = 50; |
| } |
| |
| } |
| |
| int scheduleIter() |
| { |
| if (tcb == 0) |
| return 0; |
| |
| { |
| struct packet *pkt; |
| struct task *newtcb; |
| |
| pkt=0; |
| |
| switch ( tcb->t_state ) |
| { |
| case S_WAITPKT: |
| pkt = tcb->t_wkq; |
| tcb->t_wkq = pkt->p_link; |
| tcb->t_state = tcb->t_wkq == 0 ? S_RUN : S_RUNPKT; |
| |
| case S_RUN: |
| case S_RUNPKT: |
| taskid = tcb->t_id; |
| v1 = tcb->t_v1; |
| v2 = tcb->t_v2; |
| if (tracing) { |
| trace(taskid+'0'); |
| } |
| newtcb = (*(tcb->t_fn))(pkt); |
| tcb->t_v1 = v1; |
| tcb->t_v2 = v2; |
| tcb = newtcb; |
| break; |
| |
| case S_WAIT: |
| case S_HOLD: |
| case S_HOLDPKT: |
| case S_HOLDWAIT: |
| case S_HOLDWAITPKT: |
| tcb = tcb->t_link; |
| break; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| return 1; |
| } |
| |
| struct task *wait(void) |
| { |
| tcb->t_state |= WAITBIT; |
| return (tcb); |
| } |
| |
| struct task *holdself(void) |
| { |
| ++holdcount; |
| tcb->t_state |= HOLDBIT; |
| return (tcb->t_link) ; |
| } |
| |
| struct task *findtcb(int id) |
| { |
| struct task *t = 0; |
| |
| if (1<=id && id<=(long)tasktab[0]) |
| t = tasktab[id]; |
| return(t); |
| } |
| |
| struct task *release(int id) |
| { |
| struct task *t; |
| |
| t = findtcb(id); |
| if ( t==0 ) return (0); |
| |
| t->t_state &= NOTHOLDBIT; |
| if ( t->t_pri > tcb->t_pri ) return (t); |
| |
| return (tcb) ; |
| } |
| |
| |
| struct task *qpkt(struct packet *pkt) |
| { |
| struct task *t; |
| |
| t = findtcb(pkt->p_id); |
| if (t==0) return (t); |
| |
| qpktcount++; |
| |
| pkt->p_link = 0; |
| pkt->p_id = taskid; |
| |
| if (t->t_wkq==0) |
| { |
| t->t_wkq = pkt; |
| t->t_state |= PKTBIT; |
| if (t->t_pri > tcb->t_pri) return (t); |
| } |
| else |
| { |
| append(pkt, (struct packet *)&(t->t_wkq)); |
| } |
| |
| return (tcb); |
| } |
| |
| struct task *idlefn(struct packet *pkt) |
| { |
| if ( --v2==0 ) return ( holdself() ); |
| |
| if ( (v1&1) == 0 ) |
| { |
| v1 = ( v1>>1) & MAXINT; |
| return ( release(I_DEVA) ); |
| } |
| else |
| { |
| v1 = ( (v1>>1) & MAXINT) ^ 0XD008; |
| return ( release(I_DEVB) ); |
| } |
| } |
| |
| struct task *workfn(struct packet *pkt) |
| { |
| if ( pkt==0 ) return ( wait() ); |
| else |
| { |
| int i; |
| |
| v1 = I_HANDLERA + I_HANDLERB - v1; |
| pkt->p_id = v1; |
| |
| pkt->p_a1 = 0; |
| for (i=0; i<=BUFSIZE; i++) |
| { |
| v2++; |
| if ( v2 > 26 ) v2 = 1; |
| (pkt->p_a2)[i] = alphabet[v2]; |
| } |
| return ( qpkt(pkt) ); |
| } |
| } |
| |
| struct task *handlerfn(struct packet *pkt) |
| { |
| if ( pkt!=0) { |
| append(pkt, (struct packet *)(pkt->p_kind==K_WORK ? &v1 : &v2)); |
| } |
| |
| if ( v1!=0 ) { |
| int count; |
| struct packet *workpkt = (struct packet *)v1; |
| count = workpkt->p_a1; |
| |
| if ( count > BUFSIZE ) { |
| v1 = (long)(((struct packet *)v1)->p_link); |
| return ( qpkt(workpkt) ); |
| } |
| |
| if ( v2!=0 ) { |
| struct packet *devpkt; |
| |
| devpkt = (struct packet *)v2; |
| v2 = (long)(((struct packet *)v2)->p_link); |
| devpkt->p_a1 = workpkt->p_a2[count]; |
| workpkt->p_a1 = count+1; |
| return( qpkt(devpkt) ); |
| } |
| } |
| return wait(); |
| } |
| |
| struct task *devfn(struct packet *pkt) |
| { |
| if ( pkt==0 ) |
| { |
| if ( v1==0 ) return ( wait() ); |
| pkt = (struct packet *)v1; |
| v1 = 0; |
| return ( qpkt(pkt) ); |
| } |
| else |
| { |
| v1 = (long)pkt; |
| if (tracing) trace(pkt->p_a1); |
| return ( holdself() ); |
| } |
| } |
| |
| void append(struct packet *pkt, struct packet *ptr) |
| { |
| pkt->p_link = 0; |
| |
| while ( ptr->p_link ) ptr = ptr->p_link; |
| |
| ptr->p_link = pkt; |
| } |
| |
| void setup() |
| { |
| struct packet *wkq = 0; |
| |
| createtask(I_IDLE, 0, wkq, S_RUN, idlefn, 1, Count); |
| |
| wkq = pkt(0, 0, K_WORK); |
| wkq = pkt(wkq, 0, K_WORK); |
| |
| createtask(I_WORK, 1000, wkq, S_WAITPKT, workfn, I_HANDLERA, 0); |
| |
| wkq = pkt(0, I_DEVA, K_DEV); |
| wkq = pkt(wkq, I_DEVA, K_DEV); |
| wkq = pkt(wkq, I_DEVA, K_DEV); |
| |
| createtask(I_HANDLERA, 2000, wkq, S_WAITPKT, handlerfn, 0, 0); |
| |
| wkq = pkt(0, I_DEVB, K_DEV); |
| wkq = pkt(wkq, I_DEVB, K_DEV); |
| wkq = pkt(wkq, I_DEVB, K_DEV); |
| |
| createtask(I_HANDLERB, 3000, wkq, S_WAITPKT, handlerfn, 0, 0); |
| |
| wkq = 0; |
| createtask(I_DEVA, 4000, wkq, S_WAIT, devfn, 0, 0); |
| createtask(I_DEVB, 5000, wkq, S_WAIT, devfn, 0, 0); |
| |
| tcb = tasklist; |
| |
| qpktcount = holdcount = 0; |
| |
| tracing = FALSE; |
| layout = 0; |
| } |
| |
| int getQpktcount() |
| { |
| return qpktcount; |
| } |
| |
| int getHoldcount() |
| { |
| return holdcount; |
| } |
| |
| int main() |
| { |
| EM_ASM( runRichards() ); |
| |
| return 0; |
| } |
| |