├── .gitignore ├── 386-ucontext.h ├── COPYRIGHT ├── Makefile ├── README ├── amd64-ucontext.h ├── arm-ucontext.h ├── asm.S ├── channel.c ├── context.c ├── fd.c ├── httpload.c ├── makesun ├── mips-ucontext.h ├── net.c ├── power-ucontext.h ├── primes.c ├── print.c ├── qlock.c ├── rendez.c ├── task.c ├── task.h ├── task.xcodeproj └── project.pbxproj ├── taskimpl.h ├── tcpproxy.c ├── testdelay.c └── testdelay1.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.pbxuser 3 | .DS_Store -------------------------------------------------------------------------------- /386-ucontext.h: -------------------------------------------------------------------------------- 1 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 2 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 3 | typedef struct mcontext mcontext_t; 4 | typedef struct ucontext ucontext_t; 5 | 6 | extern int swapcontext(ucontext_t*, const ucontext_t*); 7 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 8 | extern int getmcontext(mcontext_t*); 9 | extern void setmcontext(const mcontext_t*); 10 | 11 | /*- 12 | * Copyright (c) 1999 Marcel Moolenaar 13 | * All rights reserved. 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions 17 | * are met: 18 | * 1. Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer 20 | * in this position and unchanged. 21 | * 2. Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the distribution. 24 | * 3. The name of the author may not be used to endorse or promote products 25 | * derived from this software without specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 39 | */ 40 | 41 | /* #include */ 42 | 43 | /*- 44 | * Copyright (c) 1999 Marcel Moolenaar 45 | * All rights reserved. 46 | * 47 | * Redistribution and use in source and binary forms, with or without 48 | * modification, are permitted provided that the following conditions 49 | * are met: 50 | * 1. Redistributions of source code must retain the above copyright 51 | * notice, this list of conditions and the following disclaimer 52 | * in this position and unchanged. 53 | * 2. Redistributions in binary form must reproduce the above copyright 54 | * notice, this list of conditions and the following disclaimer in the 55 | * documentation and/or other materials provided with the distribution. 56 | * 3. The name of the author may not be used to endorse or promote products 57 | * derived from this software without specific prior written permission. 58 | * 59 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 60 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 61 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 62 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 63 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 64 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 65 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 66 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 67 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 68 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 69 | * 70 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp $ 71 | */ 72 | 73 | struct mcontext { 74 | /* 75 | * The first 20 fields must match the definition of 76 | * sigcontext. So that we can support sigcontext 77 | * and ucontext_t at the same time. 78 | */ 79 | int mc_onstack; /* XXX - sigcontext compat. */ 80 | int mc_gs; 81 | int mc_fs; 82 | int mc_es; 83 | int mc_ds; 84 | int mc_edi; 85 | int mc_esi; 86 | int mc_ebp; 87 | int mc_isp; 88 | int mc_ebx; 89 | int mc_edx; 90 | int mc_ecx; 91 | int mc_eax; 92 | int mc_trapno; 93 | int mc_err; 94 | int mc_eip; 95 | int mc_cs; 96 | int mc_eflags; 97 | int mc_esp; /* machine state */ 98 | int mc_ss; 99 | 100 | int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ 101 | int __spare__[17]; 102 | }; 103 | 104 | struct ucontext { 105 | /* 106 | * Keep the order of the first two fields. Also, 107 | * keep them the first two fields in the structure. 108 | * This way we can have a union with struct 109 | * sigcontext and ucontext_t. This allows us to 110 | * support them both at the same time. 111 | * note: the union is not defined, though. 112 | */ 113 | sigset_t uc_sigmask; 114 | mcontext_t uc_mcontext; 115 | 116 | struct __ucontext *uc_link; 117 | stack_t uc_stack; 118 | int __spare__[8]; 119 | }; 120 | 121 | 122 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | 2 | This software was developed as part of a project at MIT. 3 | 4 | Copyright (c) 2005-2007 Russ Cox, 5 | Massachusetts Institute of Technology 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | === 27 | 28 | Contains parts of an earlier library that has: 29 | 30 | /* 31 | * The authors of this software are Rob Pike, Sape Mullender, and Russ Cox 32 | * Copyright (c) 2003 by Lucent Technologies. 33 | * Permission to use, copy, modify, and distribute this software for any 34 | * purpose without fee is hereby granted, provided that this entire notice 35 | * is included in all copies of any software which is or includes a copy 36 | * or modification of this software and in all copies of the supporting 37 | * documentation for such software. 38 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 39 | * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY 40 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 41 | * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 42 | */ 43 | 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIB=libtask.a 2 | IPHONE_LIB = libtask-iphone.a 3 | TCPLIBS= 4 | 5 | ASM=asm.o 6 | OFILES=\ 7 | $(ASM)\ 8 | channel.o\ 9 | context.o\ 10 | fd.o\ 11 | net.o\ 12 | print.o\ 13 | qlock.o\ 14 | rendez.o\ 15 | task.o\ 16 | 17 | all: $(LIB) primes tcpproxy testdelay 18 | 19 | $(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h arm-ucontext.h 20 | 21 | AS=gcc -c 22 | CC=gcc 23 | CFLAGS=-Wall -c -I. -ggdb 24 | 25 | %.o: %.S 26 | $(AS) $*.S 27 | 28 | %.o: %.c 29 | $(CC) $(CFLAGS) $*.c 30 | 31 | $(LIB): $(OFILES) 32 | ar rvc $(LIB) $(OFILES) 33 | 34 | primes: primes.o $(LIB) 35 | $(CC) -o primes primes.o $(LIB) 36 | 37 | tcpproxy: tcpproxy.o $(LIB) 38 | $(CC) -o tcpproxy tcpproxy.o $(LIB) $(TCPLIBS) 39 | 40 | httpload: httpload.o $(LIB) 41 | $(CC) -o httpload httpload.o $(LIB) 42 | 43 | testdelay: testdelay.o $(LIB) 44 | $(CC) -o testdelay testdelay.o $(LIB) 45 | 46 | testdelay1: testdelay1.o $(LIB) 47 | $(CC) -o testdelay1 testdelay1.o $(LIB) 48 | 49 | clean: 50 | rm -f *.o primes tcpproxy testdelay testdelay1 httpload $(LIB) $(IPHONE_LIB) 51 | rm -rf build 52 | 53 | install: $(LIB) 54 | cp $(LIB) /usr/local/lib 55 | cp task.h /usr/local/include 56 | 57 | iphone: 58 | xcodebuild -project task.xcodeproj -sdk iphoneos -configuration Release 59 | xcodebuild -project task.xcodeproj -sdk iphonesimulator -configuration Debug 60 | lipo build/Debug-iphonesimulator/libtask.a build/Release-iphoneos/libtask.a -create -output $(IPHONE_LIB) 61 | 62 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Libtask is a simple coroutine library. It runs on Linux (ARM, MIPS, and x86), 2 | FreeBSD (x86), OS X (PowerPC x86, and x86-64), and SunOS Solaris (Sparc), 3 | and is easy to port to other systems. 4 | 5 | Libtask gives the programmer the illusion of threads, but 6 | the operating system sees only a single kernel thread. 7 | For clarity, we refer to the coroutines as "tasks," not threads. 8 | 9 | Scheduling is cooperative. Only one task runs at a time, 10 | and it cannot be rescheduled without explicitly giving up 11 | the CPU. Most of the functions provided in task.h do have 12 | the possibility of going to sleep. Programs using the task 13 | functions should #include . 14 | 15 | --- Basic task manipulation 16 | 17 | int taskcreate(void (*f)(void *arg), void *arg, unsigned int stacksize); 18 | 19 | Create a new task running f(arg) on a stack of size stacksize. 20 | 21 | void tasksystem(void); 22 | 23 | Mark the current task as a "system" task. These are ignored 24 | for the purposes of deciding the program is done running 25 | (see taskexit next). 26 | 27 | void taskexit(int status); 28 | 29 | Exit the current task. If this is the last non-system task, 30 | exit the entire program using the given exit status. 31 | 32 | void taskexitall(int status); 33 | 34 | Exit the entire program, using the given exit status. 35 | 36 | void taskmain(int argc, char *argv[]); 37 | 38 | Write this function instead of main. Libtask provides its own main. 39 | 40 | int taskyield(void); 41 | 42 | Explicitly give up the CPU. The current task will be scheduled 43 | again once all the other currently-ready tasks have a chance 44 | to run. Returns the number of other tasks that ran while the 45 | current task was waiting. (Zero means there are no other tasks 46 | trying to run.) 47 | 48 | int taskdelay(unsigned int ms) 49 | 50 | Explicitly give up the CPU for at least ms milliseconds. 51 | Other tasks continue to run during this time. 52 | 53 | void** taskdata(void); 54 | 55 | Return a pointer to a single per-task void* pointer. 56 | You can use this as a per-task storage place. 57 | 58 | void needstack(int n); 59 | 60 | Tell the task library that you need at least n bytes left 61 | on the stack. If you don't have it, the task library will call abort. 62 | (It's hard to figure out how big stacks should be. I usually make 63 | them really big (say 32768) and then don't worry about it.) 64 | 65 | void taskname(char*, ...); 66 | 67 | Takes an argument list like printf. Sets the current task's name. 68 | 69 | char* taskgetname(void); 70 | 71 | Returns the current task's name. Is the actual buffer; do not free. 72 | 73 | void taskstate(char*, ...); 74 | char* taskgetstate(void); 75 | 76 | Like taskname and taskgetname but for the task state. 77 | 78 | When you send a tasked program a SIGQUIT (or SIGINFO, on BSD) 79 | it will print a list of all its tasks and their names and states. 80 | This is useful for debugging why your program isn't doing anything! 81 | 82 | unsigned int taskid(void); 83 | 84 | Return the unique task id for the current task. 85 | 86 | --- Non-blocking I/O 87 | 88 | There is a small amount of runtime support for non-blocking I/O 89 | on file descriptors. 90 | 91 | int fdnoblock(int fd); 92 | 93 | Sets I/O on the given fd to be non-blocking. Should be 94 | called before any of the other fd routines. 95 | 96 | int fdread(int, void*, int); 97 | 98 | Like regular read(), but puts task to sleep while waiting for 99 | data instead of blocking the whole program. 100 | 101 | int fdwrite(int, void*, int); 102 | 103 | Like regular write(), but puts task to sleep while waiting to 104 | write data instead of blocking the whole program. 105 | 106 | void fdwait(int fd, int rw); 107 | 108 | Low-level call sitting underneath fdread and fdwrite. 109 | Puts task to sleep while waiting for I/O to be possible on fd. 110 | Rw specifies type of I/O: 'r' means read, 'w' means write, 111 | anything else means just exceptional conditions (hang up, etc.) 112 | The 'r' and 'w' also wake up for exceptional conditions. 113 | 114 | --- Network I/O 115 | 116 | These are convenient packaging of the ugly Unix socket routines. 117 | They can all put the current task to sleep during the call. 118 | 119 | int netannounce(int proto, char *address, int port) 120 | 121 | Start a network listener running on address and port of protocol. 122 | Proto is either TCP or UDP. Port is a port number. Address is a 123 | string version of a host name or IP address. If address is null, 124 | then announce binds to the given port on all available interfaces. 125 | Returns a fd to use with netaccept. 126 | Examples: netannounce(TCP, "localhost", 80) or 127 | netannounce(TCP, "127.0.0.1", 80) or netannounce(TCP, 0, 80). 128 | 129 | int netaccept(int fd, char *server, int *port) 130 | 131 | Get the next connection that comes in to the listener fd. 132 | Returns a fd to use to talk to the guy who just connected. 133 | If server is not null, it must point at a buffer of at least 134 | 16 bytes that is filled in with the remote IP address. 135 | If port is not null, it is filled in with the report port. 136 | Example: 137 | char server[16]; 138 | int port; 139 | 140 | if(netaccept(fd, server, &port) >= 0) 141 | printf("connect from %s:%d", server, port); 142 | 143 | int netdial(int proto, char *name, int port) 144 | 145 | Create a new (outgoing) connection to a particular host. 146 | Name can be an ip address or a domain name. If it's a domain name, 147 | the entire program will block while the name is resolved 148 | (the DNS library does not provide a nice non-blocking interface). 149 | Example: netdial(TCP, "www.google.com", 80) 150 | or netdial(TCP, "18.26.4.9", 80) 151 | 152 | --- Time 153 | 154 | unsigned int taskdelay(unsigned int ms) 155 | 156 | Put the current task to sleep for approximately ms milliseconds. 157 | Return the actual amount of time slept, in milliseconds. 158 | 159 | --- Example programs 160 | 161 | In this directory, tcpproxy.c is a simple TCP proxy that illustrates 162 | most of the above. You can run 163 | 164 | tcpproxy 1234 www.google.com 80 165 | 166 | and then you should be able to visit http://localhost:1234/ and see Google. 167 | 168 | Other examples are: 169 | primes.c - simple prime sieve 170 | httpload.c - simple HTTP load generator 171 | testdelay.c - test taskdelay() 172 | 173 | --- Building 174 | 175 | To build, run make. You can run make install to copy task.h and 176 | libtask.a to the appropriate places in /usr/local. Then you 177 | should be able to just link with -ltask in your programs 178 | that use it. 179 | 180 | On SunOS Solaris machines, run makesun instead of just make. 181 | 182 | --- Contact Info 183 | 184 | Please email me with questions or problems. 185 | 186 | Russ Cox 187 | rsc@swtch.com 188 | 189 | 190 | --- Stuff you probably won't use at first --- 191 | --- but might want to know about eventually --- 192 | 193 | void tasksleep(Rendez*); 194 | int taskwakeup(Rendez*); 195 | int taskwakeupall(Rendez*); 196 | 197 | A Rendez is a condition variable. You can declare a new one by 198 | just allocating memory for it (or putting it in another structure) 199 | and then zeroing the memory. Tasksleep(r) 'sleeps on r', giving 200 | up the CPU. Multiple tasks can sleep on a single Rendez. 201 | When another task comes along and calls taskwakeup(r), 202 | the first task sleeping on r (if any) will be woken up. 203 | Taskwakeupall(r) wakes up all the tasks sleeping on r. 204 | They both return the actual number of tasks awakened. 205 | 206 | 207 | 208 | void qlock(QLock*); 209 | int canqlock(QLock*); 210 | void qunlock(QLock*); 211 | 212 | You probably won't need locks because of the cooperative 213 | scheduling, but if you do, here are some. You can make a new 214 | QLock by just declaring it and zeroing the memory. 215 | Calling qlock will give up the CPU if the lock is held by someone else. 216 | Calling qunlock will not give up the CPU. 217 | Calling canqlock tries to lock the lock, but will not give up the CPU. 218 | It returns 1 if the lock was acquired, 0 if it cannot be at this time. 219 | 220 | void rlock(RWLock*); 221 | int canrlock(RWLock*); 222 | void runlock(RWLock*); 223 | 224 | void wlock(RWLock*); 225 | int canwlock(RWLock*); 226 | void wunlock(RWLock*); 227 | 228 | RWLocks are reader-writer locks. Any number of readers 229 | can lock them at once, but only one writer at a time. 230 | If a writer is holding it, there can't be any readers. 231 | 232 | 233 | Channel *chancreate(int, int); 234 | etc. 235 | 236 | Channels are buffered communication pipes you can 237 | use to send messages between tasks. Some people like 238 | doing most of the inter-task communication using channels. 239 | 240 | For details on channels see the description of channels in 241 | http://swtch.com/usr/local/plan9/man/man3/thread.html and 242 | http://swtch.com/~rsc/thread/ 243 | and also the example program primes.c, which implements 244 | a concurrent prime sieve. 245 | 246 | 247 | -------------------------------------------------------------------------------- /amd64-ucontext.h: -------------------------------------------------------------------------------- 1 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 2 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 3 | typedef struct mcontext mcontext_t; 4 | typedef struct ucontext ucontext_t; 5 | 6 | extern int swapcontext(ucontext_t*, const ucontext_t*); 7 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 8 | extern int getmcontext(mcontext_t*); 9 | extern void setmcontext(const mcontext_t*); 10 | 11 | /*- 12 | * Copyright (c) 1999 Marcel Moolenaar 13 | * All rights reserved. 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions 17 | * are met: 18 | * 1. Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer 20 | * in this position and unchanged. 21 | * 2. Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the distribution. 24 | * 3. The name of the author may not be used to endorse or promote products 25 | * derived from this software without specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 39 | */ 40 | 41 | /* #include */ 42 | 43 | /*- 44 | * Copyright (c) 1999 Marcel Moolenaar 45 | * All rights reserved. 46 | * 47 | * Redistribution and use in source and binary forms, with or without 48 | * modification, are permitted provided that the following conditions 49 | * are met: 50 | * 1. Redistributions of source code must retain the above copyright 51 | * notice, this list of conditions and the following disclaimer 52 | * in this position and unchanged. 53 | * 2. Redistributions in binary form must reproduce the above copyright 54 | * notice, this list of conditions and the following disclaimer in the 55 | * documentation and/or other materials provided with the distribution. 56 | * 3. The name of the author may not be used to endorse or promote products 57 | * derived from this software without specific prior written permission. 58 | * 59 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 60 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 61 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 62 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 63 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 64 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 65 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 66 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 67 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 68 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 69 | * 70 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp $ 71 | */ 72 | 73 | struct mcontext { 74 | /* 75 | * The first 20 fields must match the definition of 76 | * sigcontext. So that we can support sigcontext 77 | * and ucontext_t at the same time. 78 | */ 79 | long mc_onstack; /* XXX - sigcontext compat. */ 80 | long mc_rdi; /* machine state (struct trapframe) */ 81 | long mc_rsi; 82 | long mc_rdx; 83 | long mc_rcx; 84 | long mc_r8; 85 | long mc_r9; 86 | long mc_rax; 87 | long mc_rbx; 88 | long mc_rbp; 89 | long mc_r10; 90 | long mc_r11; 91 | long mc_r12; 92 | long mc_r13; 93 | long mc_r14; 94 | long mc_r15; 95 | long mc_trapno; 96 | long mc_addr; 97 | long mc_flags; 98 | long mc_err; 99 | long mc_rip; 100 | long mc_cs; 101 | long mc_rflags; 102 | long mc_rsp; 103 | long mc_ss; 104 | 105 | long mc_len; /* sizeof(mcontext_t) */ 106 | #define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ 107 | #define _MC_FPFMT_XMM 0x10002 108 | long mc_fpformat; 109 | #define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ 110 | #define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ 111 | #define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ 112 | long mc_ownedfp; 113 | /* 114 | * See for the internals of mc_fpstate[]. 115 | */ 116 | long mc_fpstate[64]; 117 | long mc_spare[8]; 118 | }; 119 | 120 | struct ucontext { 121 | /* 122 | * Keep the order of the first two fields. Also, 123 | * keep them the first two fields in the structure. 124 | * This way we can have a union with struct 125 | * sigcontext and ucontext_t. This allows us to 126 | * support them both at the same time. 127 | * note: the union is not defined, though. 128 | */ 129 | sigset_t uc_sigmask; 130 | mcontext_t uc_mcontext; 131 | 132 | struct __ucontext *uc_link; 133 | stack_t uc_stack; 134 | int __spare__[8]; 135 | }; 136 | 137 | 138 | -------------------------------------------------------------------------------- /arm-ucontext.h: -------------------------------------------------------------------------------- 1 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 2 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 3 | typedef struct mcontext mcontext_t; 4 | typedef struct ucontext ucontext_t; 5 | 6 | extern int swapcontext(ucontext_t*, const ucontext_t*); 7 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 8 | extern int getmcontext(mcontext_t*); 9 | extern void setmcontext(const mcontext_t*); 10 | 11 | struct mcontext { 12 | int gregs[16]; 13 | }; 14 | 15 | struct ucontext { 16 | /* 17 | * Keep the order of the first two fields. Also, 18 | * keep them the first two fields in the structure. 19 | * This way we can have a union with struct 20 | * sigcontext and ucontext_t. This allows us to 21 | * support them both at the same time. 22 | * note: the union is not defined, though. 23 | */ 24 | sigset_t uc_sigmask; 25 | mcontext_t uc_mcontext; 26 | 27 | struct __ucontext *uc_link; 28 | stack_t uc_stack; 29 | int __spare__[8]; 30 | }; 31 | 32 | 33 | -------------------------------------------------------------------------------- /asm.S: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #if defined(__FreeBSD__) && defined(__i386__) && __FreeBSD__ < 5 4 | #define NEEDX86CONTEXT 1 5 | #define SET setmcontext 6 | #define GET getmcontext 7 | #endif 8 | 9 | #if defined(__OpenBSD__) && defined(__i386__) 10 | #define NEEDX86CONTEXT 1 11 | #define SET setmcontext 12 | #define GET getmcontext 13 | #endif 14 | 15 | #if defined(__APPLE__) 16 | #if defined(__i386__) 17 | #define NEEDX86CONTEXT 1 18 | #define SET _setmcontext 19 | #define GET _getmcontext 20 | #elif defined(__x86_64__) 21 | #define NEEDAMD64CONTEXT 1 22 | #define SET _setmcontext 23 | #define GET _getmcontext 24 | #elif defined(__arm__) 25 | #define NEEDARMCONTEXT 1 26 | #define SET _setmcontext 27 | #define GET _getmcontext 28 | #else 29 | #define NEEDPOWERCONTEXT 1 30 | #define SET __setmcontext 31 | #define GET __getmcontext 32 | #endif 33 | #endif 34 | 35 | #if defined(__linux__) && defined(__arm__) 36 | #define NEEDARMCONTEXT 1 37 | #define SET setmcontext 38 | #define GET getmcontext 39 | #endif 40 | 41 | #if defined(__linux__) && defined(__mips__) 42 | #define NEEDMIPSCONTEXT 1 43 | #define SET setmcontext 44 | #define GET getmcontext 45 | #endif 46 | 47 | #ifdef NEEDX86CONTEXT 48 | .globl SET 49 | SET: 50 | movl 4(%esp), %eax 51 | 52 | movl 8(%eax), %fs 53 | movl 12(%eax), %es 54 | movl 16(%eax), %ds 55 | movl 76(%eax), %ss 56 | movl 20(%eax), %edi 57 | movl 24(%eax), %esi 58 | movl 28(%eax), %ebp 59 | movl 36(%eax), %ebx 60 | movl 40(%eax), %edx 61 | movl 44(%eax), %ecx 62 | 63 | movl 72(%eax), %esp 64 | pushl 60(%eax) /* new %eip */ 65 | movl 48(%eax), %eax 66 | ret 67 | 68 | .globl GET 69 | GET: 70 | movl 4(%esp), %eax 71 | 72 | movl %fs, 8(%eax) 73 | movl %es, 12(%eax) 74 | movl %ds, 16(%eax) 75 | movl %ss, 76(%eax) 76 | movl %edi, 20(%eax) 77 | movl %esi, 24(%eax) 78 | movl %ebp, 28(%eax) 79 | movl %ebx, 36(%eax) 80 | movl %edx, 40(%eax) 81 | movl %ecx, 44(%eax) 82 | 83 | movl $1, 48(%eax) /* %eax */ 84 | movl (%esp), %ecx /* %eip */ 85 | movl %ecx, 60(%eax) 86 | leal 4(%esp), %ecx /* %esp */ 87 | movl %ecx, 72(%eax) 88 | 89 | movl 44(%eax), %ecx /* restore %ecx */ 90 | movl $0, %eax 91 | ret 92 | #endif 93 | 94 | #ifdef NEEDAMD64CONTEXT 95 | .globl SET 96 | SET: 97 | movq 16(%rdi), %rsi 98 | movq 24(%rdi), %rdx 99 | movq 32(%rdi), %rcx 100 | movq 40(%rdi), %r8 101 | movq 48(%rdi), %r9 102 | movq 56(%rdi), %rax 103 | movq 64(%rdi), %rbx 104 | movq 72(%rdi), %rbp 105 | movq 80(%rdi), %r10 106 | movq 88(%rdi), %r11 107 | movq 96(%rdi), %r12 108 | movq 104(%rdi), %r13 109 | movq 112(%rdi), %r14 110 | movq 120(%rdi), %r15 111 | movq 184(%rdi), %rsp 112 | pushq 160(%rdi) /* new %eip */ 113 | movq 8(%rdi), %rdi 114 | ret 115 | 116 | .globl GET 117 | GET: 118 | movq %rdi, 8(%rdi) 119 | movq %rsi, 16(%rdi) 120 | movq %rdx, 24(%rdi) 121 | movq %rcx, 32(%rdi) 122 | movq %r8, 40(%rdi) 123 | movq %r9, 48(%rdi) 124 | movq $1, 56(%rdi) /* %rax */ 125 | movq %rbx, 64(%rdi) 126 | movq %rbp, 72(%rdi) 127 | movq %r10, 80(%rdi) 128 | movq %r11, 88(%rdi) 129 | movq %r12, 96(%rdi) 130 | movq %r13, 104(%rdi) 131 | movq %r14, 112(%rdi) 132 | movq %r15, 120(%rdi) 133 | 134 | movq (%rsp), %rcx /* %rip */ 135 | movq %rcx, 160(%rdi) 136 | leaq 8(%rsp), %rcx /* %rsp */ 137 | movq %rcx, 184(%rdi) 138 | 139 | movq 32(%rdi), %rcx /* restore %rcx */ 140 | movq $0, %rax 141 | ret 142 | #endif 143 | 144 | #ifdef NEEDPOWERCONTEXT 145 | /* get FPR and VR use flags with sc 0x7FF3 */ 146 | /* get vsave with mfspr reg, 256 */ 147 | 148 | .text 149 | .align 2 150 | 151 | .globl GET 152 | GET: /* xxx: instruction scheduling */ 153 | mflr r0 154 | mfcr r5 155 | mfctr r6 156 | mfxer r7 157 | stw r0, 0*4(r3) 158 | stw r5, 1*4(r3) 159 | stw r6, 2*4(r3) 160 | stw r7, 3*4(r3) 161 | 162 | stw r1, 4*4(r3) 163 | stw r2, 5*4(r3) 164 | li r5, 1 /* return value for setmcontext */ 165 | stw r5, 6*4(r3) 166 | 167 | stw r13, (0+7)*4(r3) /* callee-save GPRs */ 168 | stw r14, (1+7)*4(r3) /* xxx: block move */ 169 | stw r15, (2+7)*4(r3) 170 | stw r16, (3+7)*4(r3) 171 | stw r17, (4+7)*4(r3) 172 | stw r18, (5+7)*4(r3) 173 | stw r19, (6+7)*4(r3) 174 | stw r20, (7+7)*4(r3) 175 | stw r21, (8+7)*4(r3) 176 | stw r22, (9+7)*4(r3) 177 | stw r23, (10+7)*4(r3) 178 | stw r24, (11+7)*4(r3) 179 | stw r25, (12+7)*4(r3) 180 | stw r26, (13+7)*4(r3) 181 | stw r27, (14+7)*4(r3) 182 | stw r28, (15+7)*4(r3) 183 | stw r29, (16+7)*4(r3) 184 | stw r30, (17+7)*4(r3) 185 | stw r31, (18+7)*4(r3) 186 | 187 | li r3, 0 /* return */ 188 | blr 189 | 190 | .globl SET 191 | SET: 192 | lwz r13, (0+7)*4(r3) /* callee-save GPRs */ 193 | lwz r14, (1+7)*4(r3) /* xxx: block move */ 194 | lwz r15, (2+7)*4(r3) 195 | lwz r16, (3+7)*4(r3) 196 | lwz r17, (4+7)*4(r3) 197 | lwz r18, (5+7)*4(r3) 198 | lwz r19, (6+7)*4(r3) 199 | lwz r20, (7+7)*4(r3) 200 | lwz r21, (8+7)*4(r3) 201 | lwz r22, (9+7)*4(r3) 202 | lwz r23, (10+7)*4(r3) 203 | lwz r24, (11+7)*4(r3) 204 | lwz r25, (12+7)*4(r3) 205 | lwz r26, (13+7)*4(r3) 206 | lwz r27, (14+7)*4(r3) 207 | lwz r28, (15+7)*4(r3) 208 | lwz r29, (16+7)*4(r3) 209 | lwz r30, (17+7)*4(r3) 210 | lwz r31, (18+7)*4(r3) 211 | 212 | lwz r1, 4*4(r3) 213 | lwz r2, 5*4(r3) 214 | 215 | lwz r0, 0*4(r3) 216 | mtlr r0 217 | lwz r0, 1*4(r3) 218 | mtcr r0 /* mtcrf 0xFF, r0 */ 219 | lwz r0, 2*4(r3) 220 | mtctr r0 221 | lwz r0, 3*4(r3) 222 | mtxer r0 223 | 224 | lwz r3, 6*4(r3) 225 | blr 226 | #endif 227 | 228 | #ifdef NEEDARMCONTEXT 229 | .globl GET 230 | GET: 231 | str r1, [r0,#4] 232 | str r2, [r0,#8] 233 | str r3, [r0,#12] 234 | str r4, [r0,#16] 235 | str r5, [r0,#20] 236 | str r6, [r0,#24] 237 | str r7, [r0,#28] 238 | str r8, [r0,#32] 239 | str r9, [r0,#36] 240 | str r10, [r0,#40] 241 | str r11, [r0,#44] 242 | str r12, [r0,#48] 243 | str r13, [r0,#52] 244 | str r14, [r0,#56] 245 | /* store 1 as r0-to-restore */ 246 | mov r1, #1 247 | str r1, [r0] 248 | /* return 0 */ 249 | mov r0, #0 250 | mov pc, lr 251 | 252 | .globl SET 253 | SET: 254 | ldr r1, [r0,#4] 255 | ldr r2, [r0,#8] 256 | ldr r3, [r0,#12] 257 | ldr r4, [r0,#16] 258 | ldr r5, [r0,#20] 259 | ldr r6, [r0,#24] 260 | ldr r7, [r0,#28] 261 | ldr r8, [r0,#32] 262 | ldr r9, [r0,#36] 263 | ldr r10, [r0,#40] 264 | ldr r11, [r0,#44] 265 | ldr r12, [r0,#48] 266 | ldr r13, [r0,#52] 267 | ldr r14, [r0,#56] 268 | ldr r0, [r0] 269 | mov pc, lr 270 | #endif 271 | 272 | #ifdef NEEDMIPSCONTEXT 273 | .globl GET 274 | GET: 275 | sw $4, 24($4) 276 | sw $5, 28($4) 277 | sw $6, 32($4) 278 | sw $7, 36($4) 279 | 280 | sw $16, 72($4) 281 | sw $17, 76($4) 282 | sw $18, 80($4) 283 | sw $19, 84($4) 284 | sw $20, 88($4) 285 | sw $21, 92($4) 286 | sw $22, 96($4) 287 | sw $23, 100($4) 288 | 289 | sw $28, 120($4) /* gp */ 290 | sw $29, 124($4) /* sp */ 291 | sw $30, 128($4) /* fp */ 292 | sw $31, 132($4) /* ra */ 293 | 294 | xor $2, $2, $2 295 | j $31 296 | nop 297 | 298 | .globl SET 299 | SET: 300 | lw $16, 72($4) 301 | lw $17, 76($4) 302 | lw $18, 80($4) 303 | lw $19, 84($4) 304 | lw $20, 88($4) 305 | lw $21, 92($4) 306 | lw $22, 96($4) 307 | lw $23, 100($4) 308 | 309 | lw $28, 120($4) /* gp */ 310 | lw $29, 124($4) /* sp */ 311 | lw $30, 128($4) /* fp */ 312 | 313 | /* 314 | * If we set $31 directly and j $31, 315 | * we would loose the outer return address. 316 | * Use a temporary register, then. 317 | */ 318 | lw $8, 132($4) /* ra */ 319 | 320 | /* bug: not setting the pc causes a bus error */ 321 | lw $25, 132($4) /* pc */ 322 | 323 | lw $5, 28($4) 324 | lw $6, 32($4) 325 | lw $7, 36($4) 326 | lw $4, 24($4) 327 | 328 | j $8 329 | nop 330 | #endif 331 | -------------------------------------------------------------------------------- /channel.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #include "taskimpl.h" 4 | 5 | Channel* 6 | chancreate(int elemsize, int bufsize) 7 | { 8 | Channel *c; 9 | 10 | c = malloc(sizeof *c+bufsize*elemsize); 11 | if(c == nil){ 12 | fprint(2, "chancreate malloc: %r"); 13 | exit(1); 14 | } 15 | memset(c, 0, sizeof *c); 16 | c->elemsize = elemsize; 17 | c->bufsize = bufsize; 18 | c->nbuf = 0; 19 | c->buf = (uchar*)(c+1); 20 | return c; 21 | } 22 | 23 | /* bug - work out races */ 24 | void 25 | chanfree(Channel *c) 26 | { 27 | if(c == nil) 28 | return; 29 | free(c->name); 30 | free(c->arecv.a); 31 | free(c->asend.a); 32 | free(c); 33 | } 34 | 35 | static void 36 | addarray(Altarray *a, Alt *alt) 37 | { 38 | if(a->n == a->m){ 39 | a->m += 16; 40 | a->a = realloc(a->a, a->m*sizeof a->a[0]); 41 | } 42 | a->a[a->n++] = alt; 43 | } 44 | 45 | static void 46 | delarray(Altarray *a, int i) 47 | { 48 | --a->n; 49 | a->a[i] = a->a[a->n]; 50 | } 51 | 52 | /* 53 | * doesn't really work for things other than CHANSND and CHANRCV 54 | * but is only used as arg to chanarray, which can handle it 55 | */ 56 | #define otherop(op) (CHANSND+CHANRCV-(op)) 57 | 58 | static Altarray* 59 | chanarray(Channel *c, uint op) 60 | { 61 | switch(op){ 62 | default: 63 | return nil; 64 | case CHANSND: 65 | return &c->asend; 66 | case CHANRCV: 67 | return &c->arecv; 68 | } 69 | } 70 | 71 | static int 72 | altcanexec(Alt *a) 73 | { 74 | Altarray *ar; 75 | Channel *c; 76 | 77 | if(a->op == CHANNOP) 78 | return 0; 79 | c = a->c; 80 | if(c->bufsize == 0){ 81 | ar = chanarray(c, otherop(a->op)); 82 | return ar && ar->n; 83 | }else{ 84 | switch(a->op){ 85 | default: 86 | return 0; 87 | case CHANSND: 88 | return c->nbuf < c->bufsize; 89 | case CHANRCV: 90 | return c->nbuf > 0; 91 | } 92 | } 93 | } 94 | 95 | static void 96 | altqueue(Alt *a) 97 | { 98 | Altarray *ar; 99 | 100 | ar = chanarray(a->c, a->op); 101 | addarray(ar, a); 102 | } 103 | 104 | static void 105 | altdequeue(Alt *a) 106 | { 107 | int i; 108 | Altarray *ar; 109 | 110 | ar = chanarray(a->c, a->op); 111 | if(ar == nil){ 112 | fprint(2, "bad use of altdequeue op=%d\n", a->op); 113 | abort(); 114 | } 115 | 116 | for(i=0; in; i++) 117 | if(ar->a[i] == a){ 118 | delarray(ar, i); 119 | return; 120 | } 121 | fprint(2, "cannot find self in altdq\n"); 122 | abort(); 123 | } 124 | 125 | static void 126 | altalldequeue(Alt *a) 127 | { 128 | int i; 129 | 130 | for(i=0; a[i].op!=CHANEND && a[i].op!=CHANNOBLK; i++) 131 | if(a[i].op != CHANNOP) 132 | altdequeue(&a[i]); 133 | } 134 | 135 | static void 136 | amove(void *dst, void *src, uint n) 137 | { 138 | if(dst){ 139 | if(src == nil) 140 | memset(dst, 0, n); 141 | else 142 | memmove(dst, src, n); 143 | } 144 | } 145 | 146 | /* 147 | * Actually move the data around. There are up to three 148 | * players: the sender, the receiver, and the channel itself. 149 | * If the channel is unbuffered or the buffer is empty, 150 | * data goes from sender to receiver. If the channel is full, 151 | * the receiver removes some from the channel and the sender 152 | * gets to put some in. 153 | */ 154 | static void 155 | altcopy(Alt *s, Alt *r) 156 | { 157 | Alt *t; 158 | Channel *c; 159 | uchar *cp; 160 | 161 | /* 162 | * Work out who is sender and who is receiver 163 | */ 164 | if(s == nil && r == nil) 165 | return; 166 | assert(s != nil); 167 | c = s->c; 168 | if(s->op == CHANRCV){ 169 | t = s; 170 | s = r; 171 | r = t; 172 | } 173 | assert(s==nil || s->op == CHANSND); 174 | assert(r==nil || r->op == CHANRCV); 175 | 176 | /* 177 | * Channel is empty (or unbuffered) - copy directly. 178 | */ 179 | if(s && r && c->nbuf == 0){ 180 | amove(r->v, s->v, c->elemsize); 181 | return; 182 | } 183 | 184 | /* 185 | * Otherwise it's always okay to receive and then send. 186 | */ 187 | if(r){ 188 | cp = c->buf + c->off*c->elemsize; 189 | amove(r->v, cp, c->elemsize); 190 | --c->nbuf; 191 | if(++c->off == c->bufsize) 192 | c->off = 0; 193 | } 194 | if(s){ 195 | cp = c->buf + (c->off+c->nbuf)%c->bufsize*c->elemsize; 196 | amove(cp, s->v, c->elemsize); 197 | ++c->nbuf; 198 | } 199 | } 200 | 201 | static void 202 | altexec(Alt *a) 203 | { 204 | int i; 205 | Altarray *ar; 206 | Alt *other; 207 | Channel *c; 208 | 209 | c = a->c; 210 | ar = chanarray(c, otherop(a->op)); 211 | if(ar && ar->n){ 212 | i = rand()%ar->n; 213 | other = ar->a[i]; 214 | altcopy(a, other); 215 | altalldequeue(other->xalt); 216 | other->xalt[0].xalt = other; 217 | taskready(other->task); 218 | }else 219 | altcopy(a, nil); 220 | } 221 | 222 | #define dbgalt 0 223 | int 224 | chanalt(Alt *a) 225 | { 226 | int i, j, ncan, n, canblock; 227 | Channel *c; 228 | Task *t; 229 | 230 | needstack(512); 231 | for(i=0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++) 232 | ; 233 | n = i; 234 | canblock = a[i].op == CHANEND; 235 | 236 | t = taskrunning; 237 | for(i=0; iname) print("%s", c->name); else print("%p", c); } 247 | if(altcanexec(&a[i])){ 248 | if(dbgalt) print("*"); 249 | ncan++; 250 | } 251 | } 252 | if(ncan){ 253 | j = rand()%ncan; 254 | for(i=0; i %c:", "esrnb"[a[i].op]); 260 | if(c->name) print("%s", c->name); else print("%p", c); 261 | print("\n"); 262 | } 263 | altexec(&a[i]); 264 | return i; 265 | } 266 | } 267 | } 268 | } 269 | if(dbgalt)print("\n"); 270 | 271 | if(!canblock) 272 | return -1; 273 | 274 | for(i=0; iuc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong); 49 | sp = tos - 16; 50 | ucp->mc.pc = (long)func; 51 | ucp->mc.sp = (long)sp; 52 | va_start(arg, argc); 53 | ucp->mc.r3 = va_arg(arg, long); 54 | va_end(arg); 55 | } 56 | #endif 57 | 58 | #ifdef NEEDX86MAKECONTEXT 59 | void 60 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 61 | { 62 | int *sp; 63 | 64 | sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4; 65 | sp -= argc; 66 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 67 | memmove(sp, &argc+1, argc*sizeof(int)); 68 | 69 | *--sp = 0; /* return address */ 70 | ucp->uc_mcontext.mc_eip = (long)func; 71 | ucp->uc_mcontext.mc_esp = (int)sp; 72 | } 73 | #endif 74 | 75 | #ifdef NEEDAMD64MAKECONTEXT 76 | void 77 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 78 | { 79 | long *sp; 80 | va_list va; 81 | 82 | memset(&ucp->uc_mcontext, 0, sizeof ucp->uc_mcontext); 83 | if(argc != 2) 84 | *(int*)0 = 0; 85 | va_start(va, argc); 86 | ucp->uc_mcontext.mc_rdi = va_arg(va, int); 87 | ucp->uc_mcontext.mc_rsi = va_arg(va, int); 88 | va_end(va); 89 | sp = (long*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(long); 90 | sp -= argc; 91 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 92 | *--sp = 0; /* return address */ 93 | ucp->uc_mcontext.mc_rip = (long)func; 94 | ucp->uc_mcontext.mc_rsp = (long)sp; 95 | } 96 | #endif 97 | 98 | #ifdef NEEDARMMAKECONTEXT 99 | void 100 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 101 | { 102 | int i, *sp; 103 | va_list arg; 104 | 105 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 106 | va_start(arg, argc); 107 | for(i=0; i<4 && iuc_mcontext.gregs[i] = va_arg(arg, uint); 109 | va_end(arg); 110 | uc->uc_mcontext.gregs[13] = (uint)sp; 111 | uc->uc_mcontext.gregs[14] = (uint)fn; 112 | } 113 | #endif 114 | 115 | #ifdef NEEDMIPSMAKECONTEXT 116 | void 117 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 118 | { 119 | int i, *sp; 120 | va_list arg; 121 | 122 | va_start(arg, argc); 123 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 124 | for(i=0; i<4 && iuc_mcontext.mc_regs[i+4] = va_arg(arg, int); 126 | va_end(arg); 127 | uc->uc_mcontext.mc_regs[29] = (int)sp; 128 | uc->uc_mcontext.mc_regs[31] = (int)fn; 129 | } 130 | #endif 131 | 132 | #ifdef NEEDSWAPCONTEXT 133 | int 134 | swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 135 | { 136 | if(getcontext(oucp) == 0) 137 | setcontext(ucp); 138 | return 0; 139 | } 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /fd.c: -------------------------------------------------------------------------------- 1 | #include "taskimpl.h" 2 | #include 3 | #include 4 | 5 | enum 6 | { 7 | MAXFD = 1024 8 | }; 9 | 10 | static struct pollfd pollfd[MAXFD]; 11 | static Task *polltask[MAXFD]; 12 | static int npollfd; 13 | static int startedfdtask; 14 | static Tasklist sleeping; 15 | static int sleepingcounted; 16 | static uvlong nsec(void); 17 | 18 | void 19 | fdtask(void *v) 20 | { 21 | int i, ms; 22 | Task *t; 23 | uvlong now; 24 | 25 | tasksystem(); 26 | taskname("fdtask"); 27 | for(;;){ 28 | /* let everyone else run */ 29 | while(taskyield() > 0) 30 | ; 31 | /* we're the only one runnable - poll for i/o */ 32 | errno = 0; 33 | taskstate("poll"); 34 | if((t=sleeping.head) == nil) 35 | ms = -1; 36 | else{ 37 | /* sleep at most 5s */ 38 | now = nsec(); 39 | if(now >= t->alarmtime) 40 | ms = 0; 41 | else if(now+5*1000*1000*1000LL >= t->alarmtime) 42 | ms = (t->alarmtime - now)/1000000; 43 | else 44 | ms = 5000; 45 | } 46 | if(poll(pollfd, npollfd, ms) < 0){ 47 | if(errno == EINTR) 48 | continue; 49 | fprint(2, "poll: %s\n", strerror(errno)); 50 | taskexitall(0); 51 | } 52 | 53 | /* wake up the guys who deserve it */ 54 | for(i=0; i= t->alarmtime){ 65 | deltask(&sleeping, t); 66 | if(!t->system && --sleepingcounted == 0) 67 | taskcount--; 68 | taskready(t); 69 | } 70 | } 71 | } 72 | 73 | uint 74 | taskdelay(uint ms) 75 | { 76 | uvlong when, now; 77 | Task *t; 78 | 79 | if(!startedfdtask){ 80 | startedfdtask = 1; 81 | taskcreate(fdtask, 0, 32768); 82 | } 83 | 84 | now = nsec(); 85 | when = now+(uvlong)ms*1000000; 86 | for(t=sleeping.head; t!=nil && t->alarmtime < when; t=t->next) 87 | ; 88 | 89 | if(t){ 90 | taskrunning->prev = t->prev; 91 | taskrunning->next = t; 92 | }else{ 93 | taskrunning->prev = sleeping.tail; 94 | taskrunning->next = nil; 95 | } 96 | 97 | t = taskrunning; 98 | t->alarmtime = when; 99 | if(t->prev) 100 | t->prev->next = t; 101 | else 102 | sleeping.head = t; 103 | if(t->next) 104 | t->next->prev = t; 105 | else 106 | sleeping.tail = t; 107 | 108 | if(!t->system && sleepingcounted++ == 0) 109 | taskcount++; 110 | taskswitch(); 111 | 112 | return (nsec() - now)/1000000; 113 | } 114 | 115 | void 116 | fdwait(int fd, int rw) 117 | { 118 | int bits; 119 | 120 | if(!startedfdtask){ 121 | startedfdtask = 1; 122 | taskcreate(fdtask, 0, 32768); 123 | } 124 | 125 | if(npollfd >= MAXFD){ 126 | fprint(2, "too many poll file descriptors\n"); 127 | abort(); 128 | } 129 | 130 | taskstate("fdwait for %s", rw=='r' ? "read" : rw=='w' ? "write" : "error"); 131 | bits = 0; 132 | switch(rw){ 133 | case 'r': 134 | bits |= POLLIN; 135 | break; 136 | case 'w': 137 | bits |= POLLOUT; 138 | break; 139 | } 140 | 141 | polltask[npollfd] = taskrunning; 142 | pollfd[npollfd].fd = fd; 143 | pollfd[npollfd].events = bits; 144 | pollfd[npollfd].revents = 0; 145 | npollfd++; 146 | taskswitch(); 147 | } 148 | 149 | /* Like fdread but always calls fdwait before reading. */ 150 | int 151 | fdread1(int fd, void *buf, int n) 152 | { 153 | int m; 154 | 155 | do 156 | fdwait(fd, 'r'); 157 | while((m = read(fd, buf, n)) < 0 && errno == EAGAIN); 158 | return m; 159 | } 160 | 161 | int 162 | fdread(int fd, void *buf, int n) 163 | { 164 | int m; 165 | 166 | while((m=read(fd, buf, n)) < 0 && errno == EAGAIN) 167 | fdwait(fd, 'r'); 168 | return m; 169 | } 170 | 171 | int 172 | fdwrite(int fd, void *buf, int n) 173 | { 174 | int m, tot; 175 | 176 | for(tot=0; tot 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum 9 | { 10 | STACK = 32768 11 | }; 12 | 13 | char *server; 14 | char *url; 15 | 16 | void fetchtask(void*); 17 | 18 | void 19 | taskmain(int argc, char **argv) 20 | { 21 | int i, n; 22 | 23 | if(argc != 4){ 24 | fprintf(stderr, "usage: httpload n server url\n"); 25 | taskexitall(1); 26 | } 27 | n = atoi(argv[1]); 28 | server = argv[2]; 29 | url = argv[3]; 30 | 31 | for(i=0; i 1) 34 | ; 35 | sleep(1); 36 | } 37 | } 38 | 39 | void 40 | fetchtask(void *v) 41 | { 42 | int fd, n; 43 | char buf[512]; 44 | 45 | fprintf(stderr, "starting...\n"); 46 | for(;;){ 47 | if((fd = netdial(TCP, server, 80)) < 0){ 48 | fprintf(stderr, "dial %s: %s (%s)\n", server, strerror(errno), taskgetstate()); 49 | continue; 50 | } 51 | snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", url, server); 52 | fdwrite(fd, buf, strlen(buf)); 53 | while((n = fdread(fd, buf, sizeof buf)) > 0) 54 | ; 55 | close(fd); 56 | write(1, ".", 1); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /makesun: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | case "x$CC" in 4 | x|xcc) 5 | CC=cc 6 | CFLAGS="-mt -g -O -c -xCC -D__sun__ -I." 7 | ;; 8 | xgcc) 9 | CC=gcc 10 | CFLAGS="-Wall -c -I." 11 | ;; 12 | *) 13 | echo 'unknown $CC' 14 | exit 1 15 | esac 16 | 17 | u=`uname` 18 | v=`uname -r` 19 | s=`echo $u$v | tr '. ' '__'` 20 | CFLAGS="$CFLAGS -D__${s}__" 21 | 22 | make "CC=$CC" "CFLAGS=$CFLAGS" "ASM=" "TCPLIBS=-lsocket -lnsl" 23 | -------------------------------------------------------------------------------- /mips-ucontext.h: -------------------------------------------------------------------------------- 1 | typedef struct mcontext mcontext_t; 2 | typedef struct ucontext ucontext_t; 3 | 4 | extern int swapcontext(ucontext_t*, const ucontext_t*); 5 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 6 | 7 | /* 8 | * Copyright (c) 1992, 1993 9 | * The Regents of the University of California. All rights reserved. 10 | * 11 | * This code is derived from software contributed to Berkeley by 12 | * Ralph Campbell. 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 1. Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 2. Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in the 21 | * documentation and/or other materials provided with the distribution. 22 | * 4. Neither the name of the University nor the names of its contributors 23 | * may be used to endorse or promote products derived from this software 24 | * without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 | * SUCH DAMAGE. 37 | * 38 | * @(#)ucontext.h 8.1 (Berkeley) 6/10/93 39 | * JNPR: ucontext.h,v 1.2 2007/08/09 11:23:32 katta 40 | * $FreeBSD: src/sys/mips/include/ucontext.h,v 1.2 2010/01/10 19:50:24 imp Exp $ 41 | */ 42 | 43 | struct mcontext { 44 | /* 45 | * These fields must match the corresponding fields in struct 46 | * sigcontext which follow 'sc_mask'. That way we can support 47 | * struct sigcontext and ucontext_t at the same time. 48 | */ 49 | int mc_onstack; /* sigstack state to restore */ 50 | int mc_pc; /* pc at time of signal */ 51 | int mc_regs[32]; /* processor regs 0 to 31 */ 52 | int sr; /* status register */ 53 | int mullo, mulhi; /* mullo and mulhi registers... */ 54 | int mc_fpused; /* fp has been used */ 55 | int mc_fpregs[33]; /* fp regs 0 to 31 and csr */ 56 | int mc_fpc_eir; /* fp exception instruction reg */ 57 | void *mc_tls; /* pointer to TLS area */ 58 | int __spare__[8]; /* XXX reserved */ 59 | }; 60 | 61 | struct ucontext { 62 | /* 63 | * Keep the order of the first two fields. Also, 64 | * keep them the first two fields in the structure. 65 | * This way we can have a union with struct 66 | * sigcontext and ucontext_t. This allows us to 67 | * support them both at the same time. 68 | * note: the union is not defined, though. 69 | */ 70 | sigset_t uc_sigmask; 71 | mcontext_t uc_mcontext; 72 | 73 | struct __ucontext *uc_link; 74 | stack_t uc_stack; 75 | int uc_flags; 76 | int __spare__[4]; 77 | }; 78 | -------------------------------------------------------------------------------- /net.c: -------------------------------------------------------------------------------- 1 | #include "taskimpl.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int 10 | netannounce(int istcp, char *server, int port) 11 | { 12 | int fd, n, proto; 13 | struct sockaddr_in sa; 14 | socklen_t sn; 15 | uint32_t ip; 16 | 17 | taskstate("netannounce"); 18 | proto = istcp ? SOCK_STREAM : SOCK_DGRAM; 19 | memset(&sa, 0, sizeof sa); 20 | sa.sin_family = AF_INET; 21 | if(server != nil && strcmp(server, "*") != 0){ 22 | if(netlookup(server, &ip) < 0){ 23 | taskstate("netlookup failed"); 24 | return -1; 25 | } 26 | memmove(&sa.sin_addr, &ip, 4); 27 | } 28 | sa.sin_port = htons(port); 29 | if((fd = socket(AF_INET, proto, 0)) < 0){ 30 | taskstate("socket failed"); 31 | return -1; 32 | } 33 | 34 | /* set reuse flag for tcp */ 35 | if(istcp && getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0){ 36 | n = 1; 37 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n); 38 | } 39 | 40 | if(bind(fd, (struct sockaddr*)&sa, sizeof sa) < 0){ 41 | taskstate("bind failed"); 42 | close(fd); 43 | return -1; 44 | } 45 | 46 | if(proto == SOCK_STREAM) 47 | listen(fd, 16); 48 | 49 | fdnoblock(fd); 50 | taskstate("netannounce succeeded"); 51 | return fd; 52 | } 53 | 54 | int 55 | netaccept(int fd, char *server, int *port) 56 | { 57 | int cfd, one; 58 | struct sockaddr_in sa; 59 | uchar *ip; 60 | socklen_t len; 61 | 62 | fdwait(fd, 'r'); 63 | 64 | taskstate("netaccept"); 65 | len = sizeof sa; 66 | if((cfd = accept(fd, (void*)&sa, &len)) < 0){ 67 | taskstate("accept failed"); 68 | return -1; 69 | } 70 | if(server){ 71 | ip = (uchar*)&sa.sin_addr; 72 | snprint(server, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); 73 | } 74 | if(port) 75 | *port = ntohs(sa.sin_port); 76 | fdnoblock(cfd); 77 | one = 1; 78 | setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one); 79 | taskstate("netaccept succeeded"); 80 | return cfd; 81 | } 82 | 83 | #define CLASS(p) ((*(unsigned char*)(p))>>6) 84 | static int 85 | parseip(char *name, uint32_t *ip) 86 | { 87 | unsigned char addr[4]; 88 | char *p; 89 | int i, x; 90 | 91 | p = name; 92 | for(i=0; i<4 && *p; i++){ 93 | x = strtoul(p, &p, 0); 94 | if(x < 0 || x >= 256) 95 | return -1; 96 | if(*p != '.' && *p != 0) 97 | return -1; 98 | if(*p == '.') 99 | p++; 100 | addr[i] = x; 101 | } 102 | 103 | switch(CLASS(addr)){ 104 | case 0: 105 | case 1: 106 | if(i == 3){ 107 | addr[3] = addr[2]; 108 | addr[2] = addr[1]; 109 | addr[1] = 0; 110 | }else if(i == 2){ 111 | addr[3] = addr[1]; 112 | addr[2] = 0; 113 | addr[1] = 0; 114 | }else if(i != 4) 115 | return -1; 116 | break; 117 | case 2: 118 | if(i == 3){ 119 | addr[3] = addr[2]; 120 | addr[2] = 0; 121 | }else if(i != 4) 122 | return -1; 123 | break; 124 | } 125 | *ip = *(uint32_t*)addr; 126 | return 0; 127 | } 128 | 129 | int 130 | netlookup(char *name, uint32_t *ip) 131 | { 132 | struct hostent *he; 133 | 134 | if(parseip(name, ip) >= 0) 135 | return 0; 136 | 137 | /* BUG - Name resolution blocks. Need a non-blocking DNS. */ 138 | taskstate("netlookup"); 139 | if((he = gethostbyname(name)) != 0){ 140 | *ip = *(uint32_t*)he->h_addr; 141 | taskstate("netlookup succeeded"); 142 | return 0; 143 | } 144 | 145 | taskstate("netlookup failed"); 146 | return -1; 147 | } 148 | 149 | int 150 | netdial(int istcp, char *server, int port) 151 | { 152 | int proto, fd, n; 153 | uint32_t ip; 154 | struct sockaddr_in sa; 155 | socklen_t sn; 156 | 157 | if(netlookup(server, &ip) < 0) 158 | return -1; 159 | 160 | taskstate("netdial"); 161 | proto = istcp ? SOCK_STREAM : SOCK_DGRAM; 162 | if((fd = socket(AF_INET, proto, 0)) < 0){ 163 | taskstate("socket failed"); 164 | return -1; 165 | } 166 | fdnoblock(fd); 167 | 168 | /* for udp */ 169 | if(!istcp){ 170 | n = 1; 171 | setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); 172 | } 173 | 174 | /* start connecting */ 175 | memset(&sa, 0, sizeof sa); 176 | memmove(&sa.sin_addr, &ip, 4); 177 | sa.sin_family = AF_INET; 178 | sa.sin_port = htons(port); 179 | if(connect(fd, (struct sockaddr*)&sa, sizeof sa) < 0 && errno != EINPROGRESS){ 180 | taskstate("connect failed"); 181 | close(fd); 182 | return -1; 183 | } 184 | 185 | /* wait for finish */ 186 | fdwait(fd, 'w'); 187 | sn = sizeof sa; 188 | if(getpeername(fd, (struct sockaddr*)&sa, &sn) >= 0){ 189 | taskstate("connect succeeded"); 190 | return fd; 191 | } 192 | 193 | /* report error */ 194 | sn = sizeof n; 195 | getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&n, &sn); 196 | if(n == 0) 197 | n = ECONNREFUSED; 198 | close(fd); 199 | taskstate("connect failed"); 200 | errno = n; 201 | return -1; 202 | } 203 | 204 | -------------------------------------------------------------------------------- /power-ucontext.h: -------------------------------------------------------------------------------- 1 | #define setcontext(u) _setmcontext(&(u)->mc) 2 | #define getcontext(u) _getmcontext(&(u)->mc) 3 | typedef struct mcontext mcontext_t; 4 | typedef struct ucontext ucontext_t; 5 | struct mcontext 6 | { 7 | ulong pc; /* lr */ 8 | ulong cr; /* mfcr */ 9 | ulong ctr; /* mfcr */ 10 | ulong xer; /* mfcr */ 11 | ulong sp; /* callee saved: r1 */ 12 | ulong toc; /* callee saved: r2 */ 13 | ulong r3; /* first arg to function, return register: r3 */ 14 | ulong gpr[19]; /* callee saved: r13-r31 */ 15 | /* 16 | // XXX: currently do not save vector registers or floating-point state 17 | // ulong pad; 18 | // uvlong fpr[18]; / * callee saved: f14-f31 * / 19 | // ulong vr[4*12]; / * callee saved: v20-v31, 256-bits each * / 20 | */ 21 | }; 22 | 23 | struct ucontext 24 | { 25 | struct { 26 | void *ss_sp; 27 | uint ss_size; 28 | } uc_stack; 29 | sigset_t uc_sigmask; 30 | mcontext_t mc; 31 | }; 32 | 33 | void makecontext(ucontext_t*, void(*)(void), int, ...); 34 | int swapcontext(ucontext_t*, const ucontext_t*); 35 | int _getmcontext(mcontext_t*); 36 | void _setmcontext(const mcontext_t*); 37 | 38 | -------------------------------------------------------------------------------- /primes.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int quiet; 9 | int goal; 10 | int buffer; 11 | 12 | void 13 | primetask(void *arg) 14 | { 15 | Channel *c, *nc; 16 | int p, i; 17 | c = arg; 18 | 19 | p = chanrecvul(c); 20 | if(p > goal) 21 | taskexitall(0); 22 | if(!quiet) 23 | printf("%d\n", p); 24 | nc = chancreate(sizeof(unsigned long), buffer); 25 | taskcreate(primetask, nc, 32768); 26 | for(;;){ 27 | i = chanrecvul(c); 28 | if(i%p) 29 | chansendul(nc, i); 30 | } 31 | } 32 | 33 | void 34 | taskmain(int argc, char **argv) 35 | { 36 | int i; 37 | Channel *c; 38 | 39 | if(argc>1) 40 | goal = atoi(argv[1]); 41 | else 42 | goal = 100; 43 | printf("goal=%d\n", goal); 44 | 45 | c = chancreate(sizeof(unsigned long), buffer); 46 | taskcreate(primetask, c, 32768); 47 | for(i=2;; i++) 48 | chansendul(c, i); 49 | } 50 | 51 | void* 52 | emalloc(unsigned long n) 53 | { 54 | return calloc(n ,1); 55 | } 56 | 57 | long 58 | lrand(void) 59 | { 60 | return rand(); 61 | } 62 | -------------------------------------------------------------------------------- /print.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2004 Russ Cox. See COPYRIGHT. */ 2 | 3 | #include "taskimpl.h" 4 | #include /* for strerror! */ 5 | 6 | /* 7 | * Stripped down print library. Plan 9 interface, new code. 8 | */ 9 | 10 | enum 11 | { 12 | FlagLong = 1<<0, 13 | FlagLongLong = 1<<1, 14 | FlagUnsigned = 1<<2, 15 | }; 16 | 17 | static char* 18 | printstr(char *dst, char *edst, char *s, int size) 19 | { 20 | int l, n, sign; 21 | 22 | sign = 1; 23 | if(size < 0){ 24 | size = -size; 25 | sign = -1; 26 | } 27 | if(dst >= edst) 28 | return dst; 29 | l = strlen(s); 30 | n = l; 31 | if(n < size) 32 | n = size; 33 | if(n >= edst-dst) 34 | n = (edst-dst)-1; 35 | if(l > n) 36 | l = n; 37 | if(sign < 0){ 38 | memmove(dst, s, l); 39 | if(n-l) 40 | memset(dst+l, ' ', n-l); 41 | }else{ 42 | if(n-l) 43 | memset(dst, ' ', n-l); 44 | memmove(dst+n-l, s, l); 45 | } 46 | return dst+n; 47 | } 48 | 49 | char* 50 | vseprint(char *dst, char *edst, char *fmt, va_list arg) 51 | { 52 | int fl, size, sign, base; 53 | char *p, *w; 54 | char cbuf[2]; 55 | 56 | w = dst; 57 | for(p=fmt; *p && wowner == nil){ 10 | l->owner = taskrunning; 11 | return 1; 12 | } 13 | if(!block) 14 | return 0; 15 | addtask(&l->waiting, taskrunning); 16 | taskstate("qlock"); 17 | taskswitch(); 18 | if(l->owner != taskrunning){ 19 | fprint(2, "qlock: owner=%p self=%p oops\n", l->owner, taskrunning); 20 | abort(); 21 | } 22 | return 1; 23 | } 24 | 25 | void 26 | qlock(QLock *l) 27 | { 28 | _qlock(l, 1); 29 | } 30 | 31 | int 32 | canqlock(QLock *l) 33 | { 34 | return _qlock(l, 0); 35 | } 36 | 37 | void 38 | qunlock(QLock *l) 39 | { 40 | Task *ready; 41 | 42 | if(l->owner == 0){ 43 | fprint(2, "qunlock: owner=0\n"); 44 | abort(); 45 | } 46 | if((l->owner = ready = l->waiting.head) != nil){ 47 | deltask(&l->waiting, ready); 48 | taskready(ready); 49 | } 50 | } 51 | 52 | static int 53 | _rlock(RWLock *l, int block) 54 | { 55 | if(l->writer == nil && l->wwaiting.head == nil){ 56 | l->readers++; 57 | return 1; 58 | } 59 | if(!block) 60 | return 0; 61 | addtask(&l->rwaiting, taskrunning); 62 | taskstate("rlock"); 63 | taskswitch(); 64 | return 1; 65 | } 66 | 67 | void 68 | rlock(RWLock *l) 69 | { 70 | _rlock(l, 1); 71 | } 72 | 73 | int 74 | canrlock(RWLock *l) 75 | { 76 | return _rlock(l, 0); 77 | } 78 | 79 | static int 80 | _wlock(RWLock *l, int block) 81 | { 82 | if(l->writer == nil && l->readers == 0){ 83 | l->writer = taskrunning; 84 | return 1; 85 | } 86 | if(!block) 87 | return 0; 88 | addtask(&l->wwaiting, taskrunning); 89 | taskstate("wlock"); 90 | taskswitch(); 91 | return 1; 92 | } 93 | 94 | void 95 | wlock(RWLock *l) 96 | { 97 | _wlock(l, 1); 98 | } 99 | 100 | int 101 | canwlock(RWLock *l) 102 | { 103 | return _wlock(l, 0); 104 | } 105 | 106 | void 107 | runlock(RWLock *l) 108 | { 109 | Task *t; 110 | 111 | if(--l->readers == 0 && (t = l->wwaiting.head) != nil){ 112 | deltask(&l->wwaiting, t); 113 | l->writer = t; 114 | taskready(t); 115 | } 116 | } 117 | 118 | void 119 | wunlock(RWLock *l) 120 | { 121 | Task *t; 122 | 123 | if(l->writer == nil){ 124 | fprint(2, "wunlock: not locked\n"); 125 | abort(); 126 | } 127 | l->writer = nil; 128 | if(l->readers != 0){ 129 | fprint(2, "wunlock: readers\n"); 130 | abort(); 131 | } 132 | while((t = l->rwaiting.head) != nil){ 133 | deltask(&l->rwaiting, t); 134 | l->readers++; 135 | taskready(t); 136 | } 137 | if(l->readers == 0 && (t = l->wwaiting.head) != nil){ 138 | deltask(&l->wwaiting, t); 139 | l->writer = t; 140 | taskready(t); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /rendez.c: -------------------------------------------------------------------------------- 1 | #include "taskimpl.h" 2 | 3 | /* 4 | * sleep and wakeup 5 | */ 6 | void 7 | tasksleep(Rendez *r) 8 | { 9 | addtask(&r->waiting, taskrunning); 10 | if(r->l) 11 | qunlock(r->l); 12 | taskstate("sleep"); 13 | taskswitch(); 14 | if(r->l) 15 | qlock(r->l); 16 | } 17 | 18 | static int 19 | _taskwakeup(Rendez *r, int all) 20 | { 21 | int i; 22 | Task *t; 23 | 24 | for(i=0;; i++){ 25 | if(i==1 && !all) 26 | break; 27 | if((t = r->waiting.head) == nil) 28 | break; 29 | deltask(&r->waiting, t); 30 | taskready(t); 31 | } 32 | return i; 33 | } 34 | 35 | int 36 | taskwakeup(Rendez *r) 37 | { 38 | return _taskwakeup(r, 0); 39 | } 40 | 41 | int 42 | taskwakeupall(Rendez *r) 43 | { 44 | return _taskwakeup(r, 1); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /task.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #include "taskimpl.h" 4 | #include 5 | #include 6 | 7 | int taskdebuglevel; 8 | int taskcount; 9 | int tasknswitch; 10 | int taskexitval; 11 | Task *taskrunning; 12 | 13 | Context taskschedcontext; 14 | Tasklist taskrunqueue; 15 | 16 | Task **alltask; 17 | int nalltask; 18 | 19 | static char *argv0; 20 | static void contextswitch(Context *from, Context *to); 21 | 22 | static void 23 | taskdebug(char *fmt, ...) 24 | { 25 | va_list arg; 26 | char buf[128]; 27 | Task *t; 28 | char *p; 29 | static int fd = -1; 30 | 31 | return; 32 | va_start(arg, fmt); 33 | vfprint(1, fmt, arg); 34 | va_end(arg); 35 | return; 36 | 37 | if(fd < 0){ 38 | p = strrchr(argv0, '/'); 39 | if(p) 40 | p++; 41 | else 42 | p = argv0; 43 | snprint(buf, sizeof buf, "/tmp/%s.tlog", p); 44 | if((fd = open(buf, O_CREAT|O_WRONLY, 0666)) < 0) 45 | fd = open("/dev/null", O_WRONLY); 46 | } 47 | 48 | va_start(arg, fmt); 49 | vsnprint(buf, sizeof buf, fmt, arg); 50 | va_end(arg); 51 | t = taskrunning; 52 | if(t) 53 | fprint(fd, "%d.%d: %s\n", getpid(), t->id, buf); 54 | else 55 | fprint(fd, "%d._: %s\n", getpid(), buf); 56 | } 57 | 58 | static void 59 | taskstart(uint y, uint x) 60 | { 61 | Task *t; 62 | ulong z; 63 | 64 | z = x<<16; /* hide undefined 32-bit shift from 32-bit compilers */ 65 | z <<= 16; 66 | z |= y; 67 | t = (Task*)z; 68 | 69 | //print("taskstart %p\n", t); 70 | t->startfn(t->startarg); 71 | //print("taskexits %p\n", t); 72 | taskexit(0); 73 | //print("not reacehd\n"); 74 | } 75 | 76 | static int taskidgen; 77 | 78 | static Task* 79 | taskalloc(void (*fn)(void*), void *arg, uint stack) 80 | { 81 | Task *t; 82 | sigset_t zero; 83 | uint x, y; 84 | ulong z; 85 | 86 | /* allocate the task and stack together */ 87 | t = malloc(sizeof *t+stack); 88 | if(t == nil){ 89 | fprint(2, "taskalloc malloc: %r\n"); 90 | abort(); 91 | } 92 | memset(t, 0, sizeof *t); 93 | t->stk = (uchar*)(t+1); 94 | t->stksize = stack; 95 | t->id = ++taskidgen; 96 | t->startfn = fn; 97 | t->startarg = arg; 98 | 99 | /* do a reasonable initialization */ 100 | memset(&t->context.uc, 0, sizeof t->context.uc); 101 | sigemptyset(&zero); 102 | sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask); 103 | 104 | /* must initialize with current context */ 105 | if(getcontext(&t->context.uc) < 0){ 106 | fprint(2, "getcontext: %r\n"); 107 | abort(); 108 | } 109 | 110 | /* call makecontext to do the real work. */ 111 | /* leave a few words open on both ends */ 112 | t->context.uc.uc_stack.ss_sp = t->stk+8; 113 | t->context.uc.uc_stack.ss_size = t->stksize-64; 114 | #if defined(__sun__) && !defined(__MAKECONTEXT_V2_SOURCE) /* sigh */ 115 | #warning "doing sun thing" 116 | /* can avoid this with __MAKECONTEXT_V2_SOURCE but only on SunOS 5.9 */ 117 | t->context.uc.uc_stack.ss_sp = 118 | (char*)t->context.uc.uc_stack.ss_sp 119 | +t->context.uc.uc_stack.ss_size; 120 | #endif 121 | /* 122 | * All this magic is because you have to pass makecontext a 123 | * function that takes some number of word-sized variables, 124 | * and on 64-bit machines pointers are bigger than words. 125 | */ 126 | //print("make %p\n", t); 127 | z = (ulong)t; 128 | y = z; 129 | z >>= 16; /* hide undefined 32-bit shift from 32-bit compilers */ 130 | x = z>>16; 131 | makecontext(&t->context.uc, (void(*)())taskstart, 2, y, x); 132 | 133 | return t; 134 | } 135 | 136 | int 137 | taskcreate(void (*fn)(void*), void *arg, uint stack) 138 | { 139 | int id; 140 | Task *t; 141 | 142 | t = taskalloc(fn, arg, stack); 143 | taskcount++; 144 | id = t->id; 145 | if(nalltask%64 == 0){ 146 | alltask = realloc(alltask, (nalltask+64)*sizeof(alltask[0])); 147 | if(alltask == nil){ 148 | fprint(2, "out of memory\n"); 149 | abort(); 150 | } 151 | } 152 | t->alltaskslot = nalltask; 153 | alltask[nalltask++] = t; 154 | taskready(t); 155 | return id; 156 | } 157 | 158 | void 159 | tasksystem(void) 160 | { 161 | if(!taskrunning->system){ 162 | taskrunning->system = 1; 163 | --taskcount; 164 | } 165 | } 166 | 167 | void 168 | taskswitch(void) 169 | { 170 | needstack(0); 171 | contextswitch(&taskrunning->context, &taskschedcontext); 172 | } 173 | 174 | void 175 | taskready(Task *t) 176 | { 177 | t->ready = 1; 178 | addtask(&taskrunqueue, t); 179 | } 180 | 181 | int 182 | taskyield(void) 183 | { 184 | int n; 185 | 186 | n = tasknswitch; 187 | taskready(taskrunning); 188 | taskstate("yield"); 189 | taskswitch(); 190 | return tasknswitch - n - 1; 191 | } 192 | 193 | int 194 | anyready(void) 195 | { 196 | return taskrunqueue.head != nil; 197 | } 198 | 199 | void 200 | taskexitall(int val) 201 | { 202 | exit(val); 203 | } 204 | 205 | void 206 | taskexit(int val) 207 | { 208 | taskexitval = val; 209 | taskrunning->exiting = 1; 210 | taskswitch(); 211 | } 212 | 213 | static void 214 | contextswitch(Context *from, Context *to) 215 | { 216 | if(swapcontext(&from->uc, &to->uc) < 0){ 217 | fprint(2, "swapcontext failed: %r\n"); 218 | assert(0); 219 | } 220 | } 221 | 222 | static void 223 | taskscheduler(void) 224 | { 225 | int i; 226 | Task *t; 227 | 228 | taskdebug("scheduler enter"); 229 | for(;;){ 230 | if(taskcount == 0) 231 | exit(taskexitval); 232 | t = taskrunqueue.head; 233 | if(t == nil){ 234 | fprint(2, "no runnable tasks! %d tasks stalled\n", taskcount); 235 | exit(1); 236 | } 237 | deltask(&taskrunqueue, t); 238 | t->ready = 0; 239 | taskrunning = t; 240 | tasknswitch++; 241 | taskdebug("run %d (%s)", t->id, t->name); 242 | contextswitch(&taskschedcontext, &t->context); 243 | //print("back in scheduler\n"); 244 | taskrunning = nil; 245 | if(t->exiting){ 246 | if(!t->system) 247 | taskcount--; 248 | i = t->alltaskslot; 249 | alltask[i] = alltask[--nalltask]; 250 | alltask[i]->alltaskslot = i; 251 | free(t); 252 | } 253 | } 254 | } 255 | 256 | void** 257 | taskdata(void) 258 | { 259 | return &taskrunning->udata; 260 | } 261 | 262 | /* 263 | * debugging 264 | */ 265 | void 266 | taskname(char *fmt, ...) 267 | { 268 | va_list arg; 269 | Task *t; 270 | 271 | t = taskrunning; 272 | va_start(arg, fmt); 273 | vsnprint(t->name, sizeof t->name, fmt, arg); 274 | va_end(arg); 275 | } 276 | 277 | char* 278 | taskgetname(void) 279 | { 280 | return taskrunning->name; 281 | } 282 | 283 | void 284 | taskstate(char *fmt, ...) 285 | { 286 | va_list arg; 287 | Task *t; 288 | 289 | t = taskrunning; 290 | va_start(arg, fmt); 291 | vsnprint(t->state, sizeof t->name, fmt, arg); 292 | va_end(arg); 293 | } 294 | 295 | char* 296 | taskgetstate(void) 297 | { 298 | return taskrunning->state; 299 | } 300 | 301 | void 302 | needstack(int n) 303 | { 304 | Task *t; 305 | 306 | t = taskrunning; 307 | 308 | if((char*)&t <= (char*)t->stk 309 | || (char*)&t - (char*)t->stk < 256+n){ 310 | fprint(2, "task stack overflow: &t=%p tstk=%p n=%d\n", &t, t->stk, 256+n); 311 | abort(); 312 | } 313 | } 314 | 315 | static void 316 | taskinfo(int s) 317 | { 318 | int i; 319 | Task *t; 320 | char *extra; 321 | 322 | fprint(2, "task list:\n"); 323 | for(i=0; iready) 328 | extra = " (ready)"; 329 | else 330 | extra = ""; 331 | fprint(2, "%6d%c %-20s %s%s\n", 332 | t->id, t->system ? 's' : ' ', 333 | t->name, t->state, extra); 334 | } 335 | } 336 | 337 | /* 338 | * startup 339 | */ 340 | 341 | static int taskargc; 342 | static char **taskargv; 343 | int mainstacksize; 344 | 345 | static void 346 | taskmainstart(void *v) 347 | { 348 | taskname("taskmain"); 349 | taskmain(taskargc, taskargv); 350 | } 351 | 352 | int 353 | main(int argc, char **argv) 354 | { 355 | struct sigaction sa, osa; 356 | 357 | memset(&sa, 0, sizeof sa); 358 | sa.sa_handler = taskinfo; 359 | sa.sa_flags = SA_RESTART; 360 | sigaction(SIGQUIT, &sa, &osa); 361 | 362 | #ifdef SIGINFO 363 | sigaction(SIGINFO, &sa, &osa); 364 | #endif 365 | 366 | argv0 = argv[0]; 367 | taskargc = argc; 368 | taskargv = argv; 369 | 370 | if(mainstacksize == 0) 371 | mainstacksize = 256*1024; 372 | taskcreate(taskmainstart, nil, mainstacksize); 373 | taskscheduler(); 374 | fprint(2, "taskscheduler returned in main!\n"); 375 | abort(); 376 | return 0; 377 | } 378 | 379 | /* 380 | * hooray for linked lists 381 | */ 382 | void 383 | addtask(Tasklist *l, Task *t) 384 | { 385 | if(l->tail){ 386 | l->tail->next = t; 387 | t->prev = l->tail; 388 | }else{ 389 | l->head = t; 390 | t->prev = nil; 391 | } 392 | l->tail = t; 393 | t->next = nil; 394 | } 395 | 396 | void 397 | deltask(Tasklist *l, Task *t) 398 | { 399 | if(t->prev) 400 | t->prev->next = t->next; 401 | else 402 | l->head = t->next; 403 | if(t->next) 404 | t->next->prev = t->prev; 405 | else 406 | l->tail = t->prev; 407 | } 408 | 409 | unsigned int 410 | taskid(void) 411 | { 412 | return taskrunning->id; 413 | } 414 | 415 | -------------------------------------------------------------------------------- /task.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #ifndef _TASK_H_ 4 | #define _TASK_H_ 1 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | /* 14 | * basic procs and threads 15 | */ 16 | 17 | typedef struct Task Task; 18 | typedef struct Tasklist Tasklist; 19 | 20 | int anyready(void); 21 | int taskcreate(void (*f)(void *arg), void *arg, unsigned int stacksize); 22 | void taskexit(int); 23 | void taskexitall(int); 24 | void taskmain(int argc, char *argv[]); 25 | int taskyield(void); 26 | void** taskdata(void); 27 | void needstack(int); 28 | void taskname(char*, ...); 29 | void taskstate(char*, ...); 30 | char* taskgetname(void); 31 | char* taskgetstate(void); 32 | void tasksystem(void); 33 | unsigned int taskdelay(unsigned int); 34 | unsigned int taskid(void); 35 | 36 | struct Tasklist /* used internally */ 37 | { 38 | Task *head; 39 | Task *tail; 40 | }; 41 | 42 | /* 43 | * queuing locks 44 | */ 45 | typedef struct QLock QLock; 46 | struct QLock 47 | { 48 | Task *owner; 49 | Tasklist waiting; 50 | }; 51 | 52 | void qlock(QLock*); 53 | int canqlock(QLock*); 54 | void qunlock(QLock*); 55 | 56 | /* 57 | * reader-writer locks 58 | */ 59 | typedef struct RWLock RWLock; 60 | struct RWLock 61 | { 62 | int readers; 63 | Task *writer; 64 | Tasklist rwaiting; 65 | Tasklist wwaiting; 66 | }; 67 | 68 | void rlock(RWLock*); 69 | int canrlock(RWLock*); 70 | void runlock(RWLock*); 71 | 72 | void wlock(RWLock*); 73 | int canwlock(RWLock*); 74 | void wunlock(RWLock*); 75 | 76 | /* 77 | * sleep and wakeup (condition variables) 78 | */ 79 | typedef struct Rendez Rendez; 80 | 81 | struct Rendez 82 | { 83 | QLock *l; 84 | Tasklist waiting; 85 | }; 86 | 87 | void tasksleep(Rendez*); 88 | int taskwakeup(Rendez*); 89 | int taskwakeupall(Rendez*); 90 | 91 | /* 92 | * channel communication 93 | */ 94 | typedef struct Alt Alt; 95 | typedef struct Altarray Altarray; 96 | typedef struct Channel Channel; 97 | 98 | enum 99 | { 100 | CHANEND, 101 | CHANSND, 102 | CHANRCV, 103 | CHANNOP, 104 | CHANNOBLK, 105 | }; 106 | 107 | struct Alt 108 | { 109 | Channel *c; 110 | void *v; 111 | unsigned int op; 112 | Task *task; 113 | Alt *xalt; 114 | }; 115 | 116 | struct Altarray 117 | { 118 | Alt **a; 119 | unsigned int n; 120 | unsigned int m; 121 | }; 122 | 123 | struct Channel 124 | { 125 | unsigned int bufsize; 126 | unsigned int elemsize; 127 | unsigned char *buf; 128 | unsigned int nbuf; 129 | unsigned int off; 130 | Altarray asend; 131 | Altarray arecv; 132 | char *name; 133 | }; 134 | 135 | int chanalt(Alt *alts); 136 | Channel* chancreate(int elemsize, int elemcnt); 137 | void chanfree(Channel *c); 138 | int chaninit(Channel *c, int elemsize, int elemcnt); 139 | int channbrecv(Channel *c, void *v); 140 | void* channbrecvp(Channel *c); 141 | unsigned long channbrecvul(Channel *c); 142 | int channbsend(Channel *c, void *v); 143 | int channbsendp(Channel *c, void *v); 144 | int channbsendul(Channel *c, unsigned long v); 145 | int chanrecv(Channel *c, void *v); 146 | void* chanrecvp(Channel *c); 147 | unsigned long chanrecvul(Channel *c); 148 | int chansend(Channel *c, void *v); 149 | int chansendp(Channel *c, void *v); 150 | int chansendul(Channel *c, unsigned long v); 151 | 152 | /* 153 | * Threaded I/O. 154 | */ 155 | int fdread(int, void*, int); 156 | int fdread1(int, void*, int); /* always uses fdwait */ 157 | int fdwrite(int, void*, int); 158 | void fdwait(int, int); 159 | int fdnoblock(int); 160 | 161 | void fdtask(void*); 162 | 163 | /* 164 | * Network dialing - sets non-blocking automatically 165 | */ 166 | enum 167 | { 168 | UDP = 0, 169 | TCP = 1, 170 | }; 171 | 172 | int netannounce(int, char*, int); 173 | int netaccept(int, char*, int*); 174 | int netdial(int, char*, int); 175 | int netlookup(char*, uint32_t*); /* blocks entire program! */ 176 | int netdial(int, char*, int); 177 | 178 | #ifdef __cplusplus 179 | } 180 | #endif 181 | #endif 182 | 183 | -------------------------------------------------------------------------------- /task.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 86BDBD7812E32D0D00EB4465 /* taskimpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD6912E32D0D00EB4465 /* taskimpl.h */; }; 11 | 86BDBD7912E32D0D00EB4465 /* task.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD6A12E32D0D00EB4465 /* task.h */; }; 12 | 86BDBD7A12E32D0D00EB4465 /* task.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD6B12E32D0D00EB4465 /* task.c */; }; 13 | 86BDBD7B12E32D0D00EB4465 /* rendez.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD6C12E32D0D00EB4465 /* rendez.c */; }; 14 | 86BDBD7C12E32D0D00EB4465 /* qlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD6D12E32D0D00EB4465 /* qlock.c */; }; 15 | 86BDBD7D12E32D0D00EB4465 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD6E12E32D0D00EB4465 /* print.c */; }; 16 | 86BDBD7E12E32D0D00EB4465 /* power-ucontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD6F12E32D0D00EB4465 /* power-ucontext.h */; }; 17 | 86BDBD7F12E32D0D00EB4465 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD7012E32D0D00EB4465 /* net.c */; }; 18 | 86BDBD8012E32D0D00EB4465 /* mips-ucontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD7112E32D0D00EB4465 /* mips-ucontext.h */; }; 19 | 86BDBD8112E32D0D00EB4465 /* fd.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD7212E32D0D00EB4465 /* fd.c */; }; 20 | 86BDBD8212E32D0D00EB4465 /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD7312E32D0D00EB4465 /* context.c */; }; 21 | 86BDBD8312E32D0D00EB4465 /* channel.c in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD7412E32D0D00EB4465 /* channel.c */; }; 22 | 86BDBD8412E32D0D00EB4465 /* asm.S in Sources */ = {isa = PBXBuildFile; fileRef = 86BDBD7512E32D0D00EB4465 /* asm.S */; }; 23 | 86BDBD8512E32D0D00EB4465 /* amd64-ucontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD7612E32D0D00EB4465 /* amd64-ucontext.h */; }; 24 | 86BDBD8612E32D0D00EB4465 /* 386-ucontext.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BDBD7712E32D0D00EB4465 /* 386-ucontext.h */; }; 25 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 862F02A212E427D500C9FCA5 /* primes.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; path = primes.c; sourceTree = ""; }; 30 | 86BDBD6912E32D0D00EB4465 /* taskimpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = taskimpl.h; sourceTree = ""; }; 31 | 86BDBD6A12E32D0D00EB4465 /* task.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = task.h; sourceTree = ""; }; 32 | 86BDBD6B12E32D0D00EB4465 /* task.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = task.c; sourceTree = ""; }; 33 | 86BDBD6C12E32D0D00EB4465 /* rendez.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rendez.c; sourceTree = ""; }; 34 | 86BDBD6D12E32D0D00EB4465 /* qlock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = qlock.c; sourceTree = ""; }; 35 | 86BDBD6E12E32D0D00EB4465 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = ""; }; 36 | 86BDBD6F12E32D0D00EB4465 /* power-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "power-ucontext.h"; sourceTree = ""; }; 37 | 86BDBD7012E32D0D00EB4465 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = net.c; sourceTree = ""; }; 38 | 86BDBD7112E32D0D00EB4465 /* mips-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mips-ucontext.h"; sourceTree = ""; }; 39 | 86BDBD7212E32D0D00EB4465 /* fd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fd.c; sourceTree = ""; }; 40 | 86BDBD7312E32D0D00EB4465 /* context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = context.c; sourceTree = ""; }; 41 | 86BDBD7412E32D0D00EB4465 /* channel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = channel.c; sourceTree = ""; }; 42 | 86BDBD7512E32D0D00EB4465 /* asm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = asm.S; sourceTree = ""; }; 43 | 86BDBD7612E32D0D00EB4465 /* amd64-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "amd64-ucontext.h"; sourceTree = ""; }; 44 | 86BDBD7712E32D0D00EB4465 /* 386-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "386-ucontext.h"; sourceTree = ""; }; 45 | AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | D2AAC07E0554694100DB518D /* libtask.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtask.a; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | D2AAC07C0554694100DB518D /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 034768DFFF38A50411DB9C8B /* Products */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | D2AAC07E0554694100DB518D /* libtask.a */, 65 | ); 66 | name = Products; 67 | sourceTree = ""; 68 | }; 69 | 0867D691FE84028FC02AAC07 /* task */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 08FB77AEFE84172EC02AAC07 /* Classes */, 73 | 32C88DFF0371C24200C91783 /* Other Sources */, 74 | 0867D69AFE84028FC02AAC07 /* Frameworks */, 75 | 034768DFFF38A50411DB9C8B /* Products */, 76 | ); 77 | name = task; 78 | sourceTree = ""; 79 | }; 80 | 0867D69AFE84028FC02AAC07 /* Frameworks */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | AACBBE490F95108600F1A2B1 /* Foundation.framework */, 84 | ); 85 | name = Frameworks; 86 | sourceTree = ""; 87 | }; 88 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 862F02A212E427D500C9FCA5 /* primes.c */, 92 | 86BDBD6912E32D0D00EB4465 /* taskimpl.h */, 93 | 86BDBD6A12E32D0D00EB4465 /* task.h */, 94 | 86BDBD6B12E32D0D00EB4465 /* task.c */, 95 | 86BDBD6C12E32D0D00EB4465 /* rendez.c */, 96 | 86BDBD6D12E32D0D00EB4465 /* qlock.c */, 97 | 86BDBD6E12E32D0D00EB4465 /* print.c */, 98 | 86BDBD6F12E32D0D00EB4465 /* power-ucontext.h */, 99 | 86BDBD7012E32D0D00EB4465 /* net.c */, 100 | 86BDBD7112E32D0D00EB4465 /* mips-ucontext.h */, 101 | 86BDBD7212E32D0D00EB4465 /* fd.c */, 102 | 86BDBD7312E32D0D00EB4465 /* context.c */, 103 | 86BDBD7412E32D0D00EB4465 /* channel.c */, 104 | 86BDBD7512E32D0D00EB4465 /* asm.S */, 105 | 86BDBD7612E32D0D00EB4465 /* amd64-ucontext.h */, 106 | 86BDBD7712E32D0D00EB4465 /* 386-ucontext.h */, 107 | ); 108 | name = Classes; 109 | sourceTree = ""; 110 | }; 111 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | ); 115 | name = "Other Sources"; 116 | sourceTree = ""; 117 | }; 118 | /* End PBXGroup section */ 119 | 120 | /* Begin PBXHeadersBuildPhase section */ 121 | D2AAC07A0554694100DB518D /* Headers */ = { 122 | isa = PBXHeadersBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | 86BDBD7812E32D0D00EB4465 /* taskimpl.h in Headers */, 126 | 86BDBD7912E32D0D00EB4465 /* task.h in Headers */, 127 | 86BDBD7E12E32D0D00EB4465 /* power-ucontext.h in Headers */, 128 | 86BDBD8012E32D0D00EB4465 /* mips-ucontext.h in Headers */, 129 | 86BDBD8512E32D0D00EB4465 /* amd64-ucontext.h in Headers */, 130 | 86BDBD8612E32D0D00EB4465 /* 386-ucontext.h in Headers */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXHeadersBuildPhase section */ 135 | 136 | /* Begin PBXNativeTarget section */ 137 | D2AAC07D0554694100DB518D /* task */ = { 138 | isa = PBXNativeTarget; 139 | buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "task" */; 140 | buildPhases = ( 141 | D2AAC07A0554694100DB518D /* Headers */, 142 | D2AAC07B0554694100DB518D /* Sources */, 143 | D2AAC07C0554694100DB518D /* Frameworks */, 144 | ); 145 | buildRules = ( 146 | ); 147 | dependencies = ( 148 | ); 149 | name = task; 150 | productName = task; 151 | productReference = D2AAC07E0554694100DB518D /* libtask.a */; 152 | productType = "com.apple.product-type.library.static"; 153 | }; 154 | /* End PBXNativeTarget section */ 155 | 156 | /* Begin PBXProject section */ 157 | 0867D690FE84028FC02AAC07 /* Project object */ = { 158 | isa = PBXProject; 159 | buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "task" */; 160 | compatibilityVersion = "Xcode 3.1"; 161 | developmentRegion = English; 162 | hasScannedForEncodings = 1; 163 | knownRegions = ( 164 | English, 165 | Japanese, 166 | French, 167 | German, 168 | ); 169 | mainGroup = 0867D691FE84028FC02AAC07 /* task */; 170 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 171 | projectDirPath = ""; 172 | projectRoot = ""; 173 | targets = ( 174 | D2AAC07D0554694100DB518D /* task */, 175 | ); 176 | }; 177 | /* End PBXProject section */ 178 | 179 | /* Begin PBXSourcesBuildPhase section */ 180 | D2AAC07B0554694100DB518D /* Sources */ = { 181 | isa = PBXSourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | 86BDBD7A12E32D0D00EB4465 /* task.c in Sources */, 185 | 86BDBD7B12E32D0D00EB4465 /* rendez.c in Sources */, 186 | 86BDBD7C12E32D0D00EB4465 /* qlock.c in Sources */, 187 | 86BDBD7D12E32D0D00EB4465 /* print.c in Sources */, 188 | 86BDBD7F12E32D0D00EB4465 /* net.c in Sources */, 189 | 86BDBD8112E32D0D00EB4465 /* fd.c in Sources */, 190 | 86BDBD8212E32D0D00EB4465 /* context.c in Sources */, 191 | 86BDBD8312E32D0D00EB4465 /* channel.c in Sources */, 192 | 86BDBD8412E32D0D00EB4465 /* asm.S in Sources */, 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXSourcesBuildPhase section */ 197 | 198 | /* Begin XCBuildConfiguration section */ 199 | 1DEB921F08733DC00010E9CD /* Debug */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 204 | COPY_PHASE_STRIP = NO; 205 | DSTROOT = /tmp/task.dst; 206 | GCC_DYNAMIC_NO_PIC = NO; 207 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 208 | GCC_MODEL_TUNING = G5; 209 | GCC_OPTIMIZATION_LEVEL = 0; 210 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 211 | GCC_PREFIX_HEADER = ""; 212 | INSTALL_PATH = /usr/local/lib; 213 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES; 214 | PRODUCT_NAME = task; 215 | }; 216 | name = Debug; 217 | }; 218 | 1DEB922008733DC00010E9CD /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 223 | DSTROOT = /tmp/task.dst; 224 | GCC_MODEL_TUNING = G5; 225 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 226 | GCC_PREFIX_HEADER = ""; 227 | INSTALL_PATH = /usr/local/lib; 228 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES; 229 | PRODUCT_NAME = task; 230 | }; 231 | name = Release; 232 | }; 233 | 1DEB922308733DC00010E9CD /* Debug */ = { 234 | isa = XCBuildConfiguration; 235 | buildSettings = { 236 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 237 | GCC_C_LANGUAGE_STANDARD = c99; 238 | GCC_OPTIMIZATION_LEVEL = 0; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | OTHER_LDFLAGS = "-ObjC"; 242 | PREBINDING = NO; 243 | SDKROOT = iphoneos4.1; 244 | }; 245 | name = Debug; 246 | }; 247 | 1DEB922408733DC00010E9CD /* Release */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 251 | GCC_C_LANGUAGE_STANDARD = c99; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | OTHER_LDFLAGS = "-ObjC"; 255 | PREBINDING = NO; 256 | SDKROOT = iphoneos4.1; 257 | }; 258 | name = Release; 259 | }; 260 | /* End XCBuildConfiguration section */ 261 | 262 | /* Begin XCConfigurationList section */ 263 | 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "task" */ = { 264 | isa = XCConfigurationList; 265 | buildConfigurations = ( 266 | 1DEB921F08733DC00010E9CD /* Debug */, 267 | 1DEB922008733DC00010E9CD /* Release */, 268 | ); 269 | defaultConfigurationIsVisible = 0; 270 | defaultConfigurationName = Release; 271 | }; 272 | 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "task" */ = { 273 | isa = XCConfigurationList; 274 | buildConfigurations = ( 275 | 1DEB922308733DC00010E9CD /* Debug */, 276 | 1DEB922408733DC00010E9CD /* Release */, 277 | ); 278 | defaultConfigurationIsVisible = 0; 279 | defaultConfigurationName = Release; 280 | }; 281 | /* End XCConfigurationList section */ 282 | }; 283 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 284 | } 285 | -------------------------------------------------------------------------------- /taskimpl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #if defined(__sun__) 4 | # define __EXTENSIONS__ 1 /* SunOS */ 5 | # if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) 6 | /* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */ 7 | # else 8 | # define __MAKECONTEXT_V2_SOURCE 1 9 | # endif 10 | #endif 11 | 12 | #define USE_UCONTEXT 1 13 | 14 | #if defined(__OpenBSD__) || defined(__mips__) 15 | #undef USE_UCONTEXT 16 | #define USE_UCONTEXT 0 17 | #endif 18 | 19 | #if defined(__APPLE__) 20 | #include 21 | #if defined(MAC_OS_X_VERSION_10_5) 22 | #undef USE_UCONTEXT 23 | #define USE_UCONTEXT 0 24 | #endif 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #if USE_UCONTEXT 39 | #include 40 | #endif 41 | #include 42 | #include 43 | #include "task.h" 44 | 45 | #define nil ((void*)0) 46 | #define nelem(x) (sizeof(x)/sizeof((x)[0])) 47 | 48 | #define ulong task_ulong 49 | #define uint task_uint 50 | #define uchar task_uchar 51 | #define ushort task_ushort 52 | #define uvlong task_uvlong 53 | #define vlong task_vlong 54 | 55 | typedef unsigned long ulong; 56 | typedef unsigned int uint; 57 | typedef unsigned char uchar; 58 | typedef unsigned short ushort; 59 | typedef unsigned long long uvlong; 60 | typedef long long vlong; 61 | 62 | #define print task_print 63 | #define fprint task_fprint 64 | #define snprint task_snprint 65 | #define seprint task_seprint 66 | #define vprint task_vprint 67 | #define vfprint task_vfprint 68 | #define vsnprint task_vsnprint 69 | #define vseprint task_vseprint 70 | #define strecpy task_strecpy 71 | 72 | int print(char*, ...); 73 | int fprint(int, char*, ...); 74 | char *snprint(char*, uint, char*, ...); 75 | char *seprint(char*, char*, char*, ...); 76 | int vprint(char*, va_list); 77 | int vfprint(int, char*, va_list); 78 | char *vsnprint(char*, uint, char*, va_list); 79 | char *vseprint(char*, char*, char*, va_list); 80 | char *strecpy(char*, char*, char*); 81 | 82 | #if defined(__FreeBSD__) && __FreeBSD__ < 5 83 | extern int getmcontext(mcontext_t*); 84 | extern void setmcontext(const mcontext_t*); 85 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 86 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 87 | extern int swapcontext(ucontext_t*, const ucontext_t*); 88 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 89 | #endif 90 | 91 | #if defined(__APPLE__) 92 | # define mcontext libthread_mcontext 93 | # define mcontext_t libthread_mcontext_t 94 | # define ucontext libthread_ucontext 95 | # define ucontext_t libthread_ucontext_t 96 | # if defined(__i386__) 97 | # include "386-ucontext.h" 98 | # elif defined(__x86_64__) 99 | # include "amd64-ucontext.h" 100 | # elif defined(__arm__) 101 | # include "arm-ucontext.h" 102 | # else 103 | # include "power-ucontext.h" 104 | # endif 105 | #endif 106 | 107 | #if defined(__OpenBSD__) 108 | # define mcontext libthread_mcontext 109 | # define mcontext_t libthread_mcontext_t 110 | # define ucontext libthread_ucontext 111 | # define ucontext_t libthread_ucontext_t 112 | # if defined __i386__ 113 | # include "386-ucontext.h" 114 | # else 115 | # include "power-ucontext.h" 116 | # endif 117 | extern pid_t rfork_thread(int, void*, int(*)(void*), void*); 118 | #endif 119 | 120 | #if 0 && defined(__sun__) 121 | # define mcontext libthread_mcontext 122 | # define mcontext_t libthread_mcontext_t 123 | # define ucontext libthread_ucontext 124 | # define ucontext_t libthread_ucontext_t 125 | # include "sparc-ucontext.h" 126 | #endif 127 | 128 | #if defined(__arm__) && defined(__linux__) 129 | int getmcontext(mcontext_t*); 130 | void setmcontext(const mcontext_t*); 131 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 132 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 133 | #endif 134 | 135 | #if defined(__mips__) 136 | #include "mips-ucontext.h" 137 | int getmcontext(mcontext_t*); 138 | void setmcontext(const mcontext_t*); 139 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 140 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 141 | #endif 142 | 143 | typedef struct Context Context; 144 | 145 | enum 146 | { 147 | STACK = 8192 148 | }; 149 | 150 | struct Context 151 | { 152 | ucontext_t uc; 153 | }; 154 | 155 | struct Task 156 | { 157 | char name[256]; // offset known to acid 158 | char state[256]; 159 | Task *next; 160 | Task *prev; 161 | Task *allnext; 162 | Task *allprev; 163 | Context context; 164 | uvlong alarmtime; 165 | uint id; 166 | uchar *stk; 167 | uint stksize; 168 | int exiting; 169 | int alltaskslot; 170 | int system; 171 | int ready; 172 | void (*startfn)(void*); 173 | void *startarg; 174 | void *udata; 175 | }; 176 | 177 | void taskready(Task*); 178 | void taskswitch(void); 179 | 180 | void addtask(Tasklist*, Task*); 181 | void deltask(Tasklist*, Task*); 182 | 183 | extern Task *taskrunning; 184 | extern int taskcount; 185 | -------------------------------------------------------------------------------- /tcpproxy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum 10 | { 11 | STACK = 32768 12 | }; 13 | 14 | char *server; 15 | int port; 16 | void proxytask(void*); 17 | void rwtask(void*); 18 | 19 | int* 20 | mkfd2(int fd1, int fd2) 21 | { 22 | int *a; 23 | 24 | a = malloc(2*sizeof a[0]); 25 | if(a == 0){ 26 | fprintf(stderr, "out of memory\n"); 27 | abort(); 28 | } 29 | a[0] = fd1; 30 | a[1] = fd2; 31 | return a; 32 | } 33 | 34 | void 35 | taskmain(int argc, char **argv) 36 | { 37 | int cfd, fd; 38 | int rport; 39 | char remote[16]; 40 | 41 | if(argc != 4){ 42 | fprintf(stderr, "usage: tcpproxy localport server remoteport\n"); 43 | taskexitall(1); 44 | } 45 | server = argv[2]; 46 | port = atoi(argv[3]); 47 | 48 | if((fd = netannounce(TCP, 0, atoi(argv[1]))) < 0){ 49 | fprintf(stderr, "cannot announce on tcp port %d: %s\n", atoi(argv[1]), strerror(errno)); 50 | taskexitall(1); 51 | } 52 | fdnoblock(fd); 53 | while((cfd = netaccept(fd, remote, &rport)) >= 0){ 54 | fprintf(stderr, "connection from %s:%d\n", remote, rport); 55 | taskcreate(proxytask, (void*)cfd, STACK); 56 | } 57 | } 58 | 59 | void 60 | proxytask(void *v) 61 | { 62 | int fd, remotefd; 63 | 64 | fd = (int)v; 65 | if((remotefd = netdial(TCP, server, port)) < 0){ 66 | close(fd); 67 | return; 68 | } 69 | 70 | fprintf(stderr, "connected to %s:%d\n", server, port); 71 | 72 | taskcreate(rwtask, mkfd2(fd, remotefd), STACK); 73 | taskcreate(rwtask, mkfd2(remotefd, fd), STACK); 74 | } 75 | 76 | void 77 | rwtask(void *v) 78 | { 79 | int *a, rfd, wfd, n; 80 | char buf[2048]; 81 | 82 | a = v; 83 | rfd = a[0]; 84 | wfd = a[1]; 85 | free(a); 86 | 87 | while((n = fdread(rfd, buf, sizeof buf)) > 0) 88 | fdwrite(wfd, buf, n); 89 | shutdown(wfd, SHUT_WR); 90 | close(rfd); 91 | } 92 | 93 | -------------------------------------------------------------------------------- /testdelay.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum { STACK = 32768 }; 9 | 10 | Channel *c; 11 | 12 | void 13 | delaytask(void *v) 14 | { 15 | taskdelay((int)v); 16 | printf("awake after %d ms\n", (int)v); 17 | chansendul(c, 0); 18 | } 19 | 20 | void 21 | taskmain(int argc, char **argv) 22 | { 23 | int i, n; 24 | 25 | c = chancreate(sizeof(unsigned long), 0); 26 | 27 | n = 0; 28 | for(i=1; i 2 | 3 | void 4 | taskmain(int argc, char *argv[]) 5 | { 6 | taskdelay(1000); 7 | } 8 | --------------------------------------------------------------------------------