├── .gitignore ├── LICENSE ├── README.md ├── fiber.h ├── fiber.sln ├── fiber.vcxproj ├── fiber.vcxproj.filters ├── fiber.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── libtask ├── 386-ucontext.h ├── COPYRIGHT ├── Makefile ├── README ├── amd64-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 ├── taskimpl.h ├── tcpproxy.c ├── testdelay.c └── testdelay1.c ├── makefile └── test.c /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs/fiber/v14 2 | /fiber.xcodeproj/project.xcworkspace/xcuserdata/*.* 3 | /fiber.xcodeproj/xcuserdata/*.* 4 | /Debug 5 | /Release 6 | /x64 7 | /fiber.VC.db 8 | *.DS_Store 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2017 - 2018 Wang Renxin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Fiber 2 | 3 | **Header only cross platform wrapper of fiber API** 4 | 5 | A [fiber](https://en.wikipedia.org/wiki/Fiber_(computer_science)) is a particularly lightweight thread of execution. Which is useful for implementing coroutine, iterator, lightweight thread, etc. 6 | 7 | ### How to use 8 | 9 | Just `#include "fiber.h"` before using this library. 10 | 11 | There are quite few interfaces: 12 | 13 | ~~~~~~~~~~c 14 | FBAPI static bool_t fiber_is_current(const fiber_t* const fb); 15 | FBAPI static fiber_t* fiber_create(fiber_t* primary, size_t stack, fiber_proc run, void* userdata); 16 | FBAPI static bool_t fiber_delete(fiber_t* fb); 17 | FBAPI static bool_t fiber_switch(fiber_t* fb); 18 | ~~~~~~~~~~ 19 | 20 | Read comments [in code](fiber.h) to get the usage, or start with a simple [example](test.c). 21 | 22 | ### Dependency/Backend 23 | 24 | * Windows backend with [`fiber` functions](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684847(v=vs.85).aspx#fiber_functions) 25 | * POSIX backend with [`setcontext` functions](https://en.wikipedia.org/wiki/Setcontext) 26 | * JavaScript backend with [`asyncify` functions](http://kripken.github.io/emscripten-site/docs/api_reference/emscripten.h.html#asyncify-functions) 27 | 28 | ### Drafting 29 | 30 | This library is supposed to be cross platform as possible. However it's drafting because I've only implemented and tested it on Windows, POSIX and JavaScript platforms. Supporting for more platforms will be added in the future; any pull requests are welcome. 31 | -------------------------------------------------------------------------------- /fiber.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Fiber - Header only cross platform wrapper of fiber API 3 | ** 4 | ** For the latest info, see https://github.com/paladin-t/fiber/ 5 | ** 6 | ** Copyright (C) 2017 - 2018 Wang Renxin 7 | ** 8 | ** Just #include "fiber.h" before using this library. 9 | ** 10 | ** Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | ** this software and associated documentation files (the "Software"), to deal in 12 | ** the Software without restriction, including without limitation the rights to 13 | ** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 14 | ** the Software, and to permit persons to whom the Software is furnished to do so, 15 | ** subject to the following conditions: 16 | ** 17 | ** The above copyright notice and this permission notice shall be included in all 18 | ** copies or substantial portions of the Software. 19 | ** 20 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 22 | ** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 23 | ** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 24 | ** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25 | ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | #ifndef __FIBER_H__ 29 | #define __FIBER_H__ 30 | 31 | #if defined __EMSCRIPTEN__ 32 | # define FB_OS_EMSCRIPTEN 33 | #elif defined _WIN64 34 | # define FB_OS_WIN 35 | # define FB_OS_WIN64 36 | #elif defined _WIN32 37 | # define FB_OS_WIN 38 | # define FB_OS_WIN32 39 | #elif defined __APPLE__ 40 | # include 41 | # define FB_OS_APPLE 42 | # if defined TARGET_OS_IPHONE && TARGET_OS_IPHONE == 1 43 | # define FB_OS_IOS 44 | # elif defined TARGET_IPHONE_SIMULATOR && TARGET_IPHONE_SIMULATOR == 1 45 | # define FB_OS_IOS_SIM 46 | # elif defined TARGET_OS_MAC && TARGET_OS_MAC == 1 47 | # define FB_OS_MAC 48 | # endif 49 | #elif defined __ANDROID__ 50 | # define FB_OS_ANDROID 51 | #elif defined __linux__ 52 | # define FB_OS_LINUX 53 | #elif defined __unix__ 54 | # define FB_OS_UNIX 55 | #else 56 | # define FB_OS_UNKNOWN 57 | #endif 58 | 59 | #include 60 | #include 61 | #include 62 | #if defined FB_OS_EMSCRIPTEN 63 | # include 64 | #elif defined FB_OS_WIN 65 | # include 66 | #elif defined FB_OS_APPLE 67 | /* The `context` API was deprecated on Apple platforms, so we need an alternative. */ 68 | # ifdef __cplusplus 69 | extern "C" { 70 | # include "taskimpl.h" 71 | } 72 | # else /* __cplusplus */ 73 | # include "taskimpl.h" 74 | # endif /* __cplusplus */ 75 | #else /* Backend macro. */ 76 | # include 77 | #endif /* Backend macro. */ 78 | 79 | #ifdef __cplusplus 80 | extern "C" { 81 | #endif /* __cplusplus */ 82 | 83 | /* 84 | ** {======================================================== 85 | ** Declaration 86 | */ 87 | 88 | #if INTPTR_MAX == INT32_MAX 89 | # define FB32BITENV 90 | #elif INTPTR_MAX == INT64_MAX 91 | # define FB64BITENV 92 | #else 93 | # error "Environment not 32 or 64-bit." 94 | #endif 95 | 96 | #if defined FB_OS_APPLE && defined FB64BITENV 97 | # define FBSEPCMP 98 | #endif /* FB_OS_APPLE && FB64BITENV */ 99 | 100 | #ifndef FBAPI 101 | # define FBAPI 102 | #endif /* FBAPI */ 103 | 104 | #ifndef FBIMPL 105 | # define FBIMPL 106 | #endif /* FBIMPL */ 107 | 108 | #ifndef bool_t 109 | # define bool_t unsigned char 110 | #endif /* bool_t */ 111 | #ifndef __cplusplus 112 | # ifndef true 113 | # define true (1) 114 | # endif /* true */ 115 | # ifndef false 116 | # define false (0) 117 | # endif /* false */ 118 | #endif /* __cplusplus */ 119 | 120 | /* Redefine `fballoc` and `fbfree` to use other allocator. */ 121 | #ifndef fballoc 122 | # define fballoc malloc 123 | #endif /* fballoc */ 124 | #ifndef fbfree 125 | # define fbfree free 126 | #endif /* fbfree */ 127 | 128 | /* The stack size defaults to 1MB. */ 129 | #ifndef FIBER_STACK_SIZE 130 | # define FIBER_STACK_SIZE (1024 * 1024) 131 | #endif /* FIBER_STACK_SIZE */ 132 | 133 | struct fiber_t; 134 | 135 | /** 136 | * @brief Fiber processor, will callback to this. 137 | * 138 | * @param[in] fb - On which fiber is calling. 139 | */ 140 | typedef void (* fiber_proc)(struct fiber_t* /*fb*/); 141 | 142 | /** 143 | * @brief Fiber structure. 144 | */ 145 | typedef struct fiber_t { 146 | /**< Current fiber, all fibers within the same thread should share the same "current" pointer. */ 147 | struct fiber_t** current; 148 | /**< How much memory is reserved for this fiber. */ 149 | size_t stack_size; 150 | /**< Raw context of this fiber. */ 151 | void* context; 152 | /**< Processer of this fiber, as callback. */ 153 | fiber_proc proc; 154 | /**< Fiber carries some extra data with `userdata`. */ 155 | void* userdata; 156 | } fiber_t; 157 | 158 | /** 159 | * @brief Checks whether a fiber is the current active one. 160 | * 161 | * @param[in] fb - Specific fiber to check with. 162 | * @return - True if `fb` is the current active fiber. 163 | */ 164 | FBAPI static bool_t fiber_is_current(const fiber_t* const fb); 165 | /** 166 | * @brief Creates a fiber. Should create the primary fiber before creating minor fibers. 167 | * 168 | * @param[in] primary - The original primary fiber, pass `NULL` if it's the primary fiber to be created. 169 | * @param[in] stack - Reserved stack size for this fiber, pass 0 if it's the primary fiber to be created, 170 | * or uses `FIBER_STACK_SIZE` for minor fibers. 171 | * @param[in] run - Fiber processor. 172 | * @param[in] userdata - Userdata of fiber. 173 | * @return - Created fiber. 174 | */ 175 | FBAPI static fiber_t* fiber_create(fiber_t* primary, size_t stack, fiber_proc run, void* userdata); 176 | /** 177 | * @brief Deletes a fiber. Should delete minor fibers before deleting the primary fiber. 178 | * 179 | * @param[in] fb - The fiber to be deleted. 180 | * @return - True for succeed. 181 | */ 182 | FBAPI static bool_t fiber_delete(fiber_t* fb); 183 | /** 184 | * @brief Switches to a specific fiber. The `fiber_proc proc` processer will be called. 185 | * 186 | * @param[in] fb - The target fiber to switch to. 187 | * @return - True for succeed. This function returns when some fiber switches back here. 188 | */ 189 | FBAPI static bool_t fiber_switch(fiber_t* fb); 190 | 191 | /* ========================================================} */ 192 | 193 | /* 194 | ** {======================================================== 195 | ** Implementation 196 | */ 197 | 198 | #if defined FB_OS_EMSCRIPTEN 199 | 200 | typedef struct emscripten_context_t { 201 | fiber_t* primary; 202 | union { 203 | emscripten_coroutine emco; 204 | fiber_t* next; 205 | }; 206 | } emscripten_context_t; 207 | 208 | FBIMPL static void fiber_proc_impl(fiber_t* fb) { 209 | if (!fb) return; 210 | 211 | fb->proc(fb); 212 | } 213 | 214 | FBAPI static bool_t fiber_is_current(const fiber_t* const fb) { 215 | if (!fb) return false; 216 | 217 | return *fb->current == fb; 218 | } 219 | 220 | FBAPI static fiber_t* fiber_create(fiber_t* primary, size_t stack, fiber_proc run, void* userdata) { 221 | fiber_t* ret = 0; 222 | emscripten_context_t* ctx = 0; 223 | if ((!primary && run) || (primary && !run)) return ret; 224 | ret = (fiber_t*)fballoc(sizeof(fiber_t)); 225 | ret->proc = run; 226 | ret->userdata = userdata; 227 | if (primary && run) { 228 | if (!stack) stack = FIBER_STACK_SIZE; 229 | ret->current = primary->current; 230 | ret->stack_size = stack; 231 | ctx = (emscripten_context_t*)fballoc(sizeof(emscripten_context_t)); 232 | memset(ctx, 0, sizeof(emscripten_context_t)); 233 | ctx->primary = primary; 234 | ctx->emco = emscripten_coroutine_create((em_arg_callback_func)fiber_proc_impl, ret, stack); 235 | ret->context = ctx; 236 | } else { 237 | ret->current = (fiber_t**)fballoc(sizeof(fiber_t*)); 238 | *ret->current = ret; 239 | ret->stack_size = 0; 240 | ctx = (emscripten_context_t*)fballoc(sizeof(emscripten_context_t)); 241 | memset(ctx, 0, sizeof(emscripten_context_t)); 242 | ctx->primary = ret; 243 | ret->context = ctx; 244 | } 245 | 246 | return ret; 247 | } 248 | 249 | FBAPI static bool_t fiber_delete(fiber_t* fb) { 250 | emscripten_context_t* ctx = 0; 251 | if (!fb) return false; 252 | ctx = (emscripten_context_t*)fb->context; 253 | if (fb->proc) { 254 | // Using `free` to clean up the emscripten coroutine, this is an undocumented usage, 255 | // see https://github.com/kripken/emscripten/issues/6540 for discussion. 256 | free(ctx->emco); 257 | fbfree(ctx); 258 | } else { 259 | fbfree(ctx); 260 | fbfree(fb->current); 261 | } 262 | fbfree(fb); 263 | 264 | return true; 265 | } 266 | 267 | FBAPI static bool_t fiber_switch(fiber_t* fb) { 268 | fiber_t* prev = 0; 269 | fiber_t* primary = 0; 270 | emscripten_context_t* ctx = 0; 271 | if (!fb) return false; 272 | prev = *fb->current; 273 | *fb->current = fb; 274 | primary = (fiber_t*)((emscripten_context_t*)fb->context)->primary; 275 | ctx = (emscripten_context_t*)primary->context; 276 | ctx->next = fb; 277 | if (prev->proc) { 278 | emscripten_yield(); 279 | } else { 280 | while (ctx->next && ctx->next != primary) { 281 | emscripten_context_t* to = (emscripten_context_t*)ctx->next->context; 282 | *fb->current = ctx->next; 283 | emscripten_coroutine_next(to->emco); 284 | } 285 | } 286 | 287 | return true; 288 | } 289 | 290 | #elif defined FB_OS_WIN 291 | 292 | typedef LPFIBER_START_ROUTINE FiberRoutine; 293 | 294 | #ifndef WINAPI 295 | # define WINAPI 296 | #endif /* WINAPI */ 297 | 298 | #ifndef FIBERAPI 299 | # define FIBERAPI WINAPI 300 | #endif /* FIBERAPI */ 301 | 302 | FBIMPL static void FIBERAPI fiber_proc_impl(fiber_t* fb) { 303 | if (!fb) return; 304 | 305 | fb->proc(fb); 306 | } 307 | 308 | FBAPI static bool_t fiber_is_current(const fiber_t* const fb) { 309 | if (!fb) return false; 310 | 311 | return *fb->current == fb; 312 | } 313 | 314 | FBAPI static fiber_t* fiber_create(fiber_t* primary, size_t stack, fiber_proc run, void* userdata) { 315 | fiber_t* ret = 0; 316 | if ((!primary && run) || (primary && !run)) return ret; 317 | ret = (fiber_t*)fballoc(sizeof(fiber_t)); 318 | ret->proc = run; 319 | ret->userdata = userdata; 320 | if (primary && run) { 321 | if (!stack) stack = FIBER_STACK_SIZE; 322 | ret->current = primary->current; 323 | ret->stack_size = stack; 324 | ret->context = CreateFiber(stack, (FiberRoutine)fiber_proc_impl, ret); 325 | } else { 326 | ret->current = (fiber_t**)fballoc(sizeof(fiber_t*)); 327 | *ret->current = ret; 328 | ret->stack_size = 0; 329 | ret->context = ConvertThreadToFiber(0); 330 | } 331 | 332 | return ret; 333 | } 334 | 335 | FBAPI static bool_t fiber_delete(fiber_t* fb) { 336 | if (!fb) return false; 337 | if (fb->proc) 338 | DeleteFiber(fb->context); 339 | else 340 | fbfree(fb->current); 341 | fbfree(fb); 342 | 343 | return true; 344 | } 345 | 346 | FBAPI static bool_t fiber_switch(fiber_t* fb) { 347 | if (!fb) return false; 348 | *fb->current = fb; 349 | SwitchToFiber(fb->context); 350 | 351 | return true; 352 | } 353 | 354 | #else /* Backend macro. */ 355 | 356 | #if defined FBSEPCMP 357 | FBIMPL static void fiber_proc_impl(unsigned fst, unsigned scd) { 358 | uintptr_t ptr = ((uintptr_t)fst) | ((uintptr_t)scd << 32); 359 | fiber_t* fb = (fiber_t*)ptr; 360 | if (!fb) return; 361 | 362 | fb->proc(fb); 363 | } 364 | #else /* FBSEPCMP */ 365 | FBIMPL static void fiber_proc_impl(fiber_t* fb) { 366 | if (!fb) return; 367 | 368 | fb->proc(fb); 369 | } 370 | #endif /* FBSEPCMP */ 371 | 372 | FBAPI static bool_t fiber_is_current(const fiber_t* const fb) { 373 | if (!fb) return false; 374 | 375 | return *fb->current == fb; 376 | } 377 | 378 | FBAPI static fiber_t* fiber_create(fiber_t* primary, size_t stack, fiber_proc run, void* userdata) { 379 | fiber_t* ret = 0; 380 | ucontext_t* ctx = 0; 381 | if ((!primary && run) || (primary && !run)) return ret; 382 | ret = (fiber_t*)fballoc(sizeof(fiber_t)); 383 | ret->proc = run; 384 | ret->userdata = userdata; 385 | if (primary && run) { 386 | if (!stack) stack = FIBER_STACK_SIZE; 387 | ctx = (ucontext_t*)fballoc(sizeof(ucontext_t)); 388 | memset(ctx, 0, sizeof(ucontext_t)); 389 | getcontext(ctx); 390 | ctx->uc_stack.ss_sp = fballoc(stack); 391 | ctx->uc_stack.ss_size = stack; 392 | ctx->uc_stack.ss_flags = 0; 393 | #if defined FBSEPCMP 394 | do { 395 | uintptr_t fst = (uintptr_t)ret; 396 | uintptr_t scd = (uintptr_t)ret; 397 | fst &= 0x00000000ffffffff; 398 | scd >>= 32; 399 | makecontext(ctx, (void(*)())fiber_proc_impl, 2, (unsigned)fst, (unsigned)scd); 400 | } while (0); 401 | #else /* FBSEPCMP */ 402 | makecontext(ctx, (void(*)())fiber_proc_impl, 1, ret); 403 | #endif /* FBSEPCMP */ 404 | ret->current = primary->current; 405 | ret->stack_size = stack; 406 | ret->context = ctx; 407 | } else { 408 | ret->current = (fiber_t**)fballoc(sizeof(fiber_t*)); 409 | ctx = (ucontext_t*)fballoc(sizeof(ucontext_t)); 410 | memset(ctx, 0, sizeof(ucontext_t)); 411 | *ret->current = ret; 412 | ret->stack_size = 0; 413 | ret->context = ctx; 414 | } 415 | 416 | return ret; 417 | } 418 | 419 | FBAPI static bool_t fiber_delete(fiber_t* fb) { 420 | if (!fb) return false; 421 | if (fb->proc) { 422 | ucontext_t* ctx = (ucontext_t*)fb->context; 423 | fbfree(ctx->uc_stack.ss_sp); 424 | } else { 425 | fbfree(fb->current); 426 | } 427 | fbfree(fb->context); 428 | fbfree(fb); 429 | 430 | return true; 431 | } 432 | 433 | FBAPI static bool_t fiber_switch(fiber_t* fb) { 434 | fiber_t* curr = 0; 435 | if (!fb) return false; 436 | curr = *fb->current; 437 | *fb->current = fb; 438 | swapcontext((ucontext_t*)curr->context, (ucontext_t*)fb->context); 439 | 440 | return true; 441 | } 442 | 443 | #endif /* Backend macro. */ 444 | 445 | /* ========================================================} */ 446 | 447 | #ifdef __cplusplus 448 | } 449 | #endif /* __cplusplus */ 450 | 451 | #endif /* __FIBER_H__ */ 452 | -------------------------------------------------------------------------------- /fiber.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fiber", "fiber.vcxproj", "{267818B1-47B5-4D62-ACF3-B7819F06BA6F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Debug|x64.ActiveCfg = Debug|x64 17 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Debug|x64.Build.0 = Debug|x64 18 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Debug|x86.ActiveCfg = Debug|Win32 19 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Debug|x86.Build.0 = Debug|Win32 20 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Release|x64.ActiveCfg = Release|x64 21 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Release|x64.Build.0 = Release|x64 22 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Release|x86.ActiveCfg = Release|Win32 23 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /fiber.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {267818B1-47B5-4D62-ACF3-B7819F06BA6F} 29 | Win32Proj 30 | fiber 31 | 8.1 32 | 33 | 34 | 35 | Application 36 | true 37 | v140 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v140 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | true 50 | v140 51 | Unicode 52 | 53 | 54 | Application 55 | false 56 | v140 57 | true 58 | Unicode 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | true 80 | 81 | 82 | true 83 | 84 | 85 | false 86 | 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | WIN32;_DEBUG;_CONSOLE;HAVE_STRUCT_TIMESPEC;%(PreprocessorDefinitions) 97 | true 98 | 99 | 100 | 101 | 102 | Console 103 | true 104 | %(AdditionalDependencies) 105 | %(AdditionalLibraryDirectories) 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Level3 117 | Disabled 118 | _DEBUG;_CONSOLE;HAVE_STRUCT_TIMESPEC;%(PreprocessorDefinitions) 119 | true 120 | 121 | 122 | 123 | 124 | Console 125 | true 126 | %(AdditionalDependencies) 127 | %(AdditionalLibraryDirectories) 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Level3 137 | 138 | 139 | MaxSpeed 140 | true 141 | true 142 | WIN32;NDEBUG;_CONSOLE;HAVE_STRUCT_TIMESPEC;%(PreprocessorDefinitions) 143 | true 144 | 145 | 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | %(AdditionalDependencies) 153 | %(AdditionalLibraryDirectories) 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | Level3 163 | 164 | 165 | MaxSpeed 166 | true 167 | true 168 | NDEBUG;_CONSOLE;HAVE_STRUCT_TIMESPEC;%(PreprocessorDefinitions) 169 | true 170 | 171 | 172 | 173 | 174 | Console 175 | true 176 | true 177 | true 178 | %(AdditionalDependencies) 179 | %(AdditionalLibraryDirectories) 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /fiber.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fiber.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 03FF0DD4202F083900F6DD89 /* primes.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DD2202EF88100F6DD89 /* primes.c */; }; 11 | 03FF0DD5202F083900F6DD89 /* asm.S in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DCA202EF59F00F6DD89 /* asm.S */; }; 12 | 03FF0DD6202F083900F6DD89 /* channel.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DC6202EF59F00F6DD89 /* channel.c */; }; 13 | 03FF0DD7202F083900F6DD89 /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DCB202EF59F00F6DD89 /* context.c */; }; 14 | 03FF0DD8202F083900F6DD89 /* fd.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DCC202EF5A000F6DD89 /* fd.c */; }; 15 | 03FF0DD9202F083900F6DD89 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DBE202EF59500F6DD89 /* net.c */; }; 16 | 03FF0DDA202F083900F6DD89 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DBC202EF59500F6DD89 /* print.c */; }; 17 | 03FF0DDB202F083900F6DD89 /* qlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DC0202EF59500F6DD89 /* qlock.c */; }; 18 | 03FF0DDC202F083900F6DD89 /* rendez.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DB6202EF57D00F6DD89 /* rendez.c */; }; 19 | 03FF0DDD202F083900F6DD89 /* task.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DB5202EF57D00F6DD89 /* task.c */; }; 20 | 03FF0DE0202F08FE00F6DD89 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = 03FF0DDE202F08FE00F6DD89 /* test.c */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | 03FF0DA1202EDE4D00F6DD89 /* CopyFiles */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = /usr/share/man/man1/; 28 | dstSubfolderSpec = 0; 29 | files = ( 30 | ); 31 | runOnlyForDeploymentPostprocessing = 1; 32 | }; 33 | /* End PBXCopyFilesBuildPhase section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 03FF0DA3202EDE4D00F6DD89 /* fiber */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fiber; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 03FF0DB0202EF57C00F6DD89 /* taskimpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = taskimpl.h; path = libtask/taskimpl.h; sourceTree = ""; }; 38 | 03FF0DB1202EF57D00F6DD89 /* task.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = task.h; path = libtask/task.h; sourceTree = ""; }; 39 | 03FF0DB5202EF57D00F6DD89 /* task.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = task.c; path = libtask/task.c; sourceTree = ""; }; 40 | 03FF0DB6202EF57D00F6DD89 /* rendez.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rendez.c; path = libtask/rendez.c; sourceTree = ""; }; 41 | 03FF0DBC202EF59500F6DD89 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = print.c; path = libtask/print.c; sourceTree = ""; }; 42 | 03FF0DBD202EF59500F6DD89 /* mips-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mips-ucontext.h"; path = "libtask/mips-ucontext.h"; sourceTree = ""; }; 43 | 03FF0DBE202EF59500F6DD89 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net.c; path = libtask/net.c; sourceTree = ""; }; 44 | 03FF0DBF202EF59500F6DD89 /* power-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "power-ucontext.h"; path = "libtask/power-ucontext.h"; sourceTree = ""; }; 45 | 03FF0DC0202EF59500F6DD89 /* qlock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qlock.c; path = libtask/qlock.c; sourceTree = ""; }; 46 | 03FF0DC6202EF59F00F6DD89 /* channel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = channel.c; path = libtask/channel.c; sourceTree = ""; }; 47 | 03FF0DC8202EF59F00F6DD89 /* 386-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "386-ucontext.h"; path = "libtask/386-ucontext.h"; sourceTree = ""; }; 48 | 03FF0DC9202EF59F00F6DD89 /* amd64-ucontext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "amd64-ucontext.h"; path = "libtask/amd64-ucontext.h"; sourceTree = ""; }; 49 | 03FF0DCA202EF59F00F6DD89 /* asm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = asm.S; path = libtask/asm.S; sourceTree = ""; }; 50 | 03FF0DCB202EF59F00F6DD89 /* context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = context.c; path = libtask/context.c; sourceTree = ""; }; 51 | 03FF0DCC202EF5A000F6DD89 /* fd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fd.c; path = libtask/fd.c; sourceTree = ""; }; 52 | 03FF0DD2202EF88100F6DD89 /* primes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = primes.c; path = libtask/primes.c; sourceTree = ""; }; 53 | 03FF0DDE202F08FE00F6DD89 /* test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = ""; }; 54 | 03FF0DDF202F08FE00F6DD89 /* fiber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fiber.h; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 03FF0DA0202EDE4D00F6DD89 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 03FF0D9A202EDE4C00F6DD89 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 03FF0DDF202F08FE00F6DD89 /* fiber.h */, 72 | 03FF0DDE202F08FE00F6DD89 /* test.c */, 73 | 03FF0DAF202EF55E00F6DD89 /* libtask */, 74 | 03FF0DA4202EDE4D00F6DD89 /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 03FF0DA4202EDE4D00F6DD89 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 03FF0DA3202EDE4D00F6DD89 /* fiber */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 03FF0DAF202EF55E00F6DD89 /* libtask */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 03FF0DD2202EF88100F6DD89 /* primes.c */, 90 | 03FF0DCA202EF59F00F6DD89 /* asm.S */, 91 | 03FF0DC6202EF59F00F6DD89 /* channel.c */, 92 | 03FF0DCB202EF59F00F6DD89 /* context.c */, 93 | 03FF0DCC202EF5A000F6DD89 /* fd.c */, 94 | 03FF0DBE202EF59500F6DD89 /* net.c */, 95 | 03FF0DBC202EF59500F6DD89 /* print.c */, 96 | 03FF0DC0202EF59500F6DD89 /* qlock.c */, 97 | 03FF0DB6202EF57D00F6DD89 /* rendez.c */, 98 | 03FF0DB5202EF57D00F6DD89 /* task.c */, 99 | 03FF0DC8202EF59F00F6DD89 /* 386-ucontext.h */, 100 | 03FF0DC9202EF59F00F6DD89 /* amd64-ucontext.h */, 101 | 03FF0DBD202EF59500F6DD89 /* mips-ucontext.h */, 102 | 03FF0DBF202EF59500F6DD89 /* power-ucontext.h */, 103 | 03FF0DB1202EF57D00F6DD89 /* task.h */, 104 | 03FF0DB0202EF57C00F6DD89 /* taskimpl.h */, 105 | ); 106 | name = libtask; 107 | sourceTree = ""; 108 | }; 109 | /* End PBXGroup section */ 110 | 111 | /* Begin PBXNativeTarget section */ 112 | 03FF0DA2202EDE4D00F6DD89 /* fiber */ = { 113 | isa = PBXNativeTarget; 114 | buildConfigurationList = 03FF0DAA202EDE4E00F6DD89 /* Build configuration list for PBXNativeTarget "fiber" */; 115 | buildPhases = ( 116 | 03FF0D9F202EDE4D00F6DD89 /* Sources */, 117 | 03FF0DA0202EDE4D00F6DD89 /* Frameworks */, 118 | 03FF0DA1202EDE4D00F6DD89 /* CopyFiles */, 119 | ); 120 | buildRules = ( 121 | ); 122 | dependencies = ( 123 | ); 124 | name = fiber; 125 | productName = fiber; 126 | productReference = 03FF0DA3202EDE4D00F6DD89 /* fiber */; 127 | productType = "com.apple.product-type.tool"; 128 | }; 129 | /* End PBXNativeTarget section */ 130 | 131 | /* Begin PBXProject section */ 132 | 03FF0D9B202EDE4D00F6DD89 /* Project object */ = { 133 | isa = PBXProject; 134 | attributes = { 135 | LastUpgradeCheck = 0920; 136 | ORGANIZATIONNAME = wrx; 137 | TargetAttributes = { 138 | 03FF0DA2202EDE4D00F6DD89 = { 139 | CreatedOnToolsVersion = 9.2; 140 | ProvisioningStyle = Automatic; 141 | }; 142 | }; 143 | }; 144 | buildConfigurationList = 03FF0D9E202EDE4D00F6DD89 /* Build configuration list for PBXProject "fiber" */; 145 | compatibilityVersion = "Xcode 8.0"; 146 | developmentRegion = en; 147 | hasScannedForEncodings = 0; 148 | knownRegions = ( 149 | en, 150 | ); 151 | mainGroup = 03FF0D9A202EDE4C00F6DD89; 152 | productRefGroup = 03FF0DA4202EDE4D00F6DD89 /* Products */; 153 | projectDirPath = ""; 154 | projectRoot = ""; 155 | targets = ( 156 | 03FF0DA2202EDE4D00F6DD89 /* fiber */, 157 | ); 158 | }; 159 | /* End PBXProject section */ 160 | 161 | /* Begin PBXSourcesBuildPhase section */ 162 | 03FF0D9F202EDE4D00F6DD89 /* Sources */ = { 163 | isa = PBXSourcesBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | 03FF0DDB202F083900F6DD89 /* qlock.c in Sources */, 167 | 03FF0DE0202F08FE00F6DD89 /* test.c in Sources */, 168 | 03FF0DD5202F083900F6DD89 /* asm.S in Sources */, 169 | 03FF0DD7202F083900F6DD89 /* context.c in Sources */, 170 | 03FF0DDD202F083900F6DD89 /* task.c in Sources */, 171 | 03FF0DD8202F083900F6DD89 /* fd.c in Sources */, 172 | 03FF0DD4202F083900F6DD89 /* primes.c in Sources */, 173 | 03FF0DDA202F083900F6DD89 /* print.c in Sources */, 174 | 03FF0DDC202F083900F6DD89 /* rendez.c in Sources */, 175 | 03FF0DD9202F083900F6DD89 /* net.c in Sources */, 176 | 03FF0DD6202F083900F6DD89 /* channel.c in Sources */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXSourcesBuildPhase section */ 181 | 182 | /* Begin XCBuildConfiguration section */ 183 | 03FF0DA8202EDE4E00F6DD89 /* Debug */ = { 184 | isa = XCBuildConfiguration; 185 | buildSettings = { 186 | ALWAYS_SEARCH_USER_PATHS = NO; 187 | CLANG_ANALYZER_NONNULL = YES; 188 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 189 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 190 | CLANG_CXX_LIBRARY = "libc++"; 191 | CLANG_ENABLE_MODULES = YES; 192 | CLANG_ENABLE_OBJC_ARC = YES; 193 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 194 | CLANG_WARN_BOOL_CONVERSION = YES; 195 | CLANG_WARN_COMMA = YES; 196 | CLANG_WARN_CONSTANT_CONVERSION = YES; 197 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 198 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 199 | CLANG_WARN_EMPTY_BODY = YES; 200 | CLANG_WARN_ENUM_CONVERSION = YES; 201 | CLANG_WARN_INFINITE_RECURSION = YES; 202 | CLANG_WARN_INT_CONVERSION = YES; 203 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 204 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 206 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 207 | CLANG_WARN_STRICT_PROTOTYPES = YES; 208 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 209 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 210 | CLANG_WARN_UNREACHABLE_CODE = YES; 211 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 212 | CODE_SIGN_IDENTITY = "Mac Developer"; 213 | COPY_PHASE_STRIP = NO; 214 | DEBUG_INFORMATION_FORMAT = dwarf; 215 | ENABLE_STRICT_OBJC_MSGSEND = YES; 216 | ENABLE_TESTABILITY = YES; 217 | GCC_C_LANGUAGE_STANDARD = gnu11; 218 | GCC_DYNAMIC_NO_PIC = NO; 219 | GCC_NO_COMMON_BLOCKS = YES; 220 | GCC_OPTIMIZATION_LEVEL = 0; 221 | GCC_PREPROCESSOR_DEFINITIONS = ( 222 | "DEBUG=1", 223 | "$(inherited)", 224 | ); 225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 227 | GCC_WARN_UNDECLARED_SELECTOR = YES; 228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 229 | GCC_WARN_UNUSED_FUNCTION = YES; 230 | GCC_WARN_UNUSED_VARIABLE = YES; 231 | MACOSX_DEPLOYMENT_TARGET = 10.13; 232 | MTL_ENABLE_DEBUG_INFO = YES; 233 | ONLY_ACTIVE_ARCH = YES; 234 | SDKROOT = macosx; 235 | }; 236 | name = Debug; 237 | }; 238 | 03FF0DA9202EDE4E00F6DD89 /* Release */ = { 239 | isa = XCBuildConfiguration; 240 | buildSettings = { 241 | ALWAYS_SEARCH_USER_PATHS = NO; 242 | CLANG_ANALYZER_NONNULL = YES; 243 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 244 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 245 | CLANG_CXX_LIBRARY = "libc++"; 246 | CLANG_ENABLE_MODULES = YES; 247 | CLANG_ENABLE_OBJC_ARC = YES; 248 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 249 | CLANG_WARN_BOOL_CONVERSION = YES; 250 | CLANG_WARN_COMMA = YES; 251 | CLANG_WARN_CONSTANT_CONVERSION = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 261 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 262 | CLANG_WARN_STRICT_PROTOTYPES = YES; 263 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 264 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 265 | CLANG_WARN_UNREACHABLE_CODE = YES; 266 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 267 | CODE_SIGN_IDENTITY = "Mac Developer"; 268 | COPY_PHASE_STRIP = NO; 269 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 270 | ENABLE_NS_ASSERTIONS = NO; 271 | ENABLE_STRICT_OBJC_MSGSEND = YES; 272 | GCC_C_LANGUAGE_STANDARD = gnu11; 273 | GCC_NO_COMMON_BLOCKS = YES; 274 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 275 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 276 | GCC_WARN_UNDECLARED_SELECTOR = YES; 277 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 278 | GCC_WARN_UNUSED_FUNCTION = YES; 279 | GCC_WARN_UNUSED_VARIABLE = YES; 280 | MACOSX_DEPLOYMENT_TARGET = 10.13; 281 | MTL_ENABLE_DEBUG_INFO = NO; 282 | SDKROOT = macosx; 283 | }; 284 | name = Release; 285 | }; 286 | 03FF0DAB202EDE4E00F6DD89 /* Debug */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 290 | CODE_SIGN_STYLE = Automatic; 291 | DEVELOPMENT_TEAM = MYG5HMGVM7; 292 | GCC_C_LANGUAGE_STANDARD = gnu89; 293 | HEADER_SEARCH_PATHS = libtask; 294 | MACOSX_DEPLOYMENT_TARGET = 10.6; 295 | ONLY_ACTIVE_ARCH = NO; 296 | PRODUCT_NAME = "$(TARGET_NAME)"; 297 | VALID_ARCHS = "i386 x86_64"; 298 | }; 299 | name = Debug; 300 | }; 301 | 03FF0DAC202EDE4E00F6DD89 /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 305 | CODE_SIGN_STYLE = Automatic; 306 | DEVELOPMENT_TEAM = MYG5HMGVM7; 307 | GCC_C_LANGUAGE_STANDARD = gnu89; 308 | HEADER_SEARCH_PATHS = libtask; 309 | MACOSX_DEPLOYMENT_TARGET = 10.6; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | VALID_ARCHS = "i386 x86_64"; 312 | }; 313 | name = Release; 314 | }; 315 | /* End XCBuildConfiguration section */ 316 | 317 | /* Begin XCConfigurationList section */ 318 | 03FF0D9E202EDE4D00F6DD89 /* Build configuration list for PBXProject "fiber" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | 03FF0DA8202EDE4E00F6DD89 /* Debug */, 322 | 03FF0DA9202EDE4E00F6DD89 /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | 03FF0DAA202EDE4E00F6DD89 /* Build configuration list for PBXNativeTarget "fiber" */ = { 328 | isa = XCConfigurationList; 329 | buildConfigurations = ( 330 | 03FF0DAB202EDE4E00F6DD89 /* Debug */, 331 | 03FF0DAC202EDE4E00F6DD89 /* Release */, 332 | ); 333 | defaultConfigurationIsVisible = 0; 334 | defaultConfigurationName = Release; 335 | }; 336 | /* End XCConfigurationList section */ 337 | }; 338 | rootObject = 03FF0D9B202EDE4D00F6DD89 /* Project object */; 339 | } 340 | -------------------------------------------------------------------------------- /fiber.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/Makefile: -------------------------------------------------------------------------------- 1 | LIB=libtask.a 2 | TCPLIBS= 3 | 4 | ASM=asm.o 5 | OFILES=\ 6 | $(ASM)\ 7 | channel.o\ 8 | context.o\ 9 | fd.o\ 10 | net.o\ 11 | print.o\ 12 | qlock.o\ 13 | rendez.o\ 14 | task.o\ 15 | 16 | all: $(LIB) primes tcpproxy testdelay 17 | 18 | $(OFILES): taskimpl.h task.h 386-ucontext.h power-ucontext.h 19 | 20 | AS=gcc -c 21 | CC=gcc 22 | CFLAGS=-Wall -c -I. -ggdb 23 | 24 | %.o: %.S 25 | $(AS) $*.S 26 | 27 | %.o: %.c 28 | $(CC) $(CFLAGS) $*.c 29 | 30 | $(LIB): $(OFILES) 31 | ar rvc $(LIB) $(OFILES) 32 | 33 | primes: primes.o $(LIB) 34 | $(CC) -o primes primes.o $(LIB) 35 | 36 | tcpproxy: tcpproxy.o $(LIB) 37 | $(CC) -o tcpproxy tcpproxy.o $(LIB) $(TCPLIBS) 38 | 39 | httpload: httpload.o $(LIB) 40 | $(CC) -o httpload httpload.o $(LIB) 41 | 42 | testdelay: testdelay.o $(LIB) 43 | $(CC) -o testdelay testdelay.o $(LIB) 44 | 45 | testdelay1: testdelay1.o $(LIB) 46 | $(CC) -o testdelay1 testdelay1.o $(LIB) 47 | 48 | clean: 49 | rm -f *.o primes tcpproxy testdelay testdelay1 httpload $(LIB) 50 | 51 | install: $(LIB) 52 | cp $(LIB) /usr/local/lib 53 | cp task.h /usr/local/include 54 | 55 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | #else 25 | #define NEEDPOWERCONTEXT 1 26 | #define SET __setmcontext 27 | #define GET __getmcontext 28 | #endif 29 | #endif 30 | 31 | #if defined(__linux__) && defined(__arm__) 32 | #define NEEDARMCONTEXT 1 33 | #define SET setmcontext 34 | #define GET getmcontext 35 | #endif 36 | 37 | #if defined(__linux__) && defined(__mips__) 38 | #define NEEDMIPSCONTEXT 1 39 | #define SET setmcontext 40 | #define GET getmcontext 41 | #endif 42 | 43 | #ifdef NEEDX86CONTEXT 44 | .globl SET 45 | SET: 46 | movl 4(%esp), %eax 47 | 48 | movl 8(%eax), %fs 49 | movl 12(%eax), %es 50 | movl 16(%eax), %ds 51 | movl 76(%eax), %ss 52 | movl 20(%eax), %edi 53 | movl 24(%eax), %esi 54 | movl 28(%eax), %ebp 55 | movl 36(%eax), %ebx 56 | movl 40(%eax), %edx 57 | movl 44(%eax), %ecx 58 | 59 | movl 72(%eax), %esp 60 | pushl 60(%eax) /* new %eip */ 61 | movl 48(%eax), %eax 62 | ret 63 | 64 | .globl GET 65 | GET: 66 | movl 4(%esp), %eax 67 | 68 | movl %fs, 8(%eax) 69 | movl %es, 12(%eax) 70 | movl %ds, 16(%eax) 71 | movl %ss, 76(%eax) 72 | movl %edi, 20(%eax) 73 | movl %esi, 24(%eax) 74 | movl %ebp, 28(%eax) 75 | movl %ebx, 36(%eax) 76 | movl %edx, 40(%eax) 77 | movl %ecx, 44(%eax) 78 | 79 | movl $1, 48(%eax) /* %eax */ 80 | movl (%esp), %ecx /* %eip */ 81 | movl %ecx, 60(%eax) 82 | leal 4(%esp), %ecx /* %esp */ 83 | movl %ecx, 72(%eax) 84 | 85 | movl 44(%eax), %ecx /* restore %ecx */ 86 | movl $0, %eax 87 | ret 88 | #endif 89 | 90 | #ifdef NEEDAMD64CONTEXT 91 | .globl SET 92 | SET: 93 | movq 16(%rdi), %rsi 94 | movq 24(%rdi), %rdx 95 | movq 32(%rdi), %rcx 96 | movq 40(%rdi), %r8 97 | movq 48(%rdi), %r9 98 | movq 56(%rdi), %rax 99 | movq 64(%rdi), %rbx 100 | movq 72(%rdi), %rbp 101 | movq 80(%rdi), %r10 102 | movq 88(%rdi), %r11 103 | movq 96(%rdi), %r12 104 | movq 104(%rdi), %r13 105 | movq 112(%rdi), %r14 106 | movq 120(%rdi), %r15 107 | movq 184(%rdi), %rsp 108 | pushq 160(%rdi) /* new %eip */ 109 | movq 8(%rdi), %rdi 110 | ret 111 | 112 | .globl GET 113 | GET: 114 | movq %rdi, 8(%rdi) 115 | movq %rsi, 16(%rdi) 116 | movq %rdx, 24(%rdi) 117 | movq %rcx, 32(%rdi) 118 | movq %r8, 40(%rdi) 119 | movq %r9, 48(%rdi) 120 | movq $1, 56(%rdi) /* %rax */ 121 | movq %rbx, 64(%rdi) 122 | movq %rbp, 72(%rdi) 123 | movq %r10, 80(%rdi) 124 | movq %r11, 88(%rdi) 125 | movq %r12, 96(%rdi) 126 | movq %r13, 104(%rdi) 127 | movq %r14, 112(%rdi) 128 | movq %r15, 120(%rdi) 129 | 130 | movq (%rsp), %rcx /* %rip */ 131 | movq %rcx, 160(%rdi) 132 | leaq 8(%rsp), %rcx /* %rsp */ 133 | movq %rcx, 184(%rdi) 134 | 135 | movq 32(%rdi), %rcx /* restore %rcx */ 136 | movq $0, %rax 137 | ret 138 | #endif 139 | 140 | #ifdef NEEDPOWERCONTEXT 141 | /* get FPR and VR use flags with sc 0x7FF3 */ 142 | /* get vsave with mfspr reg, 256 */ 143 | 144 | .text 145 | .align 2 146 | 147 | .globl GET 148 | GET: /* xxx: instruction scheduling */ 149 | mflr r0 150 | mfcr r5 151 | mfctr r6 152 | mfxer r7 153 | stw r0, 0*4(r3) 154 | stw r5, 1*4(r3) 155 | stw r6, 2*4(r3) 156 | stw r7, 3*4(r3) 157 | 158 | stw r1, 4*4(r3) 159 | stw r2, 5*4(r3) 160 | li r5, 1 /* return value for setmcontext */ 161 | stw r5, 6*4(r3) 162 | 163 | stw r13, (0+7)*4(r3) /* callee-save GPRs */ 164 | stw r14, (1+7)*4(r3) /* xxx: block move */ 165 | stw r15, (2+7)*4(r3) 166 | stw r16, (3+7)*4(r3) 167 | stw r17, (4+7)*4(r3) 168 | stw r18, (5+7)*4(r3) 169 | stw r19, (6+7)*4(r3) 170 | stw r20, (7+7)*4(r3) 171 | stw r21, (8+7)*4(r3) 172 | stw r22, (9+7)*4(r3) 173 | stw r23, (10+7)*4(r3) 174 | stw r24, (11+7)*4(r3) 175 | stw r25, (12+7)*4(r3) 176 | stw r26, (13+7)*4(r3) 177 | stw r27, (14+7)*4(r3) 178 | stw r28, (15+7)*4(r3) 179 | stw r29, (16+7)*4(r3) 180 | stw r30, (17+7)*4(r3) 181 | stw r31, (18+7)*4(r3) 182 | 183 | li r3, 0 /* return */ 184 | blr 185 | 186 | .globl SET 187 | SET: 188 | lwz r13, (0+7)*4(r3) /* callee-save GPRs */ 189 | lwz r14, (1+7)*4(r3) /* xxx: block move */ 190 | lwz r15, (2+7)*4(r3) 191 | lwz r16, (3+7)*4(r3) 192 | lwz r17, (4+7)*4(r3) 193 | lwz r18, (5+7)*4(r3) 194 | lwz r19, (6+7)*4(r3) 195 | lwz r20, (7+7)*4(r3) 196 | lwz r21, (8+7)*4(r3) 197 | lwz r22, (9+7)*4(r3) 198 | lwz r23, (10+7)*4(r3) 199 | lwz r24, (11+7)*4(r3) 200 | lwz r25, (12+7)*4(r3) 201 | lwz r26, (13+7)*4(r3) 202 | lwz r27, (14+7)*4(r3) 203 | lwz r28, (15+7)*4(r3) 204 | lwz r29, (16+7)*4(r3) 205 | lwz r30, (17+7)*4(r3) 206 | lwz r31, (18+7)*4(r3) 207 | 208 | lwz r1, 4*4(r3) 209 | lwz r2, 5*4(r3) 210 | 211 | lwz r0, 0*4(r3) 212 | mtlr r0 213 | lwz r0, 1*4(r3) 214 | mtcr r0 /* mtcrf 0xFF, r0 */ 215 | lwz r0, 2*4(r3) 216 | mtctr r0 217 | lwz r0, 3*4(r3) 218 | mtxer r0 219 | 220 | lwz r3, 6*4(r3) 221 | blr 222 | #endif 223 | 224 | #ifdef NEEDARMCONTEXT 225 | .globl GET 226 | GET: 227 | str r1, [r0,#4] 228 | str r2, [r0,#8] 229 | str r3, [r0,#12] 230 | str r4, [r0,#16] 231 | str r5, [r0,#20] 232 | str r6, [r0,#24] 233 | str r7, [r0,#28] 234 | str r8, [r0,#32] 235 | str r9, [r0,#36] 236 | str r10, [r0,#40] 237 | str r11, [r0,#44] 238 | str r12, [r0,#48] 239 | str r13, [r0,#52] 240 | str r14, [r0,#56] 241 | /* store 1 as r0-to-restore */ 242 | mov r1, #1 243 | str r1, [r0] 244 | /* return 0 */ 245 | mov r0, #0 246 | mov pc, lr 247 | 248 | .globl SET 249 | SET: 250 | ldr r1, [r0,#4] 251 | ldr r2, [r0,#8] 252 | ldr r3, [r0,#12] 253 | ldr r4, [r0,#16] 254 | ldr r5, [r0,#20] 255 | ldr r6, [r0,#24] 256 | ldr r7, [r0,#28] 257 | ldr r8, [r0,#32] 258 | ldr r9, [r0,#36] 259 | ldr r10, [r0,#40] 260 | ldr r11, [r0,#44] 261 | ldr r12, [r0,#48] 262 | ldr r13, [r0,#52] 263 | ldr r14, [r0,#56] 264 | ldr r0, [r0] 265 | mov pc, lr 266 | #endif 267 | 268 | #ifdef NEEDMIPSCONTEXT 269 | .globl GET 270 | GET: 271 | sw $4, 24($4) 272 | sw $5, 28($4) 273 | sw $6, 32($4) 274 | sw $7, 36($4) 275 | 276 | sw $16, 72($4) 277 | sw $17, 76($4) 278 | sw $18, 80($4) 279 | sw $19, 84($4) 280 | sw $20, 88($4) 281 | sw $21, 92($4) 282 | sw $22, 96($4) 283 | sw $23, 100($4) 284 | 285 | sw $28, 120($4) /* gp */ 286 | sw $29, 124($4) /* sp */ 287 | sw $30, 128($4) /* fp */ 288 | sw $31, 132($4) /* ra */ 289 | 290 | xor $2, $2, $2 291 | j $31 292 | nop 293 | 294 | .globl SET 295 | SET: 296 | lw $16, 72($4) 297 | lw $17, 76($4) 298 | lw $18, 80($4) 299 | lw $19, 84($4) 300 | lw $20, 88($4) 301 | lw $21, 92($4) 302 | lw $22, 96($4) 303 | lw $23, 100($4) 304 | 305 | lw $28, 120($4) /* gp */ 306 | lw $29, 124($4) /* sp */ 307 | lw $30, 128($4) /* fp */ 308 | 309 | /* 310 | * If we set $31 directly and j $31, 311 | * we would loose the outer return address. 312 | * Use a temporary register, then. 313 | */ 314 | lw $8, 132($4) /* ra */ 315 | 316 | /* bug: not setting the pc causes a bus error */ 317 | lw $25, 132($4) /* pc */ 318 | 319 | lw $5, 28($4) 320 | lw $6, 32($4) 321 | lw $7, 36($4) 322 | lw $4, 24($4) 323 | 324 | j $8 325 | nop 326 | #endif 327 | -------------------------------------------------------------------------------- /libtask/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); 46 | sp = tos - 16; 47 | ucp->mc.pc = (long)func; 48 | ucp->mc.sp = (long)sp; 49 | va_start(arg, argc); 50 | ucp->mc.r3 = va_arg(arg, long); 51 | va_end(arg); 52 | } 53 | #endif 54 | 55 | #ifdef NEEDX86MAKECONTEXT 56 | void 57 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 58 | { 59 | int *sp; 60 | 61 | sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4; 62 | sp -= argc; 63 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 64 | memmove(sp, &argc+1, argc*sizeof(int)); 65 | 66 | *--sp = 0; /* return address */ 67 | ucp->uc_mcontext.mc_eip = (long)func; 68 | ucp->uc_mcontext.mc_esp = (int)sp; 69 | } 70 | #endif 71 | 72 | #ifdef NEEDAMD64MAKECONTEXT 73 | void 74 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 75 | { 76 | long *sp; 77 | va_list va; 78 | 79 | memset(&ucp->uc_mcontext, 0, sizeof ucp->uc_mcontext); 80 | if(argc != 2) 81 | *(int*)0 = 0; 82 | va_start(va, argc); 83 | ucp->uc_mcontext.mc_rdi = va_arg(va, int); 84 | ucp->uc_mcontext.mc_rsi = va_arg(va, int); 85 | va_end(va); 86 | sp = (long*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(long); 87 | sp -= argc; 88 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 89 | *--sp = 0; /* return address */ 90 | ucp->uc_mcontext.mc_rip = (long)func; 91 | ucp->uc_mcontext.mc_rsp = (long)sp; 92 | } 93 | #endif 94 | 95 | #ifdef NEEDARMMAKECONTEXT 96 | void 97 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 98 | { 99 | int i, *sp; 100 | va_list arg; 101 | 102 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 103 | va_start(arg, argc); 104 | for(i=0; i<4 && iuc_mcontext.gregs[i] = va_arg(arg, uint); 106 | va_end(arg); 107 | uc->uc_mcontext.gregs[13] = (uint)sp; 108 | uc->uc_mcontext.gregs[14] = (uint)fn; 109 | } 110 | #endif 111 | 112 | #ifdef NEEDMIPSMAKECONTEXT 113 | void 114 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 115 | { 116 | int i, *sp; 117 | va_list arg; 118 | 119 | va_start(arg, argc); 120 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 121 | for(i=0; i<4 && iuc_mcontext.mc_regs[i+4] = va_arg(arg, int); 123 | va_end(arg); 124 | uc->uc_mcontext.mc_regs[29] = (int)sp; 125 | uc->uc_mcontext.mc_regs[31] = (int)fn; 126 | } 127 | #endif 128 | 129 | #ifdef NEEDSWAPCONTEXT 130 | int 131 | swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 132 | { 133 | if(getcontext(oucp) == 0) 134 | setcontext(ucp); 135 | return 0; 136 | } 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | # else 101 | # include "power-ucontext.h" 102 | # endif 103 | #endif 104 | 105 | #if defined(__OpenBSD__) 106 | # define mcontext libthread_mcontext 107 | # define mcontext_t libthread_mcontext_t 108 | # define ucontext libthread_ucontext 109 | # define ucontext_t libthread_ucontext_t 110 | # if defined __i386__ 111 | # include "386-ucontext.h" 112 | # else 113 | # include "power-ucontext.h" 114 | # endif 115 | extern pid_t rfork_thread(int, void*, int(*)(void*), void*); 116 | #endif 117 | 118 | #if 0 && defined(__sun__) 119 | # define mcontext libthread_mcontext 120 | # define mcontext_t libthread_mcontext_t 121 | # define ucontext libthread_ucontext 122 | # define ucontext_t libthread_ucontext_t 123 | # include "sparc-ucontext.h" 124 | #endif 125 | 126 | #if defined(__arm__) 127 | int getmcontext(mcontext_t*); 128 | void setmcontext(const mcontext_t*); 129 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 130 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 131 | #endif 132 | 133 | #if defined(__mips__) 134 | #include "mips-ucontext.h" 135 | int getmcontext(mcontext_t*); 136 | void setmcontext(const mcontext_t*); 137 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 138 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 139 | #endif 140 | 141 | typedef struct Context Context; 142 | 143 | enum 144 | { 145 | STACK = 8192 146 | }; 147 | 148 | struct Context 149 | { 150 | ucontext_t uc; 151 | }; 152 | 153 | struct Task 154 | { 155 | char name[256]; // offset known to acid 156 | char state[256]; 157 | Task *next; 158 | Task *prev; 159 | Task *allnext; 160 | Task *allprev; 161 | Context context; 162 | uvlong alarmtime; 163 | uint id; 164 | uchar *stk; 165 | uint stksize; 166 | int exiting; 167 | int alltaskslot; 168 | int system; 169 | int ready; 170 | void (*startfn)(void*); 171 | void *startarg; 172 | void *udata; 173 | }; 174 | 175 | void taskready(Task*); 176 | void taskswitch(void); 177 | 178 | void addtask(Tasklist*, Task*); 179 | void deltask(Tasklist*, Task*); 180 | 181 | extern Task *taskrunning; 182 | extern int taskcount; 183 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /libtask/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 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | OS := $(shell uname -s) 2 | IS_APPLE := $(shell echo $(OS)|grep -i darwin) 3 | 4 | ifdef IS_APPLE 5 | test : test.o 6 | cc -o test test.o -lm 7 | ./test 8 | test.o : test.c fiber.h 9 | cc -Os -c test.c -Wno-deprecated-declarations 10 | else 11 | test : test.o 12 | cc -o test test.o -lm -lrt 13 | ./test 14 | test.o : test.c fiber.h 15 | cc -Os -c test.c 16 | endif 17 | 18 | clean : 19 | rm -f test.o test 20 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include "fiber.h" 2 | #include 3 | #include 4 | #ifdef FB_OS_WIN 5 | # include 6 | #endif /* FB_OS_WIN */ 7 | 8 | #ifndef fbassert 9 | # define fbassert(cond) assert(cond) 10 | #endif /* fbassert */ 11 | 12 | struct test_t { 13 | int sum; 14 | fiber_t* fb0; 15 | fiber_t* fb1; 16 | fiber_t* fb2; 17 | }; 18 | 19 | static void fiber1(fiber_t* fb) { 20 | struct test_t* t = (struct test_t*)fb->userdata; 21 | 22 | fbassert(fiber_is_current(t->fb1)); 23 | printf("fiber1: %d\n", ++t->sum); 24 | fiber_switch(t->fb2); 25 | 26 | fbassert(fiber_is_current(t->fb1)); 27 | printf("fiber1: %d\n", ++t->sum); 28 | fiber_switch(t->fb2); 29 | 30 | fbassert(fiber_is_current(t->fb1)); 31 | printf("fiber1: %d\n", ++t->sum); 32 | fiber_switch(t->fb2); 33 | } 34 | 35 | static void fiber2(fiber_t* fb) { 36 | struct test_t* t = (struct test_t*)fb->userdata; 37 | 38 | fbassert(fiber_is_current(t->fb2)); 39 | printf("fiber2: %d\n", ++t->sum); 40 | fiber_switch(t->fb0); 41 | 42 | fbassert(fiber_is_current(t->fb2)); 43 | printf("fiber2: %d\n", ++t->sum); 44 | fiber_switch(t->fb0); 45 | 46 | fbassert(fiber_is_current(t->fb2)); 47 | printf("fiber2: %d\n", ++t->sum); 48 | fiber_switch(t->fb0); 49 | } 50 | 51 | #ifdef FB_OS_WIN 52 | static void on_exit(void) { 53 | if (!!_CrtDumpMemoryLeaks()) { 54 | fprintf(stderr, "Memory leak!\n"); 55 | 56 | _CrtDbgBreak(); 57 | } 58 | } 59 | #endif /* FB_OS_WIN */ 60 | 61 | /** 62 | * An example which creates 3 fibers (including the primary fiber), 63 | * and switches several times from one another. 64 | */ 65 | int main() { 66 | /**< `test_t` is used to store some test data and will be carried by fibers as userdata. */ 67 | struct test_t test; 68 | memset(&test, 0, sizeof(test)); 69 | 70 | #ifdef FB_OS_WIN 71 | atexit(on_exit); 72 | #endif /* FB_OS_WIN */ 73 | 74 | /**< Creates the primary fiber before creating the two minor fibers. */ 75 | test.fb0 = fiber_create(0, 0, 0, &test); 76 | test.fb1 = fiber_create(test.fb0, 0, fiber1, &test); 77 | test.fb2 = fiber_create(test.fb0, 0, fiber2, &test); 78 | 79 | /**< Switching. */ 80 | fbassert(fiber_is_current(test.fb0)); 81 | fiber_switch(test.fb1); 82 | fbassert(fiber_is_current(test.fb0)); 83 | fiber_switch(test.fb1); 84 | fbassert(fiber_is_current(test.fb0)); 85 | fiber_switch(test.fb1); 86 | 87 | /**< Deletes minor fibers before deleting the primary fiber. */ 88 | fiber_delete(test.fb2); 89 | fiber_delete(test.fb1); 90 | fiber_delete(test.fb0); 91 | 92 | return 0; 93 | } 94 | --------------------------------------------------------------------------------