From cec6f687cab65d8ee65212ed7361fd6ae5bbfe3d Mon Sep 17 00:00:00 2001 From: Matthew Mondor Date: Tue, 13 Mar 2007 20:28:23 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'mysql-branch'. --- Xisop/LICENSE | 34 - Xisop/README | 53 - Xisop/TODO | 163 - Xisop/doc/clean.sh | 3 - Xisop/doc/make.sh | 11 - Xisop/doc/xisop.lyx | 10041 ------------------- Xisop/src/clean.sh | 16 - Xisop/src/common/clean.sh | 11 - Xisop/src/common/kernel/clean.sh | 8 - Xisop/src/common/kernel/debug.c | 408 - Xisop/src/common/kernel/debug.h | 104 - Xisop/src/common/kernel/device.c | 525 - Xisop/src/common/kernel/device.h | 176 - Xisop/src/common/kernel/exception.c | 222 - Xisop/src/common/kernel/exception.h | 84 - Xisop/src/common/kernel/main.c | 234 - Xisop/src/common/kernel/main.h | 155 - Xisop/src/common/kernel/make.sh | 9 - Xisop/src/common/kernel/memory.c | 1425 --- Xisop/src/common/kernel/memory.h | 260 - Xisop/src/common/kernel/object.h | 87 - Xisop/src/common/kernel/port.c | 337 - Xisop/src/common/kernel/port.h | 103 - Xisop/src/common/kernel/scheduler.c | 382 - Xisop/src/common/kernel/scheduler.h | 90 - Xisop/src/common/kernel/signal.c | 195 - Xisop/src/common/kernel/signal.h | 67 - Xisop/src/common/kernel/statistic.c | 168 - Xisop/src/common/kernel/statistic.h | 163 - Xisop/src/common/kernel/syscall.c | 204 - Xisop/src/common/kernel/syscall.h | 76 - Xisop/src/common/kernel/task.c | 432 - Xisop/src/common/kernel/task.h | 164 - Xisop/src/common/kernlib/clean.sh | 9 - Xisop/src/common/kernlib/fifo.h | 165 - Xisop/src/common/kernlib/hash.c | 381 - Xisop/src/common/kernlib/hash.h | 96 - Xisop/src/common/kernlib/lifo.h | 107 - Xisop/src/common/kernlib/list.h | 178 - Xisop/src/common/kernlib/make.sh | 13 - Xisop/src/common/kernlib/rand.c | 108 - Xisop/src/common/kernlib/rand.h | 53 - Xisop/src/common/kernlib/setjmp.h | 64 - Xisop/src/common/kernlib/string.h | 106 - Xisop/src/common/kernlib/string/_strcat.c | 52 - Xisop/src/common/kernlib/string/_strcpy.c | 53 - Xisop/src/common/kernlib/string/_strdup.c | 59 - Xisop/src/common/kernlib/string/_strncat.c | 59 - Xisop/src/common/kernlib/string/_strncpy.c | 62 - Xisop/src/common/kernlib/string/_strndup.c | 61 - Xisop/src/common/kernlib/string/_strrev.c | 57 - Xisop/src/common/kernlib/string/bstr_alloc.c | 59 - Xisop/src/common/kernlib/string/bstr_free.c | 50 - Xisop/src/common/kernlib/string/bstr_new.c | 67 - Xisop/src/common/kernlib/string/case.c | 241 - Xisop/src/common/kernlib/string/htol.c | 71 - Xisop/src/common/kernlib/string/memcmp.c | 120 - Xisop/src/common/kernlib/string/memcpy.c | 164 - Xisop/src/common/kernlib/string/memhash32.c | 72 - Xisop/src/common/kernlib/string/memmove.c | 305 - Xisop/src/common/kernlib/string/memset.c | 179 - Xisop/src/common/kernlib/string/pageclr.c | 96 - Xisop/src/common/kernlib/string/straspl.c | 68 - Xisop/src/common/kernlib/string/strchr.c | 48 - Xisop/src/common/kernlib/string/strcmp.c | 48 - Xisop/src/common/kernlib/string/strlen.c | 56 - Xisop/src/common/kernlib/string/strnchr.c | 58 - Xisop/src/common/kernlib/string/strncmp.c | 57 - Xisop/src/common/kernlib/string/strnlen.c | 51 - Xisop/src/common/kernlib/string/strnrchr.c | 54 - Xisop/src/common/kernlib/string/strrchr.c | 53 - Xisop/src/common/kernlib/string/strspl.c | 65 - Xisop/src/common/make.sh | 15 - Xisop/src/common/types.h | 133 - Xisop/src/config.h | 50 - Xisop/src/generic_makedefs.sh | 40 - Xisop/src/make.sh | 68 - Xisop/src/ports/amiga/boot/DOTuaerc | 27 - Xisop/src/ports/amiga/boot/README | 12 - Xisop/src/ports/amiga/boot/bootf/bootf_c.c | 139 - Xisop/src/ports/amiga/boot/bootf/bootf_s.s | 118 - Xisop/src/ports/amiga/boot/bootf/bootf_script.ld | 14 - Xisop/src/ports/amiga/boot/clean.sh | 10 - Xisop/src/ports/amiga/boot/config.h | 72 - Xisop/src/ports/amiga/boot/image_script.ld | 13 - Xisop/src/ports/amiga/boot/init.c | 590 -- Xisop/src/ports/amiga/boot/make.sh | 33 - Xisop/src/ports/amiga/boot/tools/aosbblock.c | 107 - Xisop/src/ports/amiga/boot/tools/config.c | 64 - Xisop/src/ports/amiga/boot/tools/dumpkern.c | 80 - Xisop/src/ports/amiga/clean.sh | 7 - Xisop/src/ports/amiga/make.sh | 10 - Xisop/src/ports/amiga/makedefs.sh | 71 - Xisop/src/ports/amiga/support.h | 467 - Xisop/src/ports/amiga/support_c.c | 77 - Xisop/src/ports/amiga/support_s.s | 865 -- Xisop/src/processors/i386/make.sh | 11 - Xisop/src/processors/i386/support.h | 83 - Xisop/src/processors/i386/support.s | 143 - Xisop/src/processors/m68k/clean.sh | 8 - Xisop/src/processors/m68k/make.sh | 10 - Xisop/src/processors/m68k/math/README | 3 - Xisop/src/processors/m68k/math/divsi3.s | 59 - Xisop/src/processors/m68k/math/modsi3.s | 60 - Xisop/src/processors/m68k/math/mulsi3.s | 55 - Xisop/src/processors/m68k/math/udivsi3.s | 114 - Xisop/src/processors/m68k/math/umodsi3.s | 51 - Xisop/src/processors/m68k/support.h | 138 - Xisop/src/processors/m68k/support.s | 321 - site/contributors.html | 95 - site/cvs.html | 89 - site/donations.html | 115 - site/favicon.ico | Bin 318 -> 0 bytes site/images/CVS.jpg | Bin 1366 -> 0 bytes site/images/key.jpg | Bin 1977 -> 0 bytes site/images/sigil.jpg | Bin 3311 -> 0 bytes site/index.html | 91 - site/mirrors.html | 92 - site/new/TODO | 93 - site/new/build/GNUmakefile | 20 - site/new/build/README | 16 - site/new/build/TODO | 10 - site/new/build/english/faq_mmftpd.txt | 17 - site/new/build/english/faq_mmmail.txt | 0 site/new/build/english/faq_mmstatd.txt | 0 site/new/build/english/menu_languages.txt | 6 - site/new/build/english/menu_main.txt | 10 - site/new/build/english/menu_mirrors.txt | 7 - site/new/build/english/page_contact.txt | 0 site/new/build/english/page_contributors.txt | 0 site/new/build/english/page_cvs.txt | 0 site/new/build/english/page_donations.txt | 0 site/new/build/english/page_index.txt | 22 - site/new/build/english/page_mirrors.txt | 0 site/new/build/english/page_philosophy.txt | 0 site/new/build/english/page_projects.txt | 0 site/new/build/english/page_software.txt | 0 site/new/build/english/soft_descriptions.txt | 15 - site/new/build/mmsite.c | 557 - site/new/build/mmsite.conf | 12 - site/new/build/site_faq.txt | 6 - site/new/build/site_languages.txt | 5 - site/new/build/site_mirrors.txt | 6 - site/new/build/site_pages.txt | 12 - site/new/build/site_software.txt | 6 - site/new/build/soft_development.txt | 4 - site/new/build/soft_old.txt | 4 - site/new/build/soft_stable.txt | 4 - site/philosophy.html | 133 - site/projects.html | 146 - site/software.html | 342 - tests/entropy/README | 12 - tests/entropy/entropy_disk.c | 629 -- tests/js-test/README | 7 - tests/js-test/js/copy.js | 37 - tests/js-test/js/fd.js | 35 - tests/js-test/js/game/objects.js | 341 - tests/js-test/js/httpd/httpd.js | 1679 ---- tests/js-test/js/httpd/ml_clean.js | 192 - tests/js-test/js/httpd/ml_machine.js | 146 - tests/js-test/js/httpd/options.js | 82 - tests/js-test/js/httpd/root.js | 197 - tests/js-test/js/httpd/string.js | 34 - tests/js-test/js/ml.js | 176 - tests/js-test/js/ml2.js | 209 - tests/js-test/js/ml3.js | 209 - tests/js-test/js/ml4.js | 203 - tests/js-test/js/ml5.js | 213 - tests/js-test/js/ml6.js | 182 - tests/js-test/js/parse.js | 318 - tests/js-test/js/poll_test.js | 93 - tests/js-test/js/sock_httpd.js | 292 - tests/js-test/js/sock_listen.js | 52 - tests/js-test/js/test.js | 84 - tests/js-test/js/test2.js | 15 - tests/js-test/js/test3.js | 46 - tests/js-test/src/GNUmakefile | 29 - tests/js-test/src/classes/js_errno.c | 222 - tests/js-test/src/classes/js_errno.h | 13 - tests/js-test/src/classes/js_fd.c | 1971 ---- tests/js-test/src/classes/js_fd.h | 15 - tests/js-test/src/classes/js_global.c | 150 - tests/js-test/src/classes/js_global.h | 15 - tests/js-test/src/classes/js_mysql.c | 6 - tests/js-test/src/classes/js_mysql.h | 13 - tests/js-test/src/classes/js_pgsql.c | 3493 ------- tests/js-test/src/classes/js_pgsql.h | 15 - tests/js-test/src/classes/js_signal.c | 231 - tests/js-test/src/classes/js_signal.h | 13 - tests/js-test/src/js-server.c | 328 - tests/js-test/util/spidermonkey-config | 49 - tests/kqueue/GNUmakefile | 22 - tests/kqueue/README | 48 - tests/kqueue/client.c | 152 - tests/kqueue/client.h | 59 - tests/kqueue/conf.h | 39 - tests/kqueue/daemon.c | 124 - tests/kqueue/daemon.h | 19 - tests/kqueue/kqueue.c | 329 - tests/kqueue/kqueue.h | 31 - tests/kqueue/main.c | 62 - tests/kqueue/net.c | 131 - tests/kqueue/net.h | 23 - tests/kqueue/packets.c | 327 - tests/kqueue/packets.h | 160 - tests/kqueue/recvq.c | 84 - tests/kqueue/recvq.h | 35 - tests/kqueue/sendq.c | 148 - tests/kqueue/sendq.h | 37 - tests/memory/README | 42 - tests/pthread/README | 113 - tests/pthread_utils/GNUmakefile | 35 - tests/pthread_utils/README | 197 - tests/pthread_utils/mm_pthread_debug.h | 63 - tests/pthread_utils/mm_pthread_msg.c | 466 - tests/pthread_utils/mm_pthread_msg.h | 110 - tests/pthread_utils/mm_pthread_poll.c | 1116 --- tests/pthread_utils/mm_pthread_poll.h | 63 - tests/pthread_utils/mm_pthread_pool.c | 504 - tests/pthread_utils/mm_pthread_pool.h | 97 - tests/pthread_utils/mm_pthread_sleep.c | 285 - tests/pthread_utils/mm_pthread_sleep.h | 57 - tests/pthread_utils/tests/msg_test.c | 269 - tests/pthread_utils/tests/poll_test.c | 73 - tests/pthread_utils/tests/polltest.c | 153 - tests/pthread_utils/tests/sigtest.c | 146 - tests/rlookup/GNUmakefile | 22 - tests/rlookup/main.c | 68 - tests/rlookup/rlc.c | 619 -- tests/rlookup/rlc.h | 27 - tests/rotate/GNUmakefile | 57 - tests/rotate/main.c | 195 - tests/sdl-client/GNUmakefile | 90 - tests/sdl-client/README | 190 - tests/sdl-client/bmp/FedCA.bmp | Bin 4854 -> 0 bytes tests/sdl-client/bmp/README | 1 - tests/sdl-client/bmp/RomDD.bmp | Bin 4854 -> 0 bytes tests/sdl-client/bmp/fedship.bmp | Bin 103478 -> 0 bytes tests/sdl-client/bmp/indship.bmp | Bin 87098 -> 0 bytes tests/sdl-client/bmp/kliship.bmp | Bin 103478 -> 0 bytes ...-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp | Bin 3390 -> 0 bytes ...old-r-normal--15-120-100-100-c-90-iso8859-1.bmp | Bin 4862 -> 0 bytes ...edium-r-normal--13-120-75-75-c-80-iso8859-1.bmp | Bin 3390 -> 0 bytes ...ium-r-normal--15-120-100-100-c-90-iso8859-1.bmp | Bin 4862 -> 0 bytes tests/sdl-client/bmp/oriship.bmp | Bin 103478 -> 0 bytes tests/sdl-client/bmp/romship.bmp | Bin 103478 -> 0 bytes tests/sdl-client/bmp/sbexpl.bmp | Bin 29050 -> 0 bytes tests/sdl-client/bmp/shexpl.bmp | Bin 9832 -> 0 bytes tests/sdl-client/conf.h | 13 - tests/sdl-client/debug.c | 42 - tests/sdl-client/debug.h | 44 - tests/sdl-client/decode.c | 38 - tests/sdl-client/decode.h | 23 - tests/sdl-client/dlist.h | 174 - tests/sdl-client/encode.c | 107 - tests/sdl-client/fnt/10x20.fnt | Bin 10240 -> 0 bytes tests/sdl-client/fnt/5x7.fnt | Bin 1792 -> 0 bytes tests/sdl-client/fnt/5x8.fnt | Bin 2048 -> 0 bytes tests/sdl-client/fnt/6x10.fnt | Bin 2560 -> 0 bytes tests/sdl-client/fnt/6x12.fnt | Bin 3072 -> 0 bytes tests/sdl-client/fnt/6x13.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/6x13B.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/6x13O.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/6x9.fnt | Bin 2304 -> 0 bytes tests/sdl-client/fnt/7x13.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/7x13B.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/7x13O.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/7x14.fnt | Bin 3584 -> 0 bytes tests/sdl-client/fnt/7x14B.fnt | Bin 3584 -> 0 bytes tests/sdl-client/fnt/8x13.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/8x13B.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/8x13O.fnt | Bin 3328 -> 0 bytes tests/sdl-client/fnt/9x15.fnt | Bin 7680 -> 0 bytes tests/sdl-client/fnt/9x15B.fnt | Bin 7680 -> 0 bytes tests/sdl-client/fnt/9x18.fnt | Bin 9216 -> 0 bytes tests/sdl-client/fnt/9x18B.fnt | Bin 9216 -> 0 bytes tests/sdl-client/main.c | 872 -- tests/sdl-client/main.h | 29 - tests/sdl-client/ogg/README | 5 - tests/sdl-client/packets.c | 327 - tests/sdl-client/packets.h | 151 - tests/sdl-client/pool.c | 417 - tests/sdl-client/pool.h | 122 - tests/sdl-client/rawobjs.h | 79 - tests/sdl-client/screen.c | 65 - tests/sdl-client/screen.h | 34 - tests/sdl-client/tests/draw.c | 948 -- tests/sdl-client/tests/draw.h | 75 - tests/sdl-client/tests/fonts.c | 318 - tests/sdl-client/tests/fonts.h | 46 - tests/sdl-client/tests/msg.c | 189 - tests/sdl-client/tests/netrek-like.c | 124 - tests/sdl-client/tests/rot.c | 182 - tests/sdl-client/tests/snd.c | 159 - tests/sdl-client/thread_msg.c | 432 - tests/sdl-client/thread_msg.h | 86 - tests/sdl-client/thread_net_recv.c | 191 - tests/sdl-client/thread_net_recv.h | 65 - tests/sdl-client/thread_net_send.c | 71 - tests/sdl-client/thread_net_send.h | 35 - tests/sdl-client/wav/README | 1 - tests/sdl-client/wav/nt_cloaked.wav | Bin 198704 -> 0 bytes tests/sdl-client/wav/nt_explosion_other.wav | Bin 276878 -> 0 bytes tests/sdl-client/wav/nt_fire_torp_other.wav | Bin 52940 -> 0 bytes tests/sdl-client/wav/nt_plasma_hit.wav | Bin 108878 -> 0 bytes tests/sdl-client/wav/nt_shield_down.wav | Bin 89732 -> 0 bytes tests/sdl-client/wav/nt_shield_up.wav | Bin 66922 -> 0 bytes tests/sdl-client/wav/nt_uncloak.wav | Bin 253180 -> 0 bytes tests/zlib/README | 3 - tests/zlib/deflate.c | 87 - tests/zlib/inflate.c | 91 - 311 files changed, 50727 deletions(-) delete mode 100644 Xisop/LICENSE delete mode 100644 Xisop/README delete mode 100644 Xisop/TODO delete mode 100755 Xisop/doc/clean.sh delete mode 100755 Xisop/doc/make.sh delete mode 100644 Xisop/doc/xisop.lyx delete mode 100755 Xisop/src/clean.sh delete mode 100755 Xisop/src/common/clean.sh delete mode 100755 Xisop/src/common/kernel/clean.sh delete mode 100644 Xisop/src/common/kernel/debug.c delete mode 100644 Xisop/src/common/kernel/debug.h delete mode 100644 Xisop/src/common/kernel/device.c delete mode 100644 Xisop/src/common/kernel/device.h delete mode 100644 Xisop/src/common/kernel/exception.c delete mode 100644 Xisop/src/common/kernel/exception.h delete mode 100644 Xisop/src/common/kernel/main.c delete mode 100644 Xisop/src/common/kernel/main.h delete mode 100755 Xisop/src/common/kernel/make.sh delete mode 100644 Xisop/src/common/kernel/memory.c delete mode 100644 Xisop/src/common/kernel/memory.h delete mode 100644 Xisop/src/common/kernel/object.h delete mode 100644 Xisop/src/common/kernel/port.c delete mode 100644 Xisop/src/common/kernel/port.h delete mode 100644 Xisop/src/common/kernel/scheduler.c delete mode 100644 Xisop/src/common/kernel/scheduler.h delete mode 100644 Xisop/src/common/kernel/signal.c delete mode 100644 Xisop/src/common/kernel/signal.h delete mode 100644 Xisop/src/common/kernel/statistic.c delete mode 100644 Xisop/src/common/kernel/statistic.h delete mode 100644 Xisop/src/common/kernel/syscall.c delete mode 100644 Xisop/src/common/kernel/syscall.h delete mode 100644 Xisop/src/common/kernel/task.c delete mode 100644 Xisop/src/common/kernel/task.h delete mode 100755 Xisop/src/common/kernlib/clean.sh delete mode 100644 Xisop/src/common/kernlib/fifo.h delete mode 100644 Xisop/src/common/kernlib/hash.c delete mode 100644 Xisop/src/common/kernlib/hash.h delete mode 100644 Xisop/src/common/kernlib/lifo.h delete mode 100644 Xisop/src/common/kernlib/list.h delete mode 100755 Xisop/src/common/kernlib/make.sh delete mode 100644 Xisop/src/common/kernlib/rand.c delete mode 100644 Xisop/src/common/kernlib/rand.h delete mode 100644 Xisop/src/common/kernlib/setjmp.h delete mode 100644 Xisop/src/common/kernlib/string.h delete mode 100644 Xisop/src/common/kernlib/string/_strcat.c delete mode 100644 Xisop/src/common/kernlib/string/_strcpy.c delete mode 100644 Xisop/src/common/kernlib/string/_strdup.c delete mode 100644 Xisop/src/common/kernlib/string/_strncat.c delete mode 100644 Xisop/src/common/kernlib/string/_strncpy.c delete mode 100644 Xisop/src/common/kernlib/string/_strndup.c delete mode 100644 Xisop/src/common/kernlib/string/_strrev.c delete mode 100644 Xisop/src/common/kernlib/string/bstr_alloc.c delete mode 100644 Xisop/src/common/kernlib/string/bstr_free.c delete mode 100644 Xisop/src/common/kernlib/string/bstr_new.c delete mode 100644 Xisop/src/common/kernlib/string/case.c delete mode 100644 Xisop/src/common/kernlib/string/htol.c delete mode 100644 Xisop/src/common/kernlib/string/memcmp.c delete mode 100644 Xisop/src/common/kernlib/string/memcpy.c delete mode 100644 Xisop/src/common/kernlib/string/memhash32.c delete mode 100644 Xisop/src/common/kernlib/string/memmove.c delete mode 100644 Xisop/src/common/kernlib/string/memset.c delete mode 100644 Xisop/src/common/kernlib/string/pageclr.c delete mode 100644 Xisop/src/common/kernlib/string/straspl.c delete mode 100644 Xisop/src/common/kernlib/string/strchr.c delete mode 100644 Xisop/src/common/kernlib/string/strcmp.c delete mode 100644 Xisop/src/common/kernlib/string/strlen.c delete mode 100644 Xisop/src/common/kernlib/string/strnchr.c delete mode 100644 Xisop/src/common/kernlib/string/strncmp.c delete mode 100644 Xisop/src/common/kernlib/string/strnlen.c delete mode 100644 Xisop/src/common/kernlib/string/strnrchr.c delete mode 100644 Xisop/src/common/kernlib/string/strrchr.c delete mode 100644 Xisop/src/common/kernlib/string/strspl.c delete mode 100755 Xisop/src/common/make.sh delete mode 100644 Xisop/src/common/types.h delete mode 100644 Xisop/src/config.h delete mode 100644 Xisop/src/generic_makedefs.sh delete mode 100755 Xisop/src/make.sh delete mode 100644 Xisop/src/ports/amiga/boot/DOTuaerc delete mode 100644 Xisop/src/ports/amiga/boot/README delete mode 100644 Xisop/src/ports/amiga/boot/bootf/bootf_c.c delete mode 100644 Xisop/src/ports/amiga/boot/bootf/bootf_s.s delete mode 100644 Xisop/src/ports/amiga/boot/bootf/bootf_script.ld delete mode 100755 Xisop/src/ports/amiga/boot/clean.sh delete mode 100644 Xisop/src/ports/amiga/boot/config.h delete mode 100644 Xisop/src/ports/amiga/boot/image_script.ld delete mode 100644 Xisop/src/ports/amiga/boot/init.c delete mode 100755 Xisop/src/ports/amiga/boot/make.sh delete mode 100644 Xisop/src/ports/amiga/boot/tools/aosbblock.c delete mode 100644 Xisop/src/ports/amiga/boot/tools/config.c delete mode 100644 Xisop/src/ports/amiga/boot/tools/dumpkern.c delete mode 100755 Xisop/src/ports/amiga/clean.sh delete mode 100755 Xisop/src/ports/amiga/make.sh delete mode 100644 Xisop/src/ports/amiga/makedefs.sh delete mode 100644 Xisop/src/ports/amiga/support.h delete mode 100644 Xisop/src/ports/amiga/support_c.c delete mode 100644 Xisop/src/ports/amiga/support_s.s delete mode 100755 Xisop/src/processors/i386/make.sh delete mode 100644 Xisop/src/processors/i386/support.h delete mode 100644 Xisop/src/processors/i386/support.s delete mode 100755 Xisop/src/processors/m68k/clean.sh delete mode 100755 Xisop/src/processors/m68k/make.sh delete mode 100644 Xisop/src/processors/m68k/math/README delete mode 100644 Xisop/src/processors/m68k/math/divsi3.s delete mode 100644 Xisop/src/processors/m68k/math/modsi3.s delete mode 100644 Xisop/src/processors/m68k/math/mulsi3.s delete mode 100644 Xisop/src/processors/m68k/math/udivsi3.s delete mode 100644 Xisop/src/processors/m68k/math/umodsi3.s delete mode 100644 Xisop/src/processors/m68k/support.h delete mode 100644 Xisop/src/processors/m68k/support.s delete mode 100644 site/contributors.html delete mode 100644 site/cvs.html delete mode 100644 site/donations.html delete mode 100644 site/favicon.ico delete mode 100644 site/images/CVS.jpg delete mode 100644 site/images/key.jpg delete mode 100644 site/images/sigil.jpg delete mode 100644 site/index.html delete mode 100644 site/mirrors.html delete mode 100644 site/new/TODO delete mode 100644 site/new/build/GNUmakefile delete mode 100644 site/new/build/README delete mode 100644 site/new/build/TODO delete mode 100644 site/new/build/english/faq_mmftpd.txt delete mode 100644 site/new/build/english/faq_mmmail.txt delete mode 100644 site/new/build/english/faq_mmstatd.txt delete mode 100644 site/new/build/english/menu_languages.txt delete mode 100644 site/new/build/english/menu_main.txt delete mode 100644 site/new/build/english/menu_mirrors.txt delete mode 100644 site/new/build/english/page_contact.txt delete mode 100644 site/new/build/english/page_contributors.txt delete mode 100644 site/new/build/english/page_cvs.txt delete mode 100644 site/new/build/english/page_donations.txt delete mode 100644 site/new/build/english/page_index.txt delete mode 100644 site/new/build/english/page_mirrors.txt delete mode 100644 site/new/build/english/page_philosophy.txt delete mode 100644 site/new/build/english/page_projects.txt delete mode 100644 site/new/build/english/page_software.txt delete mode 100644 site/new/build/english/soft_descriptions.txt delete mode 100644 site/new/build/mmsite.c delete mode 100644 site/new/build/mmsite.conf delete mode 100644 site/new/build/site_faq.txt delete mode 100644 site/new/build/site_languages.txt delete mode 100644 site/new/build/site_mirrors.txt delete mode 100644 site/new/build/site_pages.txt delete mode 100644 site/new/build/site_software.txt delete mode 100644 site/new/build/soft_development.txt delete mode 100644 site/new/build/soft_old.txt delete mode 100644 site/new/build/soft_stable.txt delete mode 100644 site/philosophy.html delete mode 100644 site/projects.html delete mode 100644 site/software.html delete mode 100644 tests/entropy/README delete mode 100644 tests/entropy/entropy_disk.c delete mode 100644 tests/js-test/README delete mode 100644 tests/js-test/js/copy.js delete mode 100644 tests/js-test/js/fd.js delete mode 100644 tests/js-test/js/game/objects.js delete mode 100644 tests/js-test/js/httpd/httpd.js delete mode 100644 tests/js-test/js/httpd/ml_clean.js delete mode 100644 tests/js-test/js/httpd/ml_machine.js delete mode 100644 tests/js-test/js/httpd/options.js delete mode 100644 tests/js-test/js/httpd/root.js delete mode 100644 tests/js-test/js/httpd/string.js delete mode 100644 tests/js-test/js/ml.js delete mode 100644 tests/js-test/js/ml2.js delete mode 100644 tests/js-test/js/ml3.js delete mode 100644 tests/js-test/js/ml4.js delete mode 100644 tests/js-test/js/ml5.js delete mode 100644 tests/js-test/js/ml6.js delete mode 100644 tests/js-test/js/parse.js delete mode 100644 tests/js-test/js/poll_test.js delete mode 100644 tests/js-test/js/sock_httpd.js delete mode 100644 tests/js-test/js/sock_listen.js delete mode 100644 tests/js-test/js/test.js delete mode 100644 tests/js-test/js/test2.js delete mode 100644 tests/js-test/js/test3.js delete mode 100644 tests/js-test/src/GNUmakefile delete mode 100644 tests/js-test/src/classes/js_errno.c delete mode 100644 tests/js-test/src/classes/js_errno.h delete mode 100644 tests/js-test/src/classes/js_fd.c delete mode 100644 tests/js-test/src/classes/js_fd.h delete mode 100644 tests/js-test/src/classes/js_global.c delete mode 100644 tests/js-test/src/classes/js_global.h delete mode 100644 tests/js-test/src/classes/js_mysql.c delete mode 100644 tests/js-test/src/classes/js_mysql.h delete mode 100644 tests/js-test/src/classes/js_pgsql.c delete mode 100644 tests/js-test/src/classes/js_pgsql.h delete mode 100644 tests/js-test/src/classes/js_signal.c delete mode 100644 tests/js-test/src/classes/js_signal.h delete mode 100644 tests/js-test/src/js-server.c delete mode 100755 tests/js-test/util/spidermonkey-config delete mode 100644 tests/kqueue/GNUmakefile delete mode 100644 tests/kqueue/README delete mode 100644 tests/kqueue/client.c delete mode 100644 tests/kqueue/client.h delete mode 100644 tests/kqueue/conf.h delete mode 100644 tests/kqueue/daemon.c delete mode 100644 tests/kqueue/daemon.h delete mode 100644 tests/kqueue/kqueue.c delete mode 100644 tests/kqueue/kqueue.h delete mode 100644 tests/kqueue/main.c delete mode 100644 tests/kqueue/net.c delete mode 100644 tests/kqueue/net.h delete mode 100644 tests/kqueue/packets.c delete mode 100644 tests/kqueue/packets.h delete mode 100644 tests/kqueue/recvq.c delete mode 100644 tests/kqueue/recvq.h delete mode 100644 tests/kqueue/sendq.c delete mode 100644 tests/kqueue/sendq.h delete mode 100644 tests/memory/README delete mode 100644 tests/pthread/README delete mode 100644 tests/pthread_utils/GNUmakefile delete mode 100644 tests/pthread_utils/README delete mode 100644 tests/pthread_utils/mm_pthread_debug.h delete mode 100644 tests/pthread_utils/mm_pthread_msg.c delete mode 100644 tests/pthread_utils/mm_pthread_msg.h delete mode 100644 tests/pthread_utils/mm_pthread_poll.c delete mode 100644 tests/pthread_utils/mm_pthread_poll.h delete mode 100644 tests/pthread_utils/mm_pthread_pool.c delete mode 100644 tests/pthread_utils/mm_pthread_pool.h delete mode 100644 tests/pthread_utils/mm_pthread_sleep.c delete mode 100644 tests/pthread_utils/mm_pthread_sleep.h delete mode 100644 tests/pthread_utils/tests/msg_test.c delete mode 100644 tests/pthread_utils/tests/poll_test.c delete mode 100644 tests/pthread_utils/tests/polltest.c delete mode 100644 tests/pthread_utils/tests/sigtest.c delete mode 100644 tests/rlookup/GNUmakefile delete mode 100644 tests/rlookup/main.c delete mode 100644 tests/rlookup/rlc.c delete mode 100644 tests/rlookup/rlc.h delete mode 100644 tests/rotate/GNUmakefile delete mode 100644 tests/rotate/main.c delete mode 100644 tests/sdl-client/GNUmakefile delete mode 100644 tests/sdl-client/README delete mode 100644 tests/sdl-client/bmp/FedCA.bmp delete mode 100644 tests/sdl-client/bmp/README delete mode 100644 tests/sdl-client/bmp/RomDD.bmp delete mode 100755 tests/sdl-client/bmp/fedship.bmp delete mode 100755 tests/sdl-client/bmp/indship.bmp delete mode 100755 tests/sdl-client/bmp/kliship.bmp delete mode 100644 tests/sdl-client/bmp/misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp delete mode 100644 tests/sdl-client/bmp/misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1.bmp delete mode 100644 tests/sdl-client/bmp/misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1.bmp delete mode 100644 tests/sdl-client/bmp/misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1.bmp delete mode 100755 tests/sdl-client/bmp/oriship.bmp delete mode 100755 tests/sdl-client/bmp/romship.bmp delete mode 100755 tests/sdl-client/bmp/sbexpl.bmp delete mode 100755 tests/sdl-client/bmp/shexpl.bmp delete mode 100644 tests/sdl-client/conf.h delete mode 100644 tests/sdl-client/debug.c delete mode 100644 tests/sdl-client/debug.h delete mode 100644 tests/sdl-client/decode.c delete mode 100644 tests/sdl-client/decode.h delete mode 100644 tests/sdl-client/dlist.h delete mode 100644 tests/sdl-client/encode.c delete mode 100644 tests/sdl-client/fnt/10x20.fnt delete mode 100644 tests/sdl-client/fnt/5x7.fnt delete mode 100644 tests/sdl-client/fnt/5x8.fnt delete mode 100644 tests/sdl-client/fnt/6x10.fnt delete mode 100644 tests/sdl-client/fnt/6x12.fnt delete mode 100644 tests/sdl-client/fnt/6x13.fnt delete mode 100644 tests/sdl-client/fnt/6x13B.fnt delete mode 100644 tests/sdl-client/fnt/6x13O.fnt delete mode 100644 tests/sdl-client/fnt/6x9.fnt delete mode 100644 tests/sdl-client/fnt/7x13.fnt delete mode 100644 tests/sdl-client/fnt/7x13B.fnt delete mode 100644 tests/sdl-client/fnt/7x13O.fnt delete mode 100644 tests/sdl-client/fnt/7x14.fnt delete mode 100644 tests/sdl-client/fnt/7x14B.fnt delete mode 100644 tests/sdl-client/fnt/8x13.fnt delete mode 100644 tests/sdl-client/fnt/8x13B.fnt delete mode 100644 tests/sdl-client/fnt/8x13O.fnt delete mode 100644 tests/sdl-client/fnt/9x15.fnt delete mode 100644 tests/sdl-client/fnt/9x15B.fnt delete mode 100644 tests/sdl-client/fnt/9x18.fnt delete mode 100644 tests/sdl-client/fnt/9x18B.fnt delete mode 100644 tests/sdl-client/main.c delete mode 100644 tests/sdl-client/main.h delete mode 100644 tests/sdl-client/ogg/README delete mode 100644 tests/sdl-client/packets.c delete mode 100644 tests/sdl-client/packets.h delete mode 100644 tests/sdl-client/pool.c delete mode 100644 tests/sdl-client/pool.h delete mode 100644 tests/sdl-client/rawobjs.h delete mode 100644 tests/sdl-client/screen.c delete mode 100644 tests/sdl-client/screen.h delete mode 100644 tests/sdl-client/tests/draw.c delete mode 100644 tests/sdl-client/tests/draw.h delete mode 100644 tests/sdl-client/tests/fonts.c delete mode 100644 tests/sdl-client/tests/fonts.h delete mode 100644 tests/sdl-client/tests/msg.c delete mode 100644 tests/sdl-client/tests/netrek-like.c delete mode 100644 tests/sdl-client/tests/rot.c delete mode 100644 tests/sdl-client/tests/snd.c delete mode 100644 tests/sdl-client/thread_msg.c delete mode 100644 tests/sdl-client/thread_msg.h delete mode 100644 tests/sdl-client/thread_net_recv.c delete mode 100644 tests/sdl-client/thread_net_recv.h delete mode 100644 tests/sdl-client/thread_net_send.c delete mode 100644 tests/sdl-client/thread_net_send.h delete mode 100644 tests/sdl-client/wav/README delete mode 100755 tests/sdl-client/wav/nt_cloaked.wav delete mode 100755 tests/sdl-client/wav/nt_explosion_other.wav delete mode 100755 tests/sdl-client/wav/nt_fire_torp_other.wav delete mode 100755 tests/sdl-client/wav/nt_plasma_hit.wav delete mode 100755 tests/sdl-client/wav/nt_shield_down.wav delete mode 100755 tests/sdl-client/wav/nt_shield_up.wav delete mode 100755 tests/sdl-client/wav/nt_uncloak.wav delete mode 100644 tests/zlib/README delete mode 100644 tests/zlib/deflate.c delete mode 100644 tests/zlib/inflate.c diff --git a/Xisop/LICENSE b/Xisop/LICENSE deleted file mode 100644 index aadb1b9..0000000 --- a/Xisop/LICENSE +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id: LICENSE,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (c) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/Xisop/README b/Xisop/README deleted file mode 100644 index 7681f89..0000000 --- a/Xisop/README +++ /dev/null @@ -1,53 +0,0 @@ -$Id: README,v 1.7 2004/06/04 02:31:51 mmondor Exp $ - - - -Xisop Copyright 2001-2003, Matthew Mondor, -All rights reserved. - -Currently under development. The only current port is Amiga, and an .uaerc -is provided for the UAE emulator to test it and possibly enhance it :) - Xisop/src/ports/amiga/boot/DOTuaerc -It is recommended to run the UAE emulator using the -T command line parameter -when on unix systems (or setting the x11.use_mitshm=true in the ~/.uaerc file). -Note that kickstart 3.0 or later is required, and that I will not provide this -file to anyone, as it is copyrighted material. You can buy a kickstart kit, or -mirror the one of your amiga to file. The models which used to ship with 3.0+ -natively were the A1200 and A4000. It is possible to make Xisop kickstart 1.3 -compatible if it was to be used to make games, since only the bootloader is -AmigaOS dependent. - -The compiled kernel is 30k in size if compiled with statistics support, or -19k otherwise. - -The source of the port-dependent initialization function (which currently -launches tasks displaying colors for testing and demonstrating) is located at - Xisop/src/ports/amiga/boot/init.c - -Some development notes are also being worked on according to the internal -implementation details, programming style notes and how to port Xisop -(also under development as the kernel interfaces are being stabilized). - Xisop/doc/xisop.pdf -This file is built from xisop.lyx which is maintained using the LyX utility. - -Almost all the current code and documentation were re-written from scratch in -Febuary and March 2003. The old Xisop code somewhat served as reference -when needed. - -Please read TODO on what currently needs to be worked on to continue the -project, what was done and what needs debugging. The project is to eventually -be fully released under BSD-style license when at least one port works fine. -Make sure to also read the documentation in doc/. - -To build the amiga port you should specify the location of the cross building -tools in Xisop/src/ports/amiga/makedefs.sh, or use the defaults if you have -a NetBSD 1.6.1 source, in which case you can simply use the build.sh script -provided in /usr/src to build the netbsdelf-m68k target toolchain (which only -needs to be done once): - cd /usr/src - ./build.sh -a m68k -t -Then: - cd Xisop/src - ./make.sh -t amiga - -Matthew Mondor diff --git a/Xisop/TODO b/Xisop/TODO deleted file mode 100644 index 9c2d318..0000000 --- a/Xisop/TODO +++ /dev/null @@ -1,163 +0,0 @@ -$Id: TODO,v 1.20 2004/10/14 15:13:20 mmondor Exp $ - - -- Import modifications from mmsoftware/mmlib: - - New more efficient pool allocator, with enhanced debugging capability. - This could imply reworking some of the whole system. - - Maybe incorporate C byteorder library, so that less processor-specific - code is required (of course, they can override C ones with asm ones). - - -Working: -======= -- Memory management system and ANSI-C related functions -- Syscalls, including one which allows to execute arbitrary code in supervisor - mode -- Exclusive, recursive and read/write locks -- User interrupt facilities -- Preemptive multitasking, _yield() and task_sleep()/task_wakeup() -- CPU saving ideling - When no tasks are on the ready queue to run, the _scontext _ctx_t - defined in scheduler.c is resumed, which in fact returns to main.c's - main() function, which sole purpose is to sys_idle(), in a loop, - which suspends the processor until the next interrupt occurs. -- Serious exceptions generate a display showing a number of lines which - corresponds to the actual error (_ecatch() parameter), useful to debug - the current Amiga port. -- Useful statistics book-keeping of global counters -- Inter-task signals -- Inter-task communication reliable ports and messages -- The init and task reaper system tasks -- Operations which need fast lookup tables to use kernlib/hash.[ch]. - This is done for some system lists, such as for port_find(). -- Multiple tasks shareing a common mpool_t created with TF_SHARED - - -Bugs to work out: -================ -- There again is some problem with memory or stack sizes. When DEBUG and - STATISTICS are enabled in config.h, things do not work as intended. - This seems to simply arise now that the kernel image is about a k larger. - For some reason, the ports/amiga/boot/config.h values do not seem to - always generate proper kernel images, for instance when I increase the - stack size to 16384 I get a guru meditation... -- The scheduler which takes task priorities into account is currently not - working. There is a temporary replacement scheduler which works now and - only performs round-robin when preempting tasks. The old one which has - some bugs is found in src/common/kernel/scheduler.c and is called - old_schedule(). -- Signals and message ports - Some hack should be found a more appropriate solution: signal_send() - needs to _yield() twice (See src/common/kernel/signal.c). - For some not yet determined reason, tasks would all eventually be - stuck on the wait queue if this was not done. - - -Remaining to complete: -===================== -- Add system similar to mmlib/mmalarm(3) to Xisop, to go with the existing - MI interrupt hook management functions -- Perhaps use hashtables in exceptions hooks management instead of linked - lists? Is this needed or wanted? Running through a hash table is slower, - but lookups are faster. Think about it and see which is best to use. -- Fix issue with amiga port init stack size... m68k usermode() could - be specified a stack size for instance, at least. We also could - reserve some memory for the stack in advance and supply it... -- Implement setjmp()/longjmp() for i386 -- CPU specific _bfill16 and _bfill32 etc (at least _bfillint or such), - to efficiently fill a native word size with an 8-bit pattern. This - could be used by the string library in memset() for instance... -- Probably that the cases of usecount (devicenode_t, mpool_t) could use - an _rlock_t for more efficiency. It is implemented in assembler, and - is sure to be atomic. -- Finish dprintf() FIFO operation optimizations, and write a generic - vsnprintf() implementation with stdarg. We want to enhance DPRINTF() - to print module and line numbers, etc. -- _panic() -- Console and printf() (along with corresponding console.device) -- Map remaining exceptions to output messages on console - For the console.device to eventually exist, the port primitives are - essencial. So until they work reliably it's not really possible to - implement right now (at least on Amiga). - It would be easy to use the video hardware memory on a i386 port - however, so a i386 port could perhaps actually help in development - for the rest :) - Ports implementation is now working reliably. Revise. -- Probably that the statistics would also be nice to have on a per-task basis. - Moreover, they are not as useful as they would if a console existed :< - currently, the DPRINTF() system logs to a FIFO buffer. -- Xisop shared libraries -- Xisop devices as a synchronization abstraction over the message ports system -- Xisop handlers as a higher-level (filesystem/file) abstraction over devices - libraries and/or hardware -- Relocatable binary loader - This unfortunately either implies writing a full fledged ELF or a.out - loader, or a BFD library for GCC ld to output in a new desired format. - The ELF loader was started but was not completed (not included in the - current sources). ELF unfortunately seems really bloated for the - actual needs of this project, and it's state is uncertain. - The loader would be used to load shared libraries, and executable - tasks, including devices and handlers. - For the moment, the system is monolithic and soon a simple interface - will be provided to allow the port-specific code to provide a list - of tasks to be launched by Xisop init. - That alone, even monolithic, allows Xisop to stand as a nice C - interface which most code is portable among 32-bit systems, to abstract - interrupt facilities, shared memory access and multitasking for - various applications. Very small, it can fit the application on a - floppy (which includes the kernel). -- timer.device -- input.device -- console.device -- Add necessary functions to allow linking in the common/kernlib/hash.c module - - - -NEW MEMORY MANAGEMENT SYSTEM NOTES: - -As before, we need several types of memory. -For each memory type, we should still attach/detach memory chunks, like now. - -For each memory chunk, a new system should be implemented for page-level -contiguous memory management and freeing, as well as a new pool allocator, -based on the idea of the new mmlib/mmpool(3) one. - -Because Xisop does not rely on MMU/PMMU, we can simplify the allocator to a -simple block allocator, without even worrying about page boundaries, if we -wanted. This would also mean that a pool page could be virtual, that is, could -not be dependent on the system page size at all, if we wanted. If that was the -case, the current mmlib/mmpool(3) allocator could be used as-is. - -Not to say that, even if we respected page alignment, we still could use a -better allocator. - -A good idea would be to maintain a list of contiguous page (or memory bytes) -chunks. Nodes of this list would be split as necessary to provide the -requested size in the allocation functions. The freeing functions would need -to attempt to coalesce the contigious chunks together when possible as well. - -Perhaps that we also would like a best-fit strategy rather than first-fit when -allocating, so that we could favor contiguous memory chunks that are closest -in size to the requested amount, rather than always splitting large chunks -unnecessarily. This would reduce fragmentation, although being slower at -allocation. However, because this would affect the page allocator, to which -calls would be reduced by the pool allocators, this could be reasonable. - -Perhaps that to observe the best-fit strategy it would be possible to somewhat -maintain a sorted index or such, of the smaller to larger available chunks. -It needs to be verified that the code and memory overhead for such an index -is negligeable, however. Moreover, would keeping a sorted list of free chunks -useful for performance? How would the allocator efficiently perform jumps in -the list? Wouldn't it need to be a tree, instead? If we used one, wouldn't we -need recursion or special iteration for both node insertion and lookup? I will -need to check that out. What I should do is count the iterations in my similar -sorted tree system in dnamed, to get an idea of the actual code overhead -involved. - -struct contiguous_chunk { - node_t chunks_node; /* To link in free/allocated chunks list */ - node_t sorted_node; /* To link in free chunks sorted list */ - void *address; /* Starting address of free memory */ - size_t length; /* Size of contiguous free memory */ - u_int32_t pages; /* Or, could be number of free pages */ -}; diff --git a/Xisop/doc/clean.sh b/Xisop/doc/clean.sh deleted file mode 100755 index f4bf49d..0000000 --- a/Xisop/doc/clean.sh +++ /dev/null @@ -1,3 +0,0 @@ -# $Id: clean.sh,v 1.2 2004/06/06 04:21:45 mmondor Exp $ - -rm -f xisop.dvi xisop.tex xisop.lyx~ xisop.pdf xisop.ps xisop.toc .log diff --git a/Xisop/doc/make.sh b/Xisop/doc/make.sh deleted file mode 100755 index 2300408..0000000 --- a/Xisop/doc/make.sh +++ /dev/null @@ -1,11 +0,0 @@ -# $Id: make.sh,v 1.3 2004/06/06 04:21:05 mmondor Exp $ - -# First export LyX document to LaTeX then run this script - -lyx -e latex xisop.lyx -latex xisop.tex -latex xisop.tex -rm -f xisop.ps xisop.aux xisop.log .log -dvips -Pcmz -Pamz -o xisop.ps -t letter -D 300 -Z xisop.dvi -ps2pdf xisop.ps -rm -f *~ diff --git a/Xisop/doc/xisop.lyx b/Xisop/doc/xisop.lyx deleted file mode 100644 index ad156ca..0000000 --- a/Xisop/doc/xisop.lyx +++ /dev/null @@ -1,10041 +0,0 @@ -#LyX 1.2 created this file. For more info see http://www.lyx.org/ -\lyxformat 220 -\textclass article -\language english -\inputencoding auto -\fontscheme default -\graphics default -\paperfontsize default -\spacing single -\papersize letterpaper -\paperpackage a4 -\use_geometry 1 -\use_amsmath 0 -\use_natbib 0 -\use_numerical_citations 0 -\paperorientation portrait -\topmargin 0.5in -\bottommargin 0.5in -\secnumdepth 3 -\tocdepth 3 -\paragraph_separation indent -\defskip medskip -\quotes_language english -\quotes_times 2 -\papercolumns 1 -\papersides 1 -\paperpagestyle default - -\layout Title - -Xisop kernel development notes -\layout Author -\pagebreak_bottom -Copyright (c) 2001-2003, Matthew Mondor -\newline -All rights reserved. -\layout Standard - - -\begin_inset LatexCommand \tableofcontents{} - -\end_inset - - -\layout Section -\pagebreak_top -General development notes -\layout Standard - -Before attempting to write software for Xisop to expand it's funtionality, - or before porting Xisop to a new architecture, it is recommended to carefully - read this manual entirely. - It attempts to answer all questions one could have about it's organization - and build process, as well as style and conventions one must follow for - code consistancy with the rest of the project. -\layout Subsection - -Development software used -\layout Standard - -To develop Xisop, the GNU GCC suite of compiler, assembler, linker and binutils - software was chosen. - The main reasons for this consists of cost savings, and portability. - GCC has support for many different CPU types was a main factor. - Moreover, the AT&T assembly syntax allows to somewhat obtain some consistency. -\layout Standard - -An effort was made to try to not support GCC-specific functions however, - for portability reasons. - For instance, the various -\emph on -_spl -\emph default -* -\emph on -() -\emph default - functions are implemented as macros around a separate assembly function, - located in the assembler -\emph on -.s -\emph default - files, rather than embedded inside the C code using inline assembly directives. - ( -\emph on -XXX -\emph default - -\emph on -actually they may be fixed to be GCC-dependent soon heh -\emph default -). -\layout Standard - -A choice was made to not use GNU or BSD make. - Instead, -\emph on -/bin/sh -\emph default - is assumed to exist. - This usually consists of a POSIX compliant shell, on GNU systems (and Linux) - the -\emph on -bash -\emph default - shell usually emulates it's behavior and -\emph on -/bin/sh -\emph default - then consists of a symbolic link to -\emph on -/bin/bash -\emph default -. - On BSD systems only POSIX 1003.2 and 1003.2a functionality is usually present - in their -\emph on -/bin/sh -\emph default -, which is what Xisop build scripts are making use of. - As -\emph on - -\emph default -such, -\emph on - bash -\emph default - is therefore not a requirement. -\layout Standard - -This document is written and maintained using LyX. - The UAE (Amiga emulator) and Bochs (i386 emulator) utilities were useful - to develop the current ports. - The original host development system consists of an i386 compatible system - running NetBSD 1.6_STABLE. - This operating system is ideal for programming and cross compiling. - The current Xisop building system was tuned to the NetBSD 1.6.1 toolchain. - To compile the amiga port, for instance, you only should need to use the - build.sh script to build the suite of netbsdelf-m68k tools. - Using the Xisop -\begin_inset Quotes eld -\end_inset - - -\emph on -./make.sh -t amiga -\emph default - -\begin_inset Quotes erd -\end_inset - - command should then build the amiga target. -\layout Standard - -The software was written using the VIm editor, with -\emph on -ts=8 -\emph default -, -\emph on -sw=4 -\emph default - and -\emph on -cindent -\emph default -. -\layout Standard - -If you compile your own gcc with your intended compiling target, you simply - need to change a file to tell the locations of the various building tools. - See the section about -\begin_inset Quotes eld -\end_inset - -the build process -\begin_inset Quotes erd -\end_inset - - later on for more information. -\layout Subsection - -Xisop compatibility with other systems, and where it fits best -\layout Subsubsection - -UNIX, POSIX, BSD, Linux -\layout Standard - -Xisop is definitely not POSIX, although it's functions are simpler than - POSIX is, requireing a small learning curve only to use. - It was not designed as a general-purpose operating system to replace Unix - and provide all it's capabilities. - It's an entity of it's own, simpler and smaller, mostly made to suit the - requirements of restricted embedded systems. - To implement most POSIX requirements a larger system is required, which - generally also results in slower code. - For instance, Xisop addresses ports and tasks as addresses, rather than - IDs. - This solves the problem of allocation and reuse of process IDs. -\layout Standard - -A Xisop task also is lightweight compared to a UNIX-style process. - Moreover, the need for more custom user signals than POSIX environment - provides made it unsuitable to reserve almost all 32 signals to reserved - semantics. - The concept of file descriptors and select()/poll() is also different. - However, SIGPOLL signal was reserved in Xisop for the implementation of - message-based signals and events using a single message port and signal. - This can be used when there can be a large number of entities a task may - be monitoring, and the user signals would not be appropriate. - It would be possible to work a system out using this facility for the 32 - standard Unix signals if the need existed. -\layout Standard - -Although it would be possible to implement POSIX compatibility libraries, - it was not a main goal in Xisop development. -\layout Subsubsection - -Memory and process protection -\layout Standard - -Xisop was not designed to support Memory Management Unit (MMU) coprocessors - and provide page-grained memory protection. - This helped to implement message passing in a very efficient manner, only - passing pointers around, and reduced considerably kernel size. - Moreover, it allows to provide most user-access system functions in a shared - library, reducing considerably the amount of system calls an application - needs to make (accessed through traps). - The number of traps being reduced, the preemtive scheduler is less clobbered. - Calling functions of a shared library happen entirely in the caller's task - allocated CPU time slice, which means that the kernel load is not affected. - Not requireing MMU is also an advantage with Xisop, as it can run with - a single MC68000L8 for instance, and a little RAM. -\layout Standard - -However, we all know that without appropriate memory protection, Xisop cannot - efficiently protect the kernel from user tasks, which can take full control - on the system at any time. - Clean interfaces were however implemented, which internally perform various - sanity checking to ensure the validity of the supplied objects and arguments, - so that common software bugs do not automatically corrupt memory and the - system. - Xisop knows the difference between a valid task, port, device handle, etc, - and invalid ones. - It also knows when to not attempt to free memory if a wrong pointer is - supplied, since -\emph on -mnode_t -\emph default - nodes are also validated using a unique magic cookie. - Such steps permit to minimize system crashes in the event of a software - bug. -\layout Standard - -The kernel comports special macros to aid in realizing object validity sceals - and dependancies checking, which are defined in < -\emph on -common/kernel/object.h -\emph default ->: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -OBJECT_VALIDATE(objptr,\SpecialChar ~ -objtype) -\emph default - Sets the -\emph on -objptr -\emph default -->object_magic field to -\emph on -objtype -\emph default -. - This type corresponds to one of the -\emph on -OBJECT_ -\emph default -* names which are defined in the same headerfile. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -OBJECT_INVALIDATE(objptr) -\emph default - Sets the -\emph on -objptr -\emph default -->object_magic field to 0. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -OBJECT_REGISTER(objptr) -\emph default - Registers -\emph on -objptr -\emph default - object by setting the -\emph on -objptr -\emph default -->object_id field to a unique number. - This number will be used for matching when verifying for proper dependancy - link. - Only objects which may be required as dependancy to others need to use - this. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -OBJECT_SETDEP(objptr,\SpecialChar ~ -depobjptr) -\emph default - Associates -\emph on -objptr -\emph default - object as requireing the -\emph on -depobjptr -\emph default - object as dependancy for proper function. - What this does is internally set -\emph on -objptr -\emph default -->objdep_magic to -\emph on -depobjptr -\emph default -->magic and -\emph on -objptr -\emph default -->objdep_id to -\emph on -depobjptr -\emph default -->object_id. - As a result, it becomes possible to refuse to perform operations related - to this object if the dependancy link ever dies. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -OBJECT_VALID(objptr,\SpecialChar ~ -objtype) -\emph default - First verifies if objptr is non-NULL, and then evaluates if the object - associated with -\emph on -objptr -\emph default - truely corresponds to -\emph on -objtype -\emph default - ( -\emph on -objptr -\emph default - != NULL && -\emph on -objptr -\emph default -->object_magic == -\emph on -objtype -\emph default -). - This consists of the reason why the various -\emph on -OBJECT_ -\emph default -* definitions in the headerfile should consist of unique values which are - unlikely to occur randomly. - Returns TRUE on success, or FALSE otherwise. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -OBJECT_DEPENDS(objptr,\SpecialChar ~ -depobjptr) -\emph default - Verifies the integrity of a dependancy link, which was previously linked - using -\emph on -OBJECT_SETDEP() -\emph default - on -\emph on -objptr -\emph default -. - This in fact makes sure that the object it should relate to ( -\emph on -depobjptr -\emph default -) is still valid, and consists of the same one ( -\emph on -depobjptr -\emph default - != NULL && -\emph on -depobjptr -\emph default -->object_magic == -\emph on -objptr -\emph default -->objdep_magic && -\emph on -depobjptr -\emph default -->object_id == -\emph on -objptr -\emph default -->objdep_id). - Returns TRUE on success, or FALSE otherwise. -\layout Standard - -Obviously, the structure of an object only requires to hold the fields which - are required for the functionality it requires according to these macros. - Those fields are all expected to be of type -\emph on -u_int32_t -\emph default -. - This system allows relatively lightweight validity checking of object credentia -ls, without the need for memory protection. - The kernel uses them wherever needed for safety. - Using this system also allows to use efficient dynamic memory allocation - techniques ( -\emph on -pool_t -\emph default - functions) to create and destroy critical system objects, and reference - can be made using pointers through the system, rather than using less efficient - or fixed-sized arrays and object ID allocation. - Programming using these macros also yields in a clean interface to result - in consistant, clean C code. -\layout Subsubsection - -Multitasking -\layout Standard - -While Xisop provides preemptive multitasking (more information provided - in the next section), it can be disabled by user applications if need be. - This means that Xisop can be used to create single-tasking applications - where a multitasking environment is not wanted, while still taking advantage - of the abstraction of CPU and hardware access Xisop allows. - This for instance allows games to be written almost entirely in C, and - be independent of an operating system such as Windows or AmigaOS, using - Xisop instead. - Such a small game can be booted from a single floppy, which would comport - all necessary components of the game, including Xisop itself. - Disabling multitasking also allows direct access to the hardware resources - by the main application, in a safe manner. - When multitasking is enabled, such safe access to hardware resources is - also provided, although using the -\emph on -device -\emph default - concept is required to remain multitasking friendly and access those. - More information about Xisop devices is given later on. -\layout Standard - -This means that multitasking was provided as a useful optional facility - rather than to force limits over the applications. - It is great to develop some kinds of systems using multitasking, while - some other applications are much better without it. - This was an important consideration when designing Xisop. - Whether multitasking is enabled or disabled, the public interrupt facilities - interface works as expected. - More information is provided on this interface in a later section. -\layout Subsubsection - -AmigaOS -\layout Standard - -Although some ideas were admitedly borrowed from the Amiga Operating System, - the compatibility stops there. - The AmigaOS headerfiles, although publically available, or source code - (which is unavailable publically) were not used as a reference to write - it, nor can Xisop run AmigaOS native object files and binaries. - Xisop is a clean-room kernel implementation, written from scratch and uses - it's own set of ideas and conventions, which are described in this document. -\layout Standard - -The Xisop signals, message ports, devices and handlers concepts were however - borrowed from AmigaOS, as it was a great proof of feasibility using a very - simple underlaying structure. - The interface and internals do not behave identically but anyone who programmed - using the AmigaOS inter-task communication and synchronization features - will feel at ease with Xisop. -\layout Subsubsection - -Where Xisop fits best -\layout Standard - -The best application Xisop suits for consists of an embedded system, dedicated - to provide specific services or tasks, running with low-cost hardware and - restricted physical memory. - There are however a wide range of applications which fit in this category, - cell phones, microwave ovens, PDAs, clocks, industrial microcontrollers - or event loggers, alarm systems, etc. - An example of low-cost hardware Xisop runs great on is a Motorola MC68000L8 - microprocessor based board with a restricted 512 kilobytes of memory, and - an RS-232 interface with UART controler chip. - Xisop can also be used to develop games on 32-bit consoles or arcade hardware. -\layout Standard - -Xisop consists of a nice component when simplifying hardware design of a - project, where a simple CPU unit, little RAM and Xisop-based software can - provide the tasks of more complex hardware-only solutions. - This also implies that the simpler hardware may then be reused, since it - now basically consists of a general purpose programmable system rather - than single-purpose hardware units which can only serve for a single project. -\layout Standard - -It does not consist of a full multipurpose operating system but rather of - a collection of primitives to aid a C programmer to write his applications - on a variety of hardware, and benefit from memory management including - support for runtime dynamic memory addition and removal, as well as multiple - memory types, inter-task communication primitives, a fair number of user - signals, abstracted interrupt facilities, and a microkernel design allowing - to add future functionality modularized as userspace tasks, shared libraries, - devices and handlers. -\layout Standard - -It's weak license (BSDL-style) makes it especially suitable for commercial - embedded applications when a technical team can build a custom application, - where royalties for use, or redistribution of custom changes in the code - are not required. - An effort is provided to make the CPU-specific interface abstract so that - most of the code can be written in C, for code clarity, consistency, developmen -t speed and ease. - The assembly code is restricted to the minimum, and always consists of - a backend to use C. - The same is true for architecture-specific assembly low-level code. - Those sections are described later on. -\layout Standard - -As such, very little time is generally required to port the basics of Xisop - to a new architecture (other 32-bit ones, at least). - Engineers can then develop custom low-cost hardware and a programmer can - write most of the software for it using C and Xisop rather than having - to write all of it in assembly, or starting from nothing and having to - re-invent the assembly to C support primitives. -\layout Standard - -Very low cost hardware helps when many units are being deployed. - However, in the cases where the hardware costs are higher (i.e. - microprosessor with MMU support and 8 or more megabytes of memory), Xisop - may seem too rudimentary, but there are then alternatives such as NetBSD - which can be ported quite fast (when required, as it already consists of - the most portable OS), and POSIX functionalities, with full unix features, - networking, protected memory, etc all become available. - It is also released under the BSD unrestrictive license and is available - at -\emph on -http://www.netbsd.org -\emph default -. -\layout Subsection - -Xisop coding standards -\layout Subsubsection - -Licencing issues and censorship -\layout Standard - -All code which is to be publically released within the standard Xisop distributi -on should be licensed under a BSD-style license, and should not be released - under the GNU Public License (GPL) or GNU Lesser Public License (LGPL). - It however is obvious that companion packages be released and distributed - separately with the Xisop main archive, as long as it be clearly isolated - and labeled as such, so that it can easily be stripped when code under - such strict a license is not wanted within a project. - It is allowed for authors to include their advertizing clause as wanted - in the BSD license advertizing at the top of their files. - A main file can then easily be created using a script of advertizement - clauses and related files whcih one can append in the documentation of - a commercial or closed source product using Xisop. -\layout Standard - -This allows anyone to use Xisop for open source or closed source projects - as wanted. - Although it is encouraged to publically donate the new processor and architectu -re specific modules one develops, as well as machine-independent new modules - of interest for inclusion into the main Xisop tree, released under BSD - license, noone is obliged to do so. - This also allows the main tree to not become too tainted with alot of code - everyone develops which does not serve the other Xisop users much and mostly - bloat the project. - The mirokernel design easy allows third party supplied libraries, devices - and handlers to be developed, and these may also be closed source, and - commercial. - There of course is no problem to release such optional kernel-independent - modules under one of the GNU licenses. -\layout Standard - -If you port Xisop to a new processor or architecture, and are willing to - contribute the code to the tree, I suggest that the source be obtained - via CVS from the main Xisop source repository, and that -\emph on -cvs diff -u -\emph default - be used to create a patch. - This patch should be sent via email to Matthew Modor, at -\emph on -mmondor@gobot.ca -\emph default -. - I then will attempt to merge it into the main Xisop CVS tree, after performing - basic sanity checking on the code, and fixing required bugs if possible - (if any). - I may also reply back if there is any reason why the changes cannot be - applied, in which case I could help to make it conform with the requirements. -\layout Subsubsection - -Standard data types and when to use them -\layout Standard - -Xisop uses a defined set of data types in it's kernel, and attempts to remain - consistant when using them for code clarity and obviousness. - The following C standard data types are used: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -char -\emph default - The standard C character type, used for C strings only in Xisop. - -\emph on -int8_t -\emph default -and -\emph on - u_int8_t -\emph default - should be used for other byte-related types. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -char\SpecialChar ~ -* -\emph default - Obvious, also only used in direct relation with C strings. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void -\emph default - When a function returns nothing, or has no arguments, for both prototype - and function declaration. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -* -\emph default - This consists as usual, of a pointer to an abstract type, and is used where - required. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -int -\emph default - This is used as a convenient format for various return codes and variables - where bit-size is not a concern, or should match the one which is assumed - for the processor (although it is highly recommended to use the various - defined types below for these). -\layout Standard - -The other standard C data types are replaced by the following ones, which - are defined in the Xisop machine-independent < -\emph on -common/types.h> -\emph default - headerfile: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool -\emph default - Corresponds to -\emph on -int -\emph default -, but specifically denotes that this variable is used for boolean operations - and conditionals for code clarity it may only hold TRUE (1) or FALSE (0) - values. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -int8_t -\emph default - Is used everywhere byte-sized signed elements are explicitely required, - from -127 to +128, except for strings where the standard C -\emph on -char -\emph default - type should be used. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int8_t -\emph default - Should be used where unsigned byte-sized elements are required, for 0-255 - values. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -int16_t -\emph default - Is the data type used for 16-bit signed integers values, -32768 to +32767. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int16_t -\emph default - The unsigned 16-bit value data type which can old 0 to 65535. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -int32_t -\emph default - For use with 32-bit signed data types -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int32_t -\emph default - 32-bit unsigned data type -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -int64_t -\emph default - signed 64-bit data type (usually typedef with -\emph on -long long -\emph default -) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int64_t -\emph default - unsigned 64-bit data type. - It is to be noted that operations on 64-bit objects is generally slow as - it requires multiple instructions on 32-bit architectures. - Currently, no 64-bit data types are beign used anymore, the few ones which - used it were converted to use 32-bit ones instead. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -size_t -\emph default - Used to represent a size in bytes, this in fact is equivalent to -\emph on -u_int32_t -\emph default -. - -\emph on -size_t -\emph default - should not be used to represent arbitary types amounts, but byte amounts - only (corresponding to a number of -\emph on -char -\emph default -, -\emph on -u_int8_t -\emph default - or -\emph on -int8_t -\emph default - types). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -ssize_t -\emph default - Purpose is the same as for -\emph on -size_t -\emph default -, but this can hold -1 for error. -\layout Standard - -And other frequently used standard Xisop types, which are still defined - in < -\emph on -common/types.h -\emph default ->, but have their corresponding structures defined at their respective locations - (mentionned in parentheses): -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -node_t -\emph default - A doubly linked list node to be used in -\emph on -list_t -\emph default - type lists. - (common/kernlib/list.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -list_t -\emph default - A doubly linked list (common/kernlib/list.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -mchunk_t -\emph default - A chunk of contiguous memory pages, part of a -\emph on -ppool_t -\emph default - (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -page_t -\emph default - A physical memory page, or a number of contiguous physical memory pages, - holding the necessary information for freeing back. - (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -ppool_t -\emph default - A system pool of pages, that is, what other pools allocate pages from. - (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pool_t -\emph default - A efficient fixed sized objects ( -\emph on -pnode_t -\emph default -) memory pool with internal statistical page cacheing, which can optionally - dynamically grow and shrink, or be static in size (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pnode_t -\emph default - A pool object node, which must prefix any pool object. - This type internally begins with a -\emph on -node_t -\emph default - and can therefore be used directly for queuing in -\emph on -list_t -\emph default -. - (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -mpool_t -\emph default - A multiple -\emph on -pool_t -\emph default - memory pool used to serve multiple sized blocks requests. - Of various memory types. - Bocks which are too large are rounded at page boundaries. - (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -mnode_t -\emph default - Internally used by the -\emph on -mpool_t -\emph default - related allocation primitives (common/kernel/memory.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -facility_t -\emph default - A public interrupt facility which the port-specific code initializes calling - the common -\emph on -facility_init() -\emph default - function. - (common/kernel/exception.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hook_t -\emph default - An interrupt, trap or exception code vector attached to a -\emph on -facility_t -\emph default -. - (common/kernel/exception.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hookid_t -\emph default - An -\emph on -hook_t -\emph default - ID, internally a -\emph on -u_int32_t -\emph default -, which is guarranteed to be unique for the facility it belongs to. - (common/kernel/exception.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -task_t -\emph default - Task structure (common/kernel/task.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -priority_t -\emph default - A task priority number (common/kernel/task.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -signum_t -\emph default - Signal number (common/kernel/signal.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -sigmask_t -\emph default - Signal mask which can represent one or more -\emph on -signum_t -\emph default -. - (common/kernel/signal.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -port_t -\emph default - Message port (common/kernel/port.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -message_t -\emph default - A message header structure which comports the glue to queue messages in - -\emph on -port_t -\emph default - (common/kernel/port.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -device_t -\emph default - An open device handler (common/kernel/device.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -devicenode_t -\emph default - A linked device hook (common/kernel/device.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -iorequest_t -\emph default - An I/O request message type used for -\emph on -device_t -\emph default - requests (common/kernel/device.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -fifo8_t -\emph default - An 8-bit elements FIFO buffer. - -\emph on -fifo -\emph default -* -\emph on -_t -\emph default - types are implemented as a fixed bytes buffer once initialized, rather - than using linked lists. - It is possible to easily create new -\emph on -fifo -\emph default -* -\emph on -_t -\emph default - types of arbitrary object sizes using a macro. - (common/kernlib/fifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -fifo16_t -\emph default - A 16-bit elements FIFO buffer (common/kernlib/fifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -fifo32_t -\emph default - A 32-bit elements FIFO buffer (common/kernlib/fifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -lifo8_t -\emph default - A 8-bit elements LIFO buffer. - -\emph on -lifo -\emph default -* -\emph on -_t -\emph default - types operate like stacks, and are internally implemented as a fixed bytes - buffer once initialized, rather than using linked lists. - A macro is provided to easily create new types of -\emph on -lifo -\emph default -* -\emph on -_t -\emph default - for objects of arbitrary size. - (common/kernlib/lifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -lifo16_t -\emph default - A 16-bit elements LIFO buffer (common/kernlib/lifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -lifo32_t -\emph default - A 32-bit elements LIFO buffer (common/kernlib/lifo.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hashtable_t -\emph default - A hash lookup table (common/kernlib/hash.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hashnode_t -\emph default - A hash lookup table node (common/kernlib/hash.h> -\layout Standard - -And here are the processor and architecture specific opaque data types they - provide: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_ipl_t -\emph default - Abstract Interrupt Priority Level type, associated with the -\emph on -_spl -\emph default -n -\emph on -() -\emph default - and -\emph on -_splx() -\emph default - functions. - (processor/support.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_ctx_t -\emph default - Abstract processor-specific supplied context handle, associated to -\emph on -_ctx_init() -\emph default - function which is used by -\emph on -task_alloc() -\emph default - and internal kernel context switching. - (processor/support.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_lock_t -\emph default - Abstract processor-specific supplied atomic simple lock handle. - Associated to the -\emph on -_lock_ -\emph default -* -\emph on -() -\emph default - functions. - (processor/support.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_rlock_t -\emph default - An abstract atomic recursive lock handle (needs to be unlocked the same - number of times it was locked to free the -\emph on -_rlock_t -\emph default -). - Associated to the -\emph on -_rlock_ -\emph default -* -\emph on -() -\emph default - functions. - (processor/support.h) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -XXX -\emph default - The 64-bit related types are currently unused. - On most processors the GCC compiler requires additional libraries to support - these, which are currently not part of Xisop. - There however exist such implementations fully written in C, like the one - used on BSD systems which would not be hard to include if it was necessary. - An effort was made to also not include software which requires the use - of floating point, for code size and efficiency. -\layout Subsubsection - -Programming style and conventions -\layout Standard - -It is a fact that consistency is a must for readibility, especially in an - open source project which many others may need to modify to suit their - particular needs. - The following programming conventions are used, and are defined for assembly - and C code. -\layout Paragraph - -Function names -\layout Standard - -All functions which are not behaving identically to ANSI-C or POSIX or other - widely standarized ones, but have the same name should have their name - prefixed by an underscore ('_'). - Others which behave exactly like the standards should have the same name - the standard expects. - Other functions which have nothing in common with standard names should - not be prefixed by underscores, except for the defined processor and port-speci -fic functions, which names should also begin with an underscore. - Of course, if a hardware-specific function is provided as a replacement - to a common portable one for performance considerations, it obviously should - bear the same name, however. -\layout Paragraph - -Formatting -\layout Standard - -Line termination should consist of -\begin_inset Quotes eld -\end_inset - - -\backslash -n -\begin_inset Quotes erd -\end_inset - - (linefeed, as is used on Amiga and Unix), rather than -\begin_inset Quotes eld -\end_inset - - -\backslash -r -\backslash -n -\begin_inset Quotes erd -\end_inset - - which is used on MS-DOS and Windows for text file storage. - Other than tab ( -\begin_inset Quotes eld -\end_inset - - -\backslash -t -\begin_inset Quotes erd -\end_inset - -) and linefeed ( -\begin_inset Quotes eld -\end_inset - - -\backslash -n -\begin_inset Quotes erd -\end_inset - -), no other control characters should be found within the source files. - Moreover, every line of the source files should not exceed 79 characters. -\layout Paragraph - -C language sections -\layout Standard - -It is important that C files be using the standard eight (8) tab size for - real tabs. - However, the software tab should consist of four (4) characters. - Tabs should be used where 8 space tabs are needed, and spaces used to fill - the 4 character tabs. - When using the VIm editor, these should be used: -\emph on -ts=8 -\emph default -, -\emph on -sw=4 -\emph default -, and -\emph on -cindent -\emph default -. - This allows the files to be printable using text file viewers properly - at all times, and to also be printable as-is on most printers. - -\emph on -XXX -\emph default - Add settings for emacs -\layout Itemize - -C program suffix should consist of lower case -\emph on -.c -\layout Itemize - -C headerfiles should use the lower case suffix -\emph on -.h -\layout Itemize - -ANSI-C programming norms should be observed as much as possible. -\layout Itemize - -ANSI convention for function arguments specification rather than K&R. -\layout Itemize - -BSD programming style used rather than GNU style, especially for opening - and closing braces convention. - This corresponds to the formatting performed using GNU indent program with - the following parameters: -\emph on -gindent -kr -ncs .c -\layout Itemize - -Functions and global variables which are specific to the current module - should be declared -\emph on -static -\emph default -, and their prototypes should be in a private headerfile or in the current - C source file, not in a public headerfile which is included by any other - C source module. -\layout Itemize - -Macros and variables directly refering to hardware architecture-specific - registers should use the -\emph on -volatile -\emph default - keyword. -\layout Itemize - -Every function must have a corresponding prototype, defined either at the - top of the current C file (if static) or in a corresponding headerfile - (public ones). -\layout Itemize - -For kernel code, the conventions should be followed about the choice of - variable types to use (described in the previous section). -\layout Itemize - -No C++ or other language should be used within the kernel code. - Of course there is no such restriction for any user program. -\layout Itemize - -Code should obviously be commented as required for clarity, but -\emph on - -\begin_inset Quotes eld -\end_inset - -/* -\begin_inset Quotes erd -\end_inset - - -\emph default - and -\emph on - -\begin_inset Quotes eld -\end_inset - -*/ -\begin_inset Quotes erd -\end_inset - - -\emph default - C-style delimited comments only are allowed, not -\emph on - -\begin_inset Quotes eld -\end_inset - -// -\begin_inset Quotes erd -\end_inset - - -\emph default - C++ ones. -\layout Itemize - -Code should not invoke general purpose memory allocation routines when a - special fast access pool was provided already to allocate and free these - types of items. - Where appropriate, the general kernel objects pool system should be expanded - when a new object is frequently allocated and freed, rather than using - the general purpose management functions. - These obviously should be common, machine-independent objects (which can - possibly use machine-specific definitions, if they become standard and - documented in this document so all ports provide them). - See the memory management section later on for more information. -\layout Itemize - -General purpose libraries supplied in -\emph on -src/common/kernlib/ -\emph default - should normally have each function implemented as a separate C file into - the library's directory. - During the build process they will get compiled independently, and then - archived together using -\emph on -ar -\emph default -. - -\emph on -ranlib -\emph default - will then be executed on the archive. - This ensures that unused functions do not be included into the end kernel - result, reducing kernel size considerably when full multipurpose libraries - are used (such as complete string libraries). -\layout Paragraph - -Assembly sections -\layout Standard - -For assembly sections, the AT&T style should be observed, and the assembly - should not be embedded into the C code using inline assembly routines. - Often a library requireing both assembly and C will at build time assemble - it's assembly section file ( -\emph on -.s -\emph default -), compile it's C part ( -\emph on -.c -\emph default -), and link the two together into an object file ( -\emph on -.o -\emph default -) using the -\emph on --r -\emph default - linker switch, which then gets linked with the kernel. - In other situations one may want to instead compile all modules to objects - ( -\emph on -.o -\emph default -), create an -\emph on -ar -\emph default - archive ( -\emph on -.a -\emph default -), run -\emph on -ranlib -\emph default - on it, and link it to the kernel (in which case all unused functionality - which was isolated into it's own module does not get included by the linker, - reducing kernel size). - This applies to both processor-specific and architecture-specific backends. - The rest is written in C. - It is encouraged to write most of the architecture-specific boot loader - code in C and provide a companion assembly file to interface and call the - C loader main function. - This minimizes assembly code, and C is more consistant and readable, it - can be more suitable to sometimes write tricky sections like relocators, - etc. -\layout Standard - -The assembly sections should ensure to be reeintrant, that is, using the - stack to save registers rather than using temporary registers to save other - registers, and using the stack as well for temporary variables for which - registers cannot be used, rather than static memory locations. - These are usually indended to be called from C, and because of the way - Xisop shared libraries work, is a main reason to follow these directives. - An assembly section which is known to execute uninterruptably may at it's - discretion use static memory if needed. -\layout Itemize - -Assembly files should have the following lowercase suffix: -\emph on -.s -\layout Itemize - -Tabulation should be set to use real tabs (not spaces), with a standard - tab width of 8. -\layout Itemize - -Assembler opcodes should be located after the first tab. -\layout Itemize - -Operands should be located after the second tabulation. -\layout Itemize - -Where more than an operand is required and are separated by a comma, a space - is required after the comma. -\layout Itemize - -Opcode names should be lowercase, and must match those shown by objdump - when dissassembling. - This allows consistancy between all code for a particular processor. - Although this may sound tidious at first, it is not as hard as it sounds - to learn the specific mnemonic names objdump displays, with some little - practice. - Adventages results in consistency, where it also becomes possible to locate - specific instructions in the code with regular expressions, etc. -\layout Itemize - - -\emph on -.equ -\emph default - and -\emph on -= -\emph default - directives, if any, should be located at the top of the assembly file. -\layout Itemize - - -\emph on -.globl -\emph default - directives to declare public functions should also be located at the top - of the file. -\layout Itemize - -All code should be within the -\emph on -.text -\emph default - section, along with any static memory variables if need be (although use - of these is discouraged, except for instance in the kernel loader bootblock - where they can be useful, or in special context code where one knows what - he's doing rather than only using the stack). -\layout Itemize - -A comment on a line or two should be placed before each function, especially - the ones which are intended to be called from C, along with the C prototype. -\layout Itemize - -Other comments should be found along the code where required for obviousness. -\layout Itemize - -Obviously, registers which a function modifies should be saved in the stack, - and restored upon function return, except (if any) the register corresponding - to the return code expected in C for that processor. -\layout Itemize - -Interrupt, trap and exception assembly sections should normally save all - registers which are commonly used for the particular processor, and restore - them before returning. - It is wrong to assume that C compiled functions always save all registers - they modify other than the expected result register. - This was learned from experience using GCC. -\layout Subsection - -Xisop scheduler and inter-task communication -\layout Subsubsection - -The multitasking scheduler -\layout Standard - -The scheduler currently allows to set priorities for each task, between - -128 and 127. - It is preemptive and will make sure to allow other tasks to run even when - a particular task hugs the CPU by not going to sleep. - A task can be in two main states: running, and sleeping. -\layout Standard - -When a task sleeps, it has a mask of signals that will awake it as soon - as possible if it receives any signal it waits for, and leaves more opportuniti -es for other tasks to execute their shores when it is sleeping. - When a task runs, it usually executes it's shores and goes back to sleep - for the next event to process, when running in a multitasking system. - However, if it does not return to sleep fast enough, the scheduler preemtive - nature will suspend it and allow other tasks to also get a fair CPU time - share, depending on the priority of the running tasks, unless the task - has disabled scheduling, in which case it will remain running until it - decides to delegate control to the system again. -\layout Standard - -The task priority controls the speed and frequency at which a running task - awakes, or runs. - What the scheduler does is assign a set of credits to all tasks in the - run queue, according to their priority one another. - Then using round-robin at each scheduler round, the task with the highest - amount of credits is given some CPU time, and a credit is taken out from - it. - If a task expired it's credits, it is no longer given a round, until all - other tasks also expired their credits. - When this happens, all tasks are given credits according to their priority - again. - Some care is taken to not constantly give a turn to the last task even - if it has more credits, to allow to make the best out of Xisop asynchroneous - facilities, but such a high priority task will have more turns within the - run still, observing it's relative priority to the others. -\layout Standard - -When a task goes to sleep, it is immediately taken out of the run queue - and will not be awaken until a signal it awaits for is received. - When it does, it will be moved in the running queue as fast as possible, - at which point the time elapsing before it can act to the signal is directly - dependent on the priority of the task related to the other ready to run - tasks. - However, when the task is moved in the run queue, it is immediately given - it's credits at the maximum it's priority permits, thus increasing the - chances it can answer in a fast manner among the other tasks in the run - queue, which may already have been there before, and elapsed their credits. -\layout Standard - -This means that if all tasks run with the default priority of 0, they all - get a fair share of the CPU, and are naturally awaking very fast when one - get a signal. - In the case where one of the tasks remains running, the speed of signal - responsiveness will ususally consist of the frequency of the scheduler. - This frequency is usually configurable, and depends on the capacity of - the timers available for the particular architecture (and of course on - CPU speed). -\layout Standard - -In the case where the scheduler detects that all tasks are sleeping, it - attempts to reduce it's CPU usage by calling the -\emph on -_idle() -\emph default - processor-specific function, which will only awaken the scheduler again - when the next interrupt, trap or exception occurs. - It is possible in Xisop to have dead locked tasks, if they decide to wait - for no signals, or if they wait for a signal to occur which never does. -\layout Standard - -Following are described all functions which are related to tasks and scheduler, - or which are useful to synchronize resources, other than the -\emph on -signal_t -\emph default - and -\emph on -port_t -\emph default - based systems, which are described in a further section. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -task_t\SpecialChar ~ -*task_alloc(int\SpecialChar ~ -(*start)(void\SpecialChar ~ -*,\SpecialChar ~ -void\SpecialChar ~ -*), void\SpecialChar ~ -*res,\SpecialChar ~ -void\SpecialChar ~ -*args,\SpecialChar ~ -priority_t\SpecialChar ~ -priorit -y,\SpecialChar ~ -size_t\SpecialChar ~ -stacksize,\SpecialChar ~ -u_int8_t\SpecialChar ~ -flags) -\emph default - Allocates a task which can then be started or freed back. - -\emph on -start -\emph default - specifies the entry point function, -\emph on -res -\emph default - an optional pointer to a buffer for results which the task may need to - use or NULL, and -\emph on -args -\emph default - an optional pointer to a buffer which may be used by the task to obtain - it's argument, or NULL. - When -\emph on -start -\emph default - is called, -\emph on -res -\emph default - is passed as the first argument and -\emph on -args -\emph default - as the second one. - -\emph on -priority -\emph default - consists of the task initial running priority which may be in the range - of -128 to 127, 0 being the normal running priority. - -\emph on -stacksize -\emph default - specifies the size of the stack in bytes which should be dedicated to the - task, a common size being 4096 bytes. - -\emph on -flags -\emph default - may be 0, or ORed -\emph on -TS_ -\emph default -* flags which are defined in < -\emph on -src/common/kernel/task.h -\emph default ->. - The task is not yet launched by Xisop. - If the -\emph on -TS_SHARED -\emph default - flag is supplied, this task will use the -\emph on -mpool_t -\emph default - of it's parent (the current task which allocates it). - This means that all memory allocated by one of the tasks sharing a memory - pool is inherently shared. - One task ending will not cause the allocated regions to be freed unless - explicitely freed. - When all tasks shareing a memory pool exit, all allocated memory by any - of them is automatically freed back. - This feature can be used when memory should inherently be shared among - the tasks, or when memory resources are very scarce. - However, unlike using Xisop messages which provide synchronization to share - arbitrary memory regions among tasks, implicit synchronization should be - used by the tasks when accessing the same shared memory locations which - they should access concurrently. - For this, -\emph on -rwlock_t -\emph default - and -\emph on -_lock_t -\emph default - based systems can be used, or a custom system based around Xisop signals - and/or messages. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -task_t\SpecialChar ~ -*task_free(task_t\SpecialChar ~ -*task) -\emph default - Allows to free -\emph on -task -\emph default - which was previously allocated by -\emph on -task_alloc() -\emph default -. - Only tasks which have been allocated but which have not been launched may - be freed using this function, or it internally does nothing. - NULL is returned. - The kernel automatically frees tasks which have been launched when they - exit. - When a task is freed, all the resources it allocated using standard Xisop - functions are automatically freed back to the system as well. - The exception is when the task was setup with the -\emph on -TS_SHARED -\emph default - flag, where the memory is only freed when all tasks sharing that memory - pool ended. - This does not affect message ports, signals, devices, libraries or handlers, - however, which are released by each task, always, as they exit. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -task_start(task_t\SpecialChar ~ -*task) -\emph default - Launches -\emph on -task -\emph default - which should have previously been allocated using -\emph on -task_alloc() -\emph default -. - The task is moved to the ready queue and will start executing as soon as - the current task yields calling -\emph on -_yield() -\emph default - or is preempted by the scheduler. - The delay for it to actually execute also depends on the relative priority - of the tasks on the ready queue and their current credits. - If synchronization is needed with it's startup, signals or messages can - be used. - TRUE is returned on success, or FALSE if the task is invalid, or was already - launched. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -task_end(task_t\SpecialChar ~ -*task) -\emph default - Immediately forces termination of the specified -\emph on -task -\emph default -, which may consist of the current task, or of another task. - The task is cleanly freed as if it exited itself. - Can also be used on a task which is locked on the waiting queue, perhaps - waiting for events it will never receive. - When a task ends and needs to be freed, it is moved in a queue for a dedicated - task called the reaper, which chores consist of freeing all resources related - to each task and the tasks themselves on it's own scheduler CPU time slices. - Other tasks and the kernel are then releaved from that work. - When a task ends it will soon automatically be freed by Xisop, and the - resources it allocated are automatically freed as well. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_yield(task_t\SpecialChar ~ -*task) -\emph default - Permits a currently running task to immediately yield control back to the - scheduler to allow other tasks to have an immediate opportunity to execute, - rather than leaving the preemtive scheduler interrupt it. - The task is not moved to the wait queue, and will have an opportunity to - resume again very soon. - -\emph on -task -\emph default - consists of a suggestion to which task to delegate control to, which should - also currently be in the ready queue. - When -\emph on -task -\emph default - is invalid or NULL, the scheduler is left to decide which task to execute - next. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -task_sleep(task_t\SpecialChar ~ -*task,\SpecialChar ~ -u_int32_t\SpecialChar ~ -flags,\SpecialChar ~ -task_t\SpecialChar ~ -*yield) -\emph default - Allows to immediately switch the specified task (which may also be the - currently running task) to the waiting queue. - The task will be unable to execute again until it is specifically moved - back again on the ready queue by calling -\emph on -task_wakeup() -\emph default - on it with at least one of the same bits in -\emph on -flags -\emph default -. - This can be useful when custom interrupt attached code hooks need to synchroniz -e tasks and such and that signals and message ports are not desired. - If the task being put to sleep consists of the current task, -\emph on -yield -\emph default - can specify another optional ready task to run immediately, if non-NULL. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -task_wakeup(task_t\SpecialChar ~ -*task,\SpecialChar ~ -u_int32_t\SpecialChar ~ -flags) -\emph default - Immediately awakes the specified task if it currently is sleeping in the - waiting queue. - This is normally used after a -\emph on -task_sleep() -\emph default - call was made on the task. - However, it is possible to use this function to wake a task which is waiting - for a signal as well if -\emph on -TSF_SIGNAL -\emph default - flag is specified. - This is normally used by custom interrupt hooks which need to synchronize - tasks, when they cannot use signals or message ports. - They then can share a -\emph on -fifo_t -\emph default - buffer, or custom -\emph on -list_t -\emph default - queue, with the wanted tasks and cause them to awake and sleep at will - for instance. - The task is only awaken if at least one bit supplied in -\emph on -flags -\emph default - matches one of the bits of the -\emph on -flags -\emph default - which were used at -\emph on -task_sleep() -\emph default -. - TRUE is returned if the task could be awaken, or FALSE if the flags do - not permit to awake it or another problem occurs. -\layout Standard - -The current sleeping flags are described as follows (as defined in < -\emph on -src/common/kernel/scheduler.h -\emph default ->) : -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -TSF_KERNEL -\emph default - Kernel-reserved, used by the task reaper for instance. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -TSF_SIGNAL -\emph default - Task is waiting for the reception of at least of one of the signal bits - in -\emph on -task_t->sigwait -\emph default -. - Internally used bu the signal subsystem. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -TSF_CUSTOM -\emph default - As the name implies, may be used by user tasks. -\layout Standard - -Here are then described the scheduler control functions: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -priority_t\SpecialChar ~ -task_getpriority(task_t\SpecialChar ~ -*task) -\emph default - Obtains the current running priority level of -\emph on -task -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -priority_t\SpecialChar ~ -task_setpriority(task_t\SpecialChar ~ -*task,\SpecialChar ~ -priority_t\SpecialChar ~ -p) -\emph default - Permits to change the running priority of -\emph on -task -\emph default - to -\emph on -p -\emph default -. - Returned is the previous priority of -\emph on -task -\emph default - which could be used to restore it. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sched_disable(void) -\emph default - Allows to disable the preemptive scheduler, which will only be re-enabled - when a corresponding number of -\emph on -sched_enable() -\emph default - have been called, as the scheduler lock consists of a recursive -\emph on -_rlock_t -\emph default -. - It is important to not call -\emph on -yield() -\emph default -, -\emph on -port_wait(), port_send(), signal_send() -\emph default - or -\emph on -signal_wait() -\emph default - when the scheduler is disabled, because it would prevent the task from - ever being awaken again. - Obviously, this call should be used with care, if any. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sched_enable(void) -\emph default - Re-enables the scheduler if the same number of instances of this function - matched with the previous -\emph on -sched_disable() -\emph default - calls. -\layout Subsubsection - -Locks and synchronization primitives -\layout Standard - -Other synchronization systems such as signals and message ports are later - described in a next section. - However, these are also very useful synchronization primitives which Xisop - provides to both kernelspace and userspace software: -\layout Paragraph - -Exclusive access locks -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_init(_lock_t\SpecialChar ~ -*lock) -\emph default - Initializes an exclusive access a lock. - This has to be used before using other functions -\emph on -lock -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_acquire(_lock_t\SpecialChar ~ -*lock) -\emph default - This function is not multitasking-friendly in that the current task loops - in an endless loop until exclusive obtention of the -\emph on -_lock_t -\emph default - is acquired. - Tasks should normally use -\emph on -lock_acquire() -\emph default - instead. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_release(_lock_t\SpecialChar ~ -*lock) -\emph default - Immediately releases the exclusive -\emph on -_lock_t -\emph default - -\emph on -lock -\emph default - to allow another locker to obtain it. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_lock_try(_lock_t\SpecialChar ~ -*lock) -\emph default - Attempts to exclusively acquire -\emph on -lock -\emph default -, but returns immediately with FALSE if it cannot. - TRUE is returned on success. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_lock_available(_lock_t\SpecialChar ~ -*lock) -\emph default - Returns TRUE if there currently are no locker on -\emph on -lock -\emph default -, but does not attempt to lock it. - It is unsafe to attempt to implement -\emph on -_lock_try() -\emph default - using this function, obviously. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -lock_acquire(_lock_t\SpecialChar ~ -*lock) -\emph default - Similarily to -\emph on -_lock_acquire() -\emph default -, locks execution of the current task until -\emph on -lock -\emph default - is exclusively obtained. - This function is however better according to multitasking as it immediately - yields CPU time to allow the current locker to free it as soon as possible - for the current task to own it. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -lock_release(_lock_t\SpecialChar ~ -*lock) -\emph default - Identical to -\emph on -_lock_release() -\emph default -, made to match -\emph on -lock_acquire() -\emph default - for consistency. -\layout Paragraph - -Recursive locks -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_init(_rlock_t\SpecialChar ~ -*lock) -\emph default - Initializes a recursive lock of type -\emph on -_rlock_t -\emph default -. - This needs to be performed before calling other recursive lock operations - on -\emph on -lock -\emph default -. - Recursive locks are different from exclusive locks in that there can be - any number of concurrent lockers at the same time. - They are usually used for systems which execute at intervals, like the - Xisop scheduler and interrupt facilities which also make use of this system. - They can then make sure to be the only locker before performing their critical - work. - This way arbitrary tasks may disable the facilities safely by locking the - lock, and unlocking it when they are done with their critical section. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_acquire(_rlock_t\SpecialChar ~ -*lock) -\emph default - Locks recusively the -\emph on -lock -\emph default - -\emph on -_rlock_t -\emph default -. - This basically atomically increases the lockers counter of the lock, and - never fails. - It always returns immediately. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_release(_rlock_t\SpecialChar ~ -*lock) -\emph default - Releases the -\emph on -lock -\emph default - -\emph on -_rlock_t -\emph default -. - Note that the same number of release operations must be performed on -\emph on -lock -\emph default - for it to become available again. - This only atomically decreases the lockers counter of the lock, and returns - immediately. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_rlock_trylock(_rlock_t\SpecialChar ~ -*lock) -\emph default - If the lock is free/available, that is, no current lockers exist on -\emph on -lock -\emph default -, this function atomically locks it and returns TRUE immediately. - Otherwise it returns FALSE and returns immediately, in which case the lock - is left in it's original state before the call. - This can be very useful for an event-driven system which needs to make - sure that the lock is free to perform it's tasks, but also needs to prevent - it's own recursion. - Obviously, if it returned TRUE, -\emph on -_rlock_release() -\emph default - is expected to be called when done. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_rlock_available(_rlock_t\SpecialChar ~ -*lock) -\emph default - Returns FALSE if there are any lockers on -\emph on -lock -\emph default -, or TRUE if the lock is currently free from any lockers. - This however only performs the check, and does not change the lock state. - It is unsafe to use this function along with -\emph on -_rlock_acquire() -\emph default - to implement a -\emph on -_rlock_trylock() -\emph default - replacement as it would not be atomic. -\layout Paragraph - -Read/Write locks -\layout Standard - -These locks internally consist of a combination of exclusive and recursive - locks. - They are ideal for instance to protect synchronization of resources where - multiple readers are allowed but that exclusive access is required for - write operations. - There currently is provided no way to upgrade a currently held shared access - lock to an exclusive lock, or to downgrade an exclusively held lock to - a shared access lock, other than releasing the lock and re-locking it. - However, if this proves necessary in the future, we shall implement these - features. - These locks are especially adequate to protect resources which are frequently - accessed in read-only mode, but which occasionally need to be updated, - which obviously requires write/exclusive access, which is the case with - several Xisop system lists, and these locks are then used by the involved - kernel functions as well. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -rwlock_init(rwlock_t\SpecialChar ~ -*lock) -\emph default - Initializes -\emph on -lock -\emph default -, which is necessary before using any other -\emph on -rwlock_ -\emph default -* -\emph on -() -\emph default - function on it. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -rwlock_acquire(rwlock_t\SpecialChar ~ -*lock,\SpecialChar ~ -bool\SpecialChar ~ -exclusive) -\emph default - Locks the current task until the -\emph on -lock -\emph default - -\emph on -rwlock_t -\emph default - can be exclusively accessed (for read and/or writing access) if -\emph on -exclusive -\emph default - is TRUE, or until a shared recursive access is obtained (for read-only - access) if -\emph on -exclusive -\emph default - is FALSE. - Is multitasking-safe. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -rwlock_release(rwlock_t\SpecialChar ~ -*lock) -\emph default - Releases the access on -\emph on -lock -\emph default - which was obtained using -\emph on -rwlock_acquire() -\emph default - or -\emph on -rwlock_try() -\emph default -. - Whether this access was exclusive or shared is internally remembered. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -rwlock_try(rwlock_t\SpecialChar ~ -*lock,\SpecialChar ~ -bool\SpecialChar ~ -exclusive) -\emph default - Very similar to -\emph on -rwlock_acquire() -\emph default - but always immediately returns with FALSE if the access cannot be obtained - immediately. - TRUE is returned with the lock held on success. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -rwlock_upgrade(rwlock_t\SpecialChar ~ -*lock) -\emph default - Permits to upgrade an already obtained shared lock to an exclusive lock. - The current task may sleep as required until all shared lockers free their - lock. - The caller -\emph on -MUST -\emph default - already be holding the lock in shared mode. - This function is most useful for operations such as check-and-modify, when - read-only access is generally required to a resource, but that under certain - conditions write access is needed to modify the resource after the check. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -rwlock_downgrade(rwlock_t\SpecialChar ~ -*lock) -\emph default - Conversely to -\emph on -rwlock_upgrade() -\emph default -, allows to downgrade an already obtained exclusive lock to a shared lock. - The caller -\emph on -MUST -\emph default - already be holding this lock in exclusive mode. - The usefulness of this function is questionable. - Although provided, the kernel does not use it. -\layout Paragraph - -System lists access -\layout Standard - -Several system lists require internal -\emph on -rwlock_t -\emph default - for synchronization against corruption. - In < -\emph on -common/kernel/main.h -\emph default -> are defined several macros which can be used to access those securely - by kernel functions. - The -\emph on -enum systables -\emph default - specifies various system lists which can be accessed using these methods, - called -\emph on -SYSTABLE_ -\emph default -*. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -SYSTABLE_RLOCK(enum\SpecialChar ~ -systables\SpecialChar ~ -table) -\emph default - Locks the -\emph on -rwlock_t -\emph default - of the specified -\emph on -table -\emph default -, in shared mode (read-only access). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -SYSTABLE_WLOCK(enum\SpecialChar ~ -systables\SpecialChar ~ -table) -\emph default - Locks the -\emph on -rwlock_t -\emph default - of the specified -\emph on -table -\emph default -, in exclusive mode (read/write access). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -SYSTABLE_UNLOCK(enum\SpecialChar ~ -systables\SpecialChar ~ -table) -\emph default - Unlocks the -\emph on -rwlock_t -\emph default - of the specified -\emph on -table -\emph default -, which should have previously been locked using -\emph on -SYSTABLE_RLOCK() -\emph default - or -\emph on -SYSTABLE_WLOCK() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -SYSTABLE_UPGRADE(enum\SpecialChar ~ -systables\SpecialChar ~ -table) -\emph default - Allows a caller which -\emph on -MUST -\emph default - hold a shared read-only access lock (after using -\emph on -SYSTABLE_RLOCK() -\emph default -) to upgrade the lock to exclusive mode. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hashtable_t\SpecialChar ~ -*SYSTABLE(enum\SpecialChar ~ -systables\SpecialChar ~ -table) -\emph default - Returns the -\emph on -hashtable_t -\emph default - pointer associated with the system list -\emph on -table -\emph default -. - Obviously, this should only be used when the lock is held, and should only - be used for the access corresponding to the currently obtained lock type. -\layout Standard - -The following two functions, as opposed to macros, are implemented as C - functions and perform boundary checking on the arguments, as they are provided - for user tasks rather than for the kernel, for which the previous macros - were designed: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hashtable_t\SpecialChar ~ -*systable_lock(u_int32_t\SpecialChar ~ -systable,\SpecialChar ~ -bool\SpecialChar ~ -exclusive) -\emph default - Attempts to lock access to the system list -\emph on -systable -\emph default -, in exclusive or shared mode. - A pointer to the -\emph on -hashtable_t -\emph default - is returned on success, or NULL otherwise. - As usual, shared locks should be obtained when read-only access is performed - on a list, but an exclusive lock is required if there is any need to modify - a system list. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -systable_unlock(u_int32_t\SpecialChar ~ -systable) -\emph default - Unlocks a previously held lock for -\emph on -systable -\emph default -, which should have previously been obtained using -\emph on -systable_lock() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -systable_upgrade(u_int32_t\SpecialChar ~ -systable) -\emph default - Upgrades a previously held lock for systable in shared mode to exclusive - mode. - The lock -\emph on -MUST -\emph default - previously be obtained in shared mode. -\layout Subsubsection - -Signals -\layout Standard - -Very few signals are reserved by the system, SIGTERM and SIGPOLL, respectively. - As Xisop currently supports 32 different signals per task, this results - in 30 user signals the applications programmer may play with. - Signals are internally implemented as bits, and are not reliably queued, - which means that although a task will always know that a particular signal - was received, it cannot know if it occured more than once before it had - the chance to process it. - It ressembles alot to a hardware bus line, which can be activated by the - other end, although our capacity to monitor a single signal state is dependent - on the rate at which we run. -\layout Standard - -Note that sending a SIGTERM signal to a task does not force it to exit. - It merely consists of a request to exit to the task, and the task may ignore - it or respect it. -\layout Standard - - -\emph on -XXX 32 is no longer a fixed value now that signum_t and sigmask_t are abstracted - and could be set by the port-specific code. -\layout Standard - -Message ports are used when the need for reliable event queuing is met. - The signals merely allow a task to sleep and be awaken on specified events, - like a message arriving on a port, which internally uses a signal bit. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -signum_t\SpecialChar ~ -signal_alloc(void) -\emph default - Attempts to allocate an available signal bit from the current task. - Returns the signal number allocated, or -1 if no more signals available. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -signal_free(sigmask_t\SpecialChar ~ -sigmask) -\emph default - Frees all specified signals in -\emph on -sigmask -\emph default -, which should previously have been obtained using -\emph on -signal_alloc() -\emph default -. - If reserved signals are part of the supplied -\emph on -sigmask -\emph default -, those are ignored. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -sigmask_t\SpecialChar ~ -signal_wait(sigmask_t\SpecialChar ~ -sigmask,\SpecialChar ~ -task_t\SpecialChar ~ -*task) -\emph default - Suspends the current task until at least one of the supplied signals in - -\emph on -sigmask -\emph default -, or a system reserved signal occurs. - Returned is the mask of signals we received which caused an awakening. - Multitasking-friendly applications usually spend most of their time suspended - by this call, and are awakening to perform their operations asynchroneously, - and go back to sleep as soon as possible, to allow other tasks to also - respond and execute efficienty. - However, because of the nature of the preemptive scheduler, a task which - remains in running state will not prevent others from executing. - -\emph on -task -\emph default -, which may be NULL, optionally specifies which task should be favored as - a suggestion to the scheduler, which allows to implement cooperative tasks - more efficiently. - The current task is guaranteed to awake at the occurance of the specified - signals, but will not be able to determine how many occurances of each - signal occurred as no queueing is performed. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -signal_send(task_t\SpecialChar ~ -*task,\SpecialChar ~ -sigmask_t\SpecialChar ~ -sigmask) -\emph default - Atomically sends the supplied signals in -\emph on -sigmask -\emph default - to the specified -\emph on -task -\emph default -. - The task, if suspended waiting for signals, is awaken if a signal it waits - for is included in -\emph on -sigmask -\emph default -, and will have a chance to run. - The delay elapsing between -\emph on -signal_send() -\emph default - and the task being able to process the signal depends on three factors: -\begin_deeper -\layout Itemize - -The speed at which the current task returns to sleep (using -\emph on -yield() -\emph default -, -\emph on -port_wait() -\emph default - or -\emph on -signal_wait() -\emph default -). -\layout Itemize - -If it does not return to sleep, the current task will continue running until - it is preempted by the scheduler, which is dependent on the scheduler timer - interrupt frequency. -\layout Itemize - -The priority of the tasks in the ready queue, that is, which are currently - awake. - This factor takes place after the other end was awaken, and before it gets - an opportunity to actually execute. -\end_deeper -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -sigmask_t\SpecialChar ~ -SIGMASK(signum_t\SpecialChar ~ -signum) -\emph default - Consists of a useful macro to convert a signal number ( -\emph on -signum_t -\emph default -) to a signal mask ( -\emph on -sigmask_t -\emph default -). - Those may then be ORed together (using C '|' bitwise operator character) - to represent multiple signals. -\layout Subsubsection - -Message ports -\layout Standard - -In the UNIX world, this is called Inter Process Communication (IPC). - In the case of Xisop, we communicate between light-weight tasks, rather - than between full fledged processes, using signals, datagram messages and - connectionless, unidirectional ports. - The Xisop port functions internally operate using signal primitives and - message queues (in FIFO order). - These are safe to call from userspace as well as kernelspace tasks. - However, it is not safe to transfer messages among ports in an interrupt - handler context without using -\emph on -_splhigh() -\emph default - for synchronization. - -\emph on -XXX -\layout Standard - -A Xisop message consists of an arbitrary sized object prefixed with a -\emph on -message_t -\emph default - structure, which is internally used for message queueing and replying informati -on. - Because the message is internally -\begin_inset Quotes eld -\end_inset - -moved -\begin_inset Quotes erd -\end_inset - - by only swapping pointers efficiently, memory copy operations are minimized. - However, this also means that the original creator of the message, as well - as the other end to which the message is passed, are responsible to synchronize - operations properly among eachother on the message memory area (more informatio -n on this below). - The -\emph on -message_t -\emph default - header starts with a -\emph on -pnode_t -\emph default - internally, which means that the user can use -\emph on -pool_t -\emph default - primitives to efficiently and arbitrarily create and destroy messages. - It also means that at their discretion the ends are able to internally - queue the message in custom -\emph on -list_t -\emph default - lists when necessary (after -\emph on -port_get() -\emph default -, and taking care to unlink it before -\emph on -port_send() -\emph default -/ -\emph on -port_reply() -\emph default -, obviously). -\layout Standard - -Some care was made when implementing Xisop message ports to take in consideratio -n tasks and or ports which may be destroyed before a message is replied - back by the other end, or for cases where a public port address, after - being obtained once, becomes invalid as the public service dies. - Instead of implementing a higher overhead or less versatile unique port - ID allocation, validation and lookup system, or using expensive string - operations with a -\emph on -hashtable_t -\emph default - using -\emph on -hashtable_lookup() -\emph default - for every message send, the following techniques were implemented: -\layout Itemize - -A special magic cookie is set on a valid, existing port. - This means that when attempting to perform any operation on a -\emph on -port_t -\emph default - pointer which does not resolve to an actual, currently valid port, operation - is refused to take place. - When a message port is destroyed, that magic number is reset to zero, which - renders it unusable. -\layout Itemize - -Because an efficient -\emph on -pool_t -\emph default - is used to allocate and free back -\emph on -port_t -\emph default - objects, it would be possible for an intended reply port to be destroyed, - and for another port, belonging to any task, to be created at the same - address. - To solve this issue, each port also comports an internal unique ID. - When a message is sent to a port, from which a reply is expected, the -\emph on -message_t -\emph default - is made to remember both the reply -\emph on -port_t -\emph default - address and unique ID. - When attempting to reply, the -\emph on -port_t -\emph default - validity is performed as usual via the magic number, and the unique ID - is then evaluated for a match. - This way, a reply message will never be queued back on an unexpected port, - or to a nonexisting one which may just have died. -\layout Itemize - -The unique ID supplied to a port only consists of an unsigned 32-bit integer, - which is obtained from a global shared counter, which is incremented and - used whenever required. - This means that the odds of another -\emph on -port_t -\emph default - using the same address and ID within the delay of a send/reply are probably - always none. -\layout Itemize - -Using this method prevented restrictions on the maximum number of ports - and tasks which can exist in Xisop. - The overhead is also smaller than having to run through an array looking - for an empty slot, and having to re-allocate the memory area to dynamically - grow or shrink it, because without MMU support alot of memory copying would - be required for those operations. - Using a -\emph on -pool_t -\emph default - then is ideal for speed. - Using a relatively fast lookup hash table would require a lookup to be - performed before every message send, which was considered suboptimal when - designing Xisop. - Although -\emph on -port_find() -\emph default - uses this, it would have been absurd to need to perform this lookup before - sending any message. - Especially considering that locking must be used when accessing the system - hash table for synchronization. -\layout Standard - -Usually, the tasks should be written to be reliable and to synchronize well - within eachother. - However, with these precautions, supported by well written applications, - the -\emph on -port_t -\emph default - system is always very reliable and predictable. - Here are described the functions: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -port_t\SpecialChar ~ -*port_create(const\SpecialChar ~ -char\SpecialChar ~ -*name) -\emph default - Allows to create a message port on the current task. - This internally also needs to allocate a signal bit using -\emph on -signal_alloc() -\emph default -, which is associated to the -\emph on -port_t -\emph default - for the -\emph on -port_wait() -\emph default - internals. - NULL is returned on failure, or a pointer to the new -\emph on -port_t -\emph default - on success. - -\emph on -name -\emph default - is optional and should be NULL if the port does not need to be advertized - to the whole system. - If other tasks need to find our port by name, then -\emph on -name -\emph default - will be usable with -\emph on -port_find() -\emph default - to locate it, and listing the system public ports would advertize it as - well. - Ports are generally private, except for special public services. - The length of -\emph on -name -\emph default - will be truncated to 32 characters if it is longer. - If a public port is created, but that another public port bears the same - name alerady, the operation fails. - The port name is case-sensitive. - If the task exists without closing it's ports, they are automatically destroyed - by the kernel. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -port_t\SpecialChar ~ -*port_destroy(port_t\SpecialChar ~ -*port) -\emph default - Destroys a message port of the current process, which was created using - -\emph on -port_create() -\emph default -. - The internally allocated signal bit and memory are released back to the - system. - If any queued messages exist, the queue is lost, but the -\emph on -message_t -\emph default - objects are untouched, as they remain the responsibility of the application - who created them. - NULL is returned. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -port_t\SpecialChar ~ -*port_find(const\SpecialChar ~ -char\SpecialChar ~ -*name) -\emph default - Allows to locate a public message port by name. - If the port can be found, it's address is returned. - NULL is returned otherwise. - Because this needs to lookup through a system's public ports hash table - it needs to lock it internally using a -\emph on -rwlock_t -\emph default - in shared access mode. - The port name is case-sensitive. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -port_send(port_t\SpecialChar ~ -*port,\SpecialChar ~ -port_t\SpecialChar ~ -*replyport,\SpecialChar ~ -message_t\SpecialChar ~ -*message) -\emph default - Queues the supplied -\emph on -message_t -\emph default - to the specified -\emph on -port_t -\emph default - in FIFO order, and internally -\emph on -send_signal() -\emph default - the associated process with the internal port signal. - This means that the other process could be sleeping using -\emph on -signal_wait() -\emph default - or -\emph on -port_wait() -\emph default - and will be awakened so that it may process the message. - The supplied message then becomes owned by the other end, and should be - left alone by the current task until a reply be obtained from the other - side on the -\emph on -message_t -\emph default -'s -\emph on -replyport -\emph default -. - This -\emph on -port_send() -\emph default - and -\emph on -port_reply() -\emph default - mechanism serves for synchronization. - This means that normally, -\emph on -replyport -\emph default - is supplied the address of a local -\emph on -port_t -\emph default - used to receive results from the task we send messages to via it's own - -\emph on -port_t -\emph default -. - TRUE is returned on success, or FALSE if the message could not be delivered - (in which case the supplied -\emph on -port_t -\emph default - address is probably invalid and a -\emph on -port_find() -\emph default - operation can be used again to attempt to locate the port, if it consists - of a public port which should exist). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -message_t\SpecialChar ~ -*port_get(port_t\SpecialChar ~ -*port) -\emph default - If at least one message is available in the specified -\emph on -port_t -\emph default -, the first one is unqueued from it in FIFO order and the address to it - is returned. - Otherwise, NULL is returned. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -port_reply(message_t\SpecialChar ~ -*msg) -\emph default - Sends back the supplied -\emph on -message_t -\emph default - to the reply -\emph on -port_t -\emph default - of the task that previously sent it to us. - This port corresponds to the -\emph on -replyport -\emph default - argument that was used at -\emph on -port_send() -\emph default -. - Normally, the other end waits until we are done with the message, and we - use this function to notify that it can safely continue to do whatever - it wants with the -\emph on -message_t -\emph default - data. - TRUE is returned on success, or FALSE if no -\emph on -replyport -\emph default - was set for the -\emph on -message_t -\emph default -, or that the reply port is no longer valid. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -port_t\SpecialChar ~ -*port_wait(port_t\SpecialChar ~ -**ports,\SpecialChar ~ -u_int32_t\SpecialChar ~ -num,\SpecialChar ~ -task_t\SpecialChar ~ -*task) -\emph default - Suspends the current task until a message is received through one of the - supplied port(s) specified in the array of -\emph on -port_t -\emph default - pointers -\emph on -ports -\emph default -. - -\emph on -num -\emph default - specifies the number of -\emph on -port_t -\emph default - pointers supplied in the ports array. - -\emph on -task -\emph default - specifies a suggestion preference of which task to switch to, or NULL to - let the scheduler choose. - Returned is the pointer to the -\emph on -port_t -\emph default - which received the message, or NULL if a reserved signal was the awakening - cause. - If one of the ports already has queued messages the task will not be set - to sleep and the aforementionned port will be returned immediately. - If it is necessary to monitor other signals as well as port message arrivals, - it is advised to manually assemble the -\emph on -sigmask_t -\emph default - from all monitored signals, including the ones associated to the monitored - ports, and to use -\emph on -signal_wait() -\emph default - instead. - Evaluating the resulting -\emph on -sigmask_t -\emph default - will permit to know which ports received messages, if any. - Use of the -\emph on -PORT_SIGMASK() -\emph default - macro will then be useful. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -port_flush(port_t\SpecialChar ~ -*port) -\emph default - Unqueues all pending messages in the supplied -\emph on -port_t -\emph default -, if any. - This can be useful to discard unused -\emph on -port_reply() -\emph default - results which are obtained where no result codes are needed, rather than - using a -\emph on -while() -\emph default - loop of -\emph on -port_get() -\emph default - statements. - Also useful before destroying ports when desired. - Returns TRUE on success, or FALSE if the port is invalid. - Should obviously not be used on other tasks' ports, only ours. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -sigmask_t\SpecialChar ~ -PORT_SIGMASK(port_t\SpecialChar ~ -*port) -\emph default - Is useful when it is necessary to know which signal bit is associated with - a particular port. - The returned -\emph on -sigmask_t -\emph default - can be ORed with the other masks to provide to -\emph on -signal_wait() -\emph default -. - This way, it is possible for a task to monitor the state of other signals - while at the same time monitoring message ports for events. - This macro, just like -\emph on -SIGMASK() -\emph default -, should be used instead of expressions such as -\emph on -(1L << n) -\emph default - both for code obviousness and backwards compatibility, because the number - of available signals could eventually grow. -\layout Subsubsection - -The special SIGPOLL signal and the poll port -\layout Standard - - -\emph on -XXX needs to be rethinked and re-written :) -\layout Standard - -As there only are 30 user signals, and that a message port is usually associated - with a signal, it may be useful to assign more than one message port to - a single signal, or process more than one event using a single signal and - message port. -\layout Standard - -The SIGPOLL signal is reserved for just that, and each task always has a - message port associated with this signal. - Through this port can be sent various type of messages for more than one - event the task may want to be awakened for. - This provides message multiplexing, while the method for multiple message - ports using the same signal would provide port multiplexing. - The reason why message multiplexing was chosen as a standard in Xisop was - because it requires less resources. - The more ports there are on the system, the larger the system ports pool - grows and it will never shrink for considerations described in the previous - subsection. - -\emph on -XXX -\layout Standard - -This special system-reserved port can be used to transfer reliable signals, - possibly emulating POSIX semantics, or to transfer many other types of - events a task may all be waiting for. - It also is useful to have a high number of concurrently opened high-level - files, and implement filedescriptors. - A special set of functions is provided by Xisop machine-independent layer - to transfer messages through this port, and to evaluate the type of event - that originated the message, along with message size. - Because unlike for standard message ports where messages of a fixed size - are usually transfered, the message size changes here, depending on the - event type and message. -\layout Standard - - -\emph on -XXX -\layout Subsection - -Xisop memory management system -\layout Standard - -Xisop provides three types of memory management primitives for the kernel. - These are provided by the Xisop machine-independent layer. - It also provides distinction between the various types of memory, when - an architecture has more than one (i.e. - Amiga CHIP and FAST RAM, peripheral memory, etc). - Special care was used to prevent the memory management system from having - to disable interrupts (which may be very useful when the -\emph on -_FACILITY_SCHEDTIMER -\emph default - consists of the only timing source for an architecture and needs to be - as reliable as possible). - A -\emph on -_lock_t -\emph default - is internally used by the system page primitives to sychronize access to - the system page pools. - This also avoids having to export them as system calls via traps. -\layout Subsubsection - -Page primitives -\layout Standard - -The first level system consists of page allocation and freeing. - The page size is dependent on architecture when MMU is concerned, however - within Xisop which provides it's own memory management, a page is typically - 4096 bytes. - Primitives are provided to allocate a single page, or number of physically - contiguous pages, and to free back one page, or a number of contiguous - pages. - At system initialization, the page pools are initiated to provide access - to the physical memory areas, and are classified by memory type. - There are a few functions also defined by Xisop which allow to add physical - memory areas to the page pools, and specify their type, so that the architectur -e-dependent initialization code be simpler, and also that at runtime it - be possible to attach new RAM which was mapped from external devices, possibly - hot-pluggable ones such as PCMCIA memory cards, etc. - Here are described the dynamic memory linking functions. - Note that these functions internally use a -\emph on -_lock_t -\emph default - which is acquired to access the system pages pools. - This means that they are generally safe to call anytime, but from interrupt - handler context. - -\emph on -XXX -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -mchunk_t\SpecialChar ~ -*mchunk_init(void\SpecialChar ~ -*mem,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Internally prepares the supplied memory block to pages which can later - be linked into the system. - The internal control structures are setup in hidden data which will not - be added into the public pages. - This is dependent on -\emph on -_PAGE_SIZE -\emph default -, which should be defined by the port-specific < -\emph on -port/support.h -\emph default -> headerfile. - NULL is returned if the supplied memory area was too small to be split - into pages and to store the necessary control data. - Otherwise, a pointer to the -\emph on -mchunk_t -\emph default - is provided. - After using this call, the memory area should never be manipulated anymore, - other than using other Xisop standard calls, unless it is known that the - area is not linked into the system pages. - The supplied memory is expected to be physical contiguous memory. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -mchunk_attach(int\SpecialChar ~ -memtype,\SpecialChar ~ -mchunk_t\SpecialChar ~ -*mchunk) -\emph default - Allows to link an -\emph on -mchunk_t -\emph default - which was previously prepared using -\emph on -mchunk_init() -\emph default -, to the system -\emph on -ppool_t -\emph default - associated with the specified memory type. - After this is performed, it is possible to allocate memory pages from this - memory chunk until it be unlinked using -\emph on -mchunk_detach() -\emph default -. - This depends on -\emph on -_MEM_MAX -\emph default -, which is defined by the port specific < -\emph on -port/support.h -\emph default -> headerfile. - TRUE is normally returned, unless the chunk is seen to already have been - attached, or that the supplied memory type is invalid, in which case FALSE - is returned. - It is possible to setup and append as many -\emph on -mchunk_t -\emph default - as wanted. - For instance, the port-specific code which sets up the kernel pages for - available memory may need to call -\emph on -mchunk_init() -\emph default - and -\emph on -mchunk_attach() -\emph default - multiple times, one for each contiguous memory block. - It is safe to call this function to attach new memory at system runtime, - anytime. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -mchunk_detach(int\SpecialChar ~ -memtype,\SpecialChar ~ -mchunk_t\SpecialChar ~ -*mchunk) -\emph default - Permits to safely detach from the system an -\emph on -mchunk_t -\emph default - which previously was attached using -\emph on -mchunk_attach() -\emph default -. - TRUE is returned on success, or FALSE if the memory type is invalid, if - the supplied -\emph on -mchunk_t -\emph default - was not currently attached, or if any memory from that -\emph on -mchunk_t -\emph default - is still currently allocated, in which case the chunk is not unliked. -\layout Standard - -The first level of allocation primitives allow to allocate and free one - or multiple contiguous pages of physical memory to and from the system - pools ( -\emph on -ppool_t -\emph default - of each memory type). - Internally, the list of linked -\emph on -mchunk_t -\emph default - for a memory type is ran through. - These functions also acquire the system pools safety lock while working - on the system memory pools: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -page_t\SpecialChar ~ -*pages_alloc(int\SpecialChar ~ -memtype,\SpecialChar ~ -u_int32_t\SpecialChar ~ -many,\SpecialChar ~ -bool\SpecialChar ~ -zero) -\emph default - Allocates -\emph on -many -\emph default - contiguous memory pages of -\emph on -_PAGE_SIZE -\emph default - bytes, of the supplied -\emph on -memtype -\emph default -, which can be -\emph on -_MEM_ANY -\emph default - in which case all memory types are tried sequencially, favoring the first - memory type to the last. - A -\emph on -page_t -\emph default - pointer is returned which can be used to access the memory area via -\emph on -page_t->address -\emph default -, or to free back the memory using -\emph on -pages_free() -\emph default -. - NULL is returned if not enough memory can be found to satisfy the request. - If -\emph on -zero -\emph default - is TRUE and pages could be allocated, the memory area is zeroed using -\emph on -pageclr() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -pages_free(page_t\SpecialChar ~ -*pages) -\emph default - Releases to the system one or more contiguous memory pages which previously - were allocated using -\emph on -pages_alloc() -\emph default -. - TRUE is returned on success, or FALSE if the supplied pointer was NULL, - or if the -\emph on -page_t -\emph default - was already freed back. -\layout Subsubsection - -Simple object pool primitives -\layout Standard - -The second level consists of a pool of fixed sized entities, the -\emph on -pool_t -\emph default -. - A pool can be pre-allocated once, with a fixed maximum number of elements, - setup to grow automatically when new elements are needed, internally allocating - and preparing new pages as required, and can optionally also shrink smaller - automatically, releasing back to the system the unused pages. - When a pool is about to shrink, it evaluates statistics about the number - of pages the pool normally holds on average, so that primitives to free - the page are not called too often unnecessarily. - Such pages are buffered by the pool for future use, if they are expected - to be reclaimed back soon. - Using these functions is more efficient in speed and memory than using - page allocation primitives, calls to which it attempts to minimize, while - filling each page of memory with the most objects possible. -\layout Standard - -A C structure should be defined for the type of object which is to be allocated, - and the first element of that structure should consist of a -\emph on -pnode_t -\emph default - element. - These functions, unlike page allocation ones, do not synchronize if multiple - tasks or interrupt handlers share a -\emph on -pool_t -\emph default -. - The caller should therefore provide synchronization whenever necessary. - However, if the -\emph on -pool_t -\emph default - allocates or frees system pages, the -\emph on -pages_alloc() -\emph default - and -\emph on -pages_free() -\emph default - functions are used which internally use synchronization to ensure that - the system pools do not corrupt. - These functions are mostly for kernel use. - If used from userspace, these pools will not be automatically freed back - to the system unless the tasks specifically destroys them before exiting. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -pool_init(pool_t\SpecialChar ~ -*p, u_int32_t\SpecialChar ~ -stepp, u_int32_t\SpecialChar ~ -minp, u_int32_t\SpecialChar ~ -maxp, size_t\SpecialChar ~ -node -size, int\SpecialChar ~ -memtype) -\emph default - Initializes the supplied -\emph on -pool_t -\emph default - object -\emph on -p -\emph default - to be used to allocate objects of -\emph on -nodesize -\emph default - length (size which should include the -\emph on -pnode_t -\emph default - element). - This size should be equal or smaller than -\emph on -_PAGE_SIZE -\emph default - * -\emph on -stepp -\emph default - / 2. - -\emph on -stepp -\emph default - specifies how many contiguous pages should be allocated and freed at once - using -\emph on -pages_ -\emph default -* -\emph on -() -\emph default - primitives, when required. - If -\emph on -stepp -\emph default - appears too small to fit a useful number of nodes in a -\emph on -page_t -\emph default -, it will be automatically grown until it reaches a maximum of 8, after - which FALSE will be returned for failure (although there is no such limit - for the -\emph on -stepp -\emph default - argument itself when manually set high enough). - Each -\emph on -page_t -\emph default - is then internally split into objects. - -\emph on -minp -\emph default - tells the minimum number of -\emph on -page_t -\emph default - which should always remain into the -\emph on -pool_t -\emph default -, or 0 if it is allowed to shrink totally when it needs no memory. - The pool will initially allocate those at initialization, and it will never - shrink smaller during it's lifetime, if non-zero. - -\emph on -maxp -\emph default - similarily specifies the maximum number of -\emph on -page_t -\emph default - which the -\emph on -pool_t -\emph default - should eventually grow to, or 0 for no limit. - For instance, using -\emph on -minp -\emph default - and -\emph on -maxp -\emph default - of 0 allows the pool_t to dynamically grow and shrink as necessary and - it could eventually use all available RAM. - Using a -\emph on -minp -\emph default - and -\emph on -maxp -\emph default - of 2 ensures that at least two -\emph on -page_t -\emph default - be initially allocated, which will never be freed back unless the -\emph on -pool_t -\emph default - is destroyed, and also tells that the pool should never allocate more pages. - This can be useful in interrupt context or some situations where we do - not want the system pool pages to be accessed. - A fixed number of maximum object nodes will be available to allocate and - free efficiently then. - -\emph on -memtype -\emph default - specifies the memory type which this pool will use to allocate the pages. - It is invalid to specify -\emph on -_MEM_ANY -\emph default - here. - TRUE is returned on success, or FALSE on failure (invalid memory type or - not enough available memory). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -pool_destroy(pool_t\SpecialChar ~ -*pool) -\emph default - Frees all memory currently being used by the specified -\emph on -pool_t -\emph default - and destroys the pool object, which can no longer be used by pool object - allocation primitives unless it is re-initialized. - Any currently allocated objects from the -\emph on -pool_t -\emph default - become invalid immediately and should therefore not be accessed anymore, - they get freed as well. - TRUE is returned on success, or FALSE if the supplied -\emph on -pool_t -\emph default - was not previously initialized successfully. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pnode_t\SpecialChar ~ -*pool_alloc(pool_t\SpecialChar ~ -*pool,\SpecialChar ~ -bool\SpecialChar ~ -zero) -\emph default - Attempts to allocate a single object from the specified -\emph on -pool_t -\emph default -. - The object size depends on the -\emph on -nodesize -\emph default - parameter which was supplied at -\emph on -pool_init() -\emph default -. - A pointer to the object is returned on success, or NULL if not enough memory - is available, either for the -\emph on -pool_t -\emph default -, if -\emph on -maxp -\emph default - was non-zero, or system memory. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pnode_t\SpecialChar ~ -*pool_free(pnode_t\SpecialChar ~ -*node) -\emph default - Releases the specified object -\emph on -node -\emph default - which was previously allocated using -\emph on -pool_alloc() -\emph default -, back to the -\emph on -pool_t -\emph default - it belongs to. - NULL is returned. -\layout Subsubsection - -General purpose memory pools -\layout Standard - -The third level memory management system, working with -\emph on -mpool_t -\emph default -, consists of a number of -\emph on -pool_t -\emph default -, adapted to serve most byte requirement requests, through more standard - malloc() and free() like functions. - For a system with a -\emph on -_PAGE_SIZE -\emph default - of 4096, -\emph on -_MPOOLSTEP -\emph default - of 1 and -\emph on -_MPOOLS -\emph default - of 7 and -\emph on -_MPOOLSTART -\emph default - of 16, there are 7 -\emph on -pool_t -\emph default -, deserved to serve element sized as closely possible to the requested number - of bytes (smallest nodesize 16 + sizeof(mnode_t)), and a -\emph on -list_t -\emph default - designed to hold -\emph on -page_t -\emph default - pointers to satisfy larger requests, which get rounded on page boundaries. - An -\emph on -mpool_t -\emph default - is capable of serving requests for various memory types, including -\emph on -_MEM_ANY -\emph default -, where the first memory types are privileged over the last ones. - Like their -\emph on -pool_t -\emph default - counterparts, these functions do not perform any special synchronization - which may be necessary if an -\emph on -mpool_t -\emph default - was shared among several tasks. - Here are the functions related to the -\emph on -mpool_t -\emph default -: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -mpool_init(mpool_t\SpecialChar ~ -*mpool) -\emph default - Initializes an -\emph on -mpool_t -\emph default - to accept allocation requests. - TRUE is returned on success, or FALSE if there is a problem initializing - the -\emph on -pool_t -\emph default - elements, or if the supplied -\emph on -mpool -\emph default - pointer is NULL. - This function is dependent on the port-specific -\emph on -_MPOOLS -\emph default -, -\emph on -_MPOOLSTEP, _MPOOLSTART -\emph default - and the -\emph on -enum _memtypes -\emph default -holding -\emph on -_MEM_MAX -\emph default - which should have been defined in < -\emph on -port/support.h -\emph default ->. - -\emph on -_MPOOLS -\emph default - specifies the number of -\emph on -pool_t -\emph default - objects, -\emph on -_MPOOLSTEP -\emph default - the -\emph on -stepp -\emph default - argument to -\emph on -pool_init() -\emph default -, -\emph on -_MPOOLSTART -\emph default - the maximum bytesize request for the first -\emph on -pool_t -\emph default -, and -\emph on -_MEM_MAX -\emph default - the number of memory types supplied by the system. - See the port-dependent section for more information on how to set these. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -mpool_destroy(mpool_t\SpecialChar ~ -*mpool) -\emph default - Frees all memory currently associated with the specified -\emph on -mpool_t -\emph default -, which should have previously been initialized by -\emph on -mpool_init() -\emph default -, and disables the -\emph on -mpool_t -\emph default -. - Any pointers to memory which were obtained via -\emph on -_malloc() -\emph default - using this pool become invalid. - No more requests will be allowed on this -\emph on -mpool_t -\emph default - unless re-initialized using -\emph on -mpool_init() -\emph default -. - TRUE is returned, or FALSE if the -\emph on -mpool_t -\emph default - was already destroyed, or that the supplied pointer is NULL. - It is also possible for this function to return FALSE without error, in - the case where at least another task shares this -\emph on -mpool_t -\emph default -. - (See the -\emph on -TS_SHARED -\emph default - flag to -\emph on -task_alloc() -\emph default -). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*_malloc(mpool_t\SpecialChar ~ -*mpool,\SpecialChar ~ -int\SpecialChar ~ -memtype,\SpecialChar ~ -size_t\SpecialChar ~ -size,\SpecialChar ~ -bool\SpecialChar ~ -zero) -\emph default - Attempts to allocate the requested -\emph on -size -\emph default - contiguous bytes from the supplied -\emph on -mpool -\emph default -, using memory of type -\emph on -memtype -\emph default -. - _MEM_ANY is valid, and will cause any available memory type to be returned. - A pointer is returned to a memory area holding the number of bytes that - were requested, or NULL if there is not enough memory to satisfy the request, - or if the parameters are wrong. - If -\emph on -zero -\emph default - is TRUE, the memory area is cleared with 0x00 bytes. - Automatic synchronization is performed if the -\emph on -mpool_t -\emph default - is shared by more than one task. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*_free(void\SpecialChar ~ -*mem) -\emph default - Frees back the memory to which the supplied -\emph on -mem -\emph default - points, to where it belongs. - NULL is returned. - Automatic synchronization is performed if the -\emph on -mpool_t -\emph default - is shared by more than one task. -\layout Paragraph - -Kernel code -\layout Standard - -Here are variants which can be used by kernel functions. - Note that the kernel can use all the above previously mentionned functions - as well, however for consistency it is good to use the following where - appropriate. - All of these, contrary to the previously described primitives, internally - use exclusive locks as necessary to ensure the integrity of the system - pools, so that disabling the scheduler is unnecessary: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*_kmalloc(int\SpecialChar ~ -memtype,\SpecialChar ~ -size_t\SpecialChar ~ -size,\SpecialChar ~ -bool\SpecialChar ~ -zero) -\emph default - Allocates general-purpose memory from the kernel memory pool, which should - be released using -\emph on -kfree() -\emph default -. - When a task uses this function the memory is not restored to the system - automatically when it exists. - Special syncronization is used internally so that it is safe to use by - multiple tasks. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*_kfree(void\SpecialChar ~ -*mem) -\emph default - Frees back to the kernel memory pools memory which has previously been - allocated by -\emph on -kmalloc() -\emph default -. - Internal special synchronization is used. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*TMALLOC(int\SpecialChar ~ -memtype,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Equivalent to calling -\emph on -kmalloc(memtype, size, FALSE); -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*TCMALLOC(int\SpecialChar ~ -memtype,\SpecialChar ~ -int\SpecialChar ~ -number,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Equivalent to calling -\emph on -kmalloc(memtype, number * size, TRUE); -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*MALLOC(size_t\SpecialChar ~ -size) -\emph default - Identical to calling -\emph on -kmalloc(_MEM_ANY, size, FALSE); -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*CMALLOC(int\SpecialChar ~ -number,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Like calling -\emph on -_kmalloc(_MEM_ANY, number * size, TRUE); -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*FREE(void\SpecialChar ~ -*mem) -\emph default - Equivalent to -\emph on -_kfree(mem); -\emph default - but made to match all above macros. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*kmalloc(size_t\SpecialChar ~ -size) -\emph default - Like -\emph on -MALLOC() -\emph default - but implemented as an ANSI-C compliant function. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -kfree(void\SpecialChar ~ -*mem) -\emph default - Counterpart to -\emph on -kmalloc() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pnode_t\SpecialChar ~ -*spool_alloc(u_int32_t\SpecialChar ~ -pool) -\emph default - Allows to efficiently allocate a frequently used kernel object for which - a special system pool exists. - -\emph on -pool -\emph default - may consist of one of the -\emph on -POOL_ -\emph default -* names which are defined in the -\emph on -enum _syspools -\emph default - in < -\emph on -src/kernel/memory.h -\emph default ->. - Automatic synchronization is performed. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -pnode_t\SpecialChar ~ -*spools_free(u_int32_t\SpecialChar ~ -pool,\SpecialChar ~ -pnode_t\SpecialChar ~ -*node) -\emph default - Made to free a system object which was previously allocated using -\emph on -spool_alloc() -\emph default -. - Automatic synchronization is performed. -\layout Paragraph - -User space tasks -\layout Standard - -The following can be called by user tasks to allocate memory using their - own memory pool, which is automatically released back to the system when - they exit. - They behave identically to the standard ANSI-C functions bearing the same - name. - They are implemented as functions rather than macros, for inclusion into - the Xisop shared library. - These are also safe to use in the case where more than one tasks are sharing - an -\emph on -mpool_t -\emph default - (see the -\emph on -TS_SHARED -\emph default - flag to -\emph on -task_alloc() -\emph default -). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*malloc(size_t\SpecialChar ~ -size) -\emph default - Behaves identically to the standard ANSI-C -\emph on -malloc() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*calloc(int\SpecialChar ~ -number,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Identical to ANSI-C -\emph on -calloc() -\emph default - semantics. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*realloc(void\SpecialChar ~ -*ptr,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Like ANSI-C -\emph on -realloc() -\emph default - semantics. - Note that like the standard, the returned pointer can point to a new memory - area, in which case the previous contents will have been copied over. - The use of this function is generally discouraged against generally more - efficient dynamic allocation techniques using linked lists. - It is however provided for compatibility with ANSI-C. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -free(void\SpecialChar ~ -*ptr) -\emph default - Again like the ANSI-C -\emph on -free() -\emph default - function. - Note that this function can also free memory which has been allocated using - -\emph on -tmalloc() -\emph default - and -\emph on -tcmalloc() -\emph default -. -\layout Standard - -ANSI-C however has no concept of multiple memory types, and as such -\emph on -tmalloc() -\emph default - had to be included. - -\emph on -free() -\emph default - can be used to free back memory which they allocate still: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*tmalloc(int\SpecialChar ~ -memtype,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Like -\emph on -malloc() -\emph default - but allows to specify a Xisop port-dependent memory type. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*tcmalloc(int\SpecialChar ~ -memtype,\SpecialChar ~ -int\SpecialChar ~ -number,\SpecialChar ~ -size_t\SpecialChar ~ -size) -\emph default - Like -\emph on -calloc() -\emph default -, but can also be told the type of memory wanted. -\layout Subsubsection - -A note about absolute memory allocation -\layout Standard - -Xisop does not provide an allocation function which can be told the absolute - memory location area desired. - There are several reasons for this which this section attempts to explain. -\layout Standard - -Xisop provides the necessary inter-task communications tools to prevent - the need of using absolute memory addresses for rendez-vous among tasks. - Moreover, it has the concept of devices, which can be left the task to - perform synchronization among tasks which need to share a specific resource. - Additionally, Xisop does not setup the MMU in a way to prevent user tasks - from accessing any memory. -\layout Standard - -This means that if absolute memory locations need to be reserved by the - system, they normally should not be included into the general purpose memory - pools. - A user device task can then specifically handle those locations as necessary - and provide multitasking-friendly access to them. -\layout Standard - -For instance, the video memory should not be attached to the system memory - pools by the port-specific code. - Instead, a device task should be written and provided to allow safe access - to the video hardware, and basic console support. - Optionally, a handler can be provided, which even allows a higher abstraction - to access the device. - For instance, the device could supply basic resource allocation and access - primitives, while the handler could support vt100 emulation over the device. -\layout Standard - -In the case of a single-tasking application being developped around Xisop, - once the scheduler is disabled there is no need for any special handling - to access the wanted memory regions. - The memory allocator is no longer necessary to use, even. -\layout Standard - -Another consideration to realize is that if for instance video memory was - part of the system memory pools, it could automatically be allocated by - another task which was only requesting some memory. - If we had support for reserved pages, then there would be no point in allocatin -g them, also. - Only general-purpose memory should be attached into the system. - There exists the possibility of reserving a specific memory type for some - memory however, if there is a need for specific regions to only be used - by certain applications but that general purpose management primitives - are still desired. -\layout Standard - -Other than the Xisop message port system which allows tasks to share and - synchronize arbitrary memory regions, it is possible for several tasks - to inherently share a common memory pool, using the -\emph on -TS_SHARED -\emph default - flag to -\emph on -task_alloc() -\emph default -. - This can in some circumstances be used if the memory resources are quite - scarce (many tasks which only allocate few but various sized memory blocks - of different memory types can waste quite a large amount of pages. - Using the same pool would then permit the same pages to be used among the - tasks for their similar allocation needs. - Their allocated blocks generally consist of a page which is split in equally - sized blocks). - Moreover, in such a setup, one task which allocates a block of memory does - not implicitly free it on exit, if other tasks are still running sharing - the memory. - Those blocks need to be explicitely freed unless all tasks exit to really - be released back to the system. - Moreover, special synchronization must be used by the tasks if they want - to access the same memory addresses. - This is usually done using an -\emph on -rwlock_t -\emph default -, or disabling the scheduler temporarily. -\layout Subsection - -Xisop public interrupt abstraction facilities -\layout Standard - -To allow Xisop architecture-specific devices to attach interrupt handler - hooks, and for portable code to make use of a few basic interrupt facilities - like timers, it is a good idea to provide a few access functions to allow - this. - The idea is to provide a facility which allows the kernel code, or userspace - tasks, to run a piece of code once, a certain number of times, or indefinitely, - as part of the low-level interrupt handling code. - It thus should be possible to add and delete their code handlers from each - of the wanted interrupt handlers. - To provide this multi-purpose facility, the following system was developed, - and almost entirely consists of portable common code. -\layout Subsubsection - -Internals -\layout Standard - -The following structure is defined in < -\emph on -common/kernel/exception.h -\emph default ->: -\layout Quote - - -\emph on -typedef struct _int_hook { -\newline -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -pnode_t node; -\newline -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -hookid_t id; -\newline -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -u_int32_t skipcount, runcount; -\newline -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -void (*code)(hookid_t, int, void *); -\newline -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -\SpecialChar ~ -void *data; -\newline -} hook_t; -\layout Standard - -Where -\emph on -node -\emph default - is used for internal linking, -\emph on -id -\emph default -consists of a unique ID for this facility, -\emph on -skipcount -\emph default - of the number of times this handler will execute before calling the -\emph on -code -\emph default - hook, -\emph on -runcount -\emph default - of the number of times the hook -\emph on -code -\emph default - will be called before it gets automatically deleted, or 0 if it should - execute everytime this interrupt occurs. - -\emph on -void\SpecialChar ~ -(*code)(hookid_t, int, void\SpecialChar ~ -*) -\emph default - consists of the C function to invoke when the event occurs. - The abstracted arguments -\emph on -void -\emph default - pointer may serve any purpose the application wants. - -\emph on -void\SpecialChar ~ -*data -\emph default - pointer to abstract user-defined data will be passed as argument to the - called function. - The -\emph on -hookid_t -\emph default - argument will consist of the ID of the -\emph on -hook_t -\emph default - into the facility which caused the call, and is made to be unique. - The supplied -\emph on -int -\emph default - argument may be useless, or can serve to determine the origin of the interrupt, - somewhat like the -\emph on -hookid_t -\emph default -, but will use a facility-specific semantics, which could include a key - being pressed in the case of a keyboard interrupt, etc. - The kernel uses an efficient memory -\emph on -pool_t -\emph default - to internally allocate and free these automatically when hooks are attached - and detached from facilities. -\layout Standard - -The following machine-independent function is also provided so that the - port-specific code (from assembly or C) may easily order an execution of - all attached hooks on a facility. - The hook ids are made to be unique so that it is safe for the one who attached - a hook to try to delete it, assuming that if it exists in the list, it - cannot be any other hook supplied by other code (even if it expired and - another hook replaced it internally). - This consists of an interface for the port, not of the general user interface - to the facilities: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -facility_exechooks(u_int32_t\SpecialChar ~ -facility,\SpecialChar ~ -int\SpecialChar ~ -origin) -\emph default - executes all attached code hooks of the specified -\emph on -facility -\emph default -, sequencially (if any). - This means that for each existing hook, the corresponding function is called - if it's -\emph on -skipcount -\emph default - is 0, or -\emph on -skipcount -\emph default - is simply decreased by 1 otherwise. - When the hook is to be called, it is passed the corresponding user data - pointer (which can be NULL) to it, the -\emph on -hookid_t -\emph default - id for the hook, and -\emph on -origin -\emph default - into the -\emph on -int -\emph default - argument. - The hook is then evaluated for expiration if -\emph on -runcount -\emph default - was non-zero at insertion with -\emph on -hook_attach() -\emph default -, and automatically destroyed if it expires. - The caller should normally disable the interrupt associated with the facility - temporarily before calling this function, however the associated -\emph on -facility_t -\emph default - internally uses an -\emph on -_rlock_t -\emph default - to prevent self-recursion, lock which is also used by -\emph on -hook_attach() -\emph default - and -\emph on -hook_detach() -\emph default - for safety. - This function is made for the port-specific code to call when the interrupt - this facility is concerned with occurs. - This function is dependent on -\emph on -_FACILITY_MAX -\emph default - and the -\emph on -enum _facilities -\emph default - which are port-specific in < -\emph on -port/support.h -\emph default ->. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -facilities_init(void) -\emph default - is provided to ease initialization of the system facility arrays from the - port-specific code. - This function depends on the port-specific -\emph on -_FACILITY_MAX -\emph default - and the -\emph on -enum _facilities -\emph default - defined in < -\emph on -port/support.h -\emph default ->. - More informaton on port-specific initialization is provided in a next chapter. -\layout Standard - -Decision was made to provide the above functions even though their functionality - is simple for a few reasons. - It prevents code duplication among ports, minimises assembly sections in - machine-dependent sections, and they are known to work, providing the required - functionality. - Being abstracted, their internals may change over time affecting all ports - simultaneously without requireing changes in the machine-specific sections. - Moreover, they use an internal memory -\emph on -pool_t -\emph default - per -\emph on -facility_t -\emph default - for efficiency. - Once initialized, those will never need to query the system page primitives, - and are thus very efficient, as well as safe to use from interrupt context - without special handling. -\layout Standard - -Because these facilities are transparent to the Xisop microkernel itself, - and are provided by port-specific code, although driven by common portable - code, the interrupt sources are not required to internally correspond to - actual hardware interrupts. - The port-specific code is free to provide the wanted interrupt sources - and facilities in the manner it wishes. - As such they can be used for various hardware and sotfware event types. -\layout Subsubsection - -User interface -\layout Standard - -Here is now described the kernel user interface to manipulate custom interrupt - hooks on the provided facilities. - These are also machine-independent. - They were implemented around -\emph on -_rlock_t -\emph default - and -\emph on -pool_t -\emph default - primitives in a way to make it possible for userland to access their functional -ity without the need for system call traps. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -hookid_t\SpecialChar ~ -hook_attach(u_int32_t\SpecialChar ~ -facility, u_int32_t\SpecialChar ~ -skipcount, u_int32_t\SpecialChar ~ -runcount, - void\SpecialChar ~ -(*code)(hookid_t,\SpecialChar ~ -int,\SpecialChar ~ -void\SpecialChar ~ -*), void\SpecialChar ~ -*data) -\emph default - Allows to append or insert a user supplied code hook to the wanted interrupt - facility. - The -\emph on -facility -\emph default - argument specifies what type of exception, trap or interrupt is wanted, - and is port-specific. - An example would be -\emph on -_FACILITY_VBLANK -\emph default -. - -\emph on -code -\emph default - specifies which function to call as the user hook handler, which should - never be NULL. - -\emph on -data -\emph default - points to an optional user data block which will be passed back when calling - the function handler, and can be NULL. - The argument of type -\emph on -hookid_t -\emph default - which will be passed will consist of the unique ID representing this -\emph on -hook_t -\emph default - into the -\emph on -facility -\emph default -, while the -\emph on -int -\emph default - argument, which is facility-specific, could serve to determine the origin - of the event if the facility serves several. - The return value is 0 in the case of an error (unknown public facility), - or a unique ID which can be used to eventually delete that particular hook. - This is required to not correspond to the hook function address, since - multiple hooks may call the same function if wanted. - This ID is always unique to this facility. - It is safe to attach a code hook function which can expire and then attempt - to remove it using the supplied -\emph on -hookid_t -\emph default -. - If it expired and another hook now uses the same -\emph on -hook_t -\emph default - address, it's -\emph on -hookid_t -\emph default - will still be different. - The semantics of -\emph on -skipcount -\emph default - and -\emph on -runcount -\emph default - are explained in the internals above. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -hook_detach(u_int32_t\SpecialChar ~ -facility,\SpecialChar ~ -hookid_t\SpecialChar ~ -id) -\emph default - Permits to remove a user supplied hook on the wanted -\emph on -facility -\emph default -, with the specfied -\emph on -id -\emph default -. - Returns TRUE if it could find and delete the hook, or FALSE if the hook - did not exist, or no longer does (it may have expired). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -facility_disable(u_int32_t\SpecialChar ~ -facility) -\emph default - Disables all hooks of the specified facility temporarily. - They cannot expire during the period they are suspended, and none will - be executed, even when the interrupt source occurs. - It does not disable the interrupt source. - This system is recursive, in that the exact same number of calls to -\emph on -facility_enable() -\emph default - must be made to re-enable the facility. - Note that it is safe to attach and detach hooks from a facility at any - time, and that this function is only provided as a feature. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -facility_enable(u_int32_t\SpecialChar ~ -facility) -\emph default - Re-enables the specified facility which was previously suspended using - -\emph on -facility_disable() -\emph default -, if the -\emph on -facility_t -\emph default - internal -\emph on -_rlock_t -\emph default - reaches 0 (that is all previous calls to -\emph on -facility_disable() -\emph default - were matched by a -\emph on -facility_disable() -\emph default -). -\layout Subsubsection - -Common facilities -\layout Standard - -Not all ports have all these facilities, and some may provide more. - However, this consists of a guide so that facilities which are intended - to provide the same functionality on the various architectures bear the - same name. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_SCHEDTIMER -\emph default - This is the only facility which must be available on all ports. - It usually executes at intervals governed by -\emph on -_SCHEDTIMER_HZ -\emph default -, a frequency defined in instances per second (hertz), which is defined - in < -\emph on -port/support.h -\emph default ->. - Systems which only comport one hardware timer source will at least always - have this timer facility available for multiple uses, although internally - used by the scheduler. - Disabling the scheduler does not disable the timer facility, as the scheduler - lock consists of an -\emph on -_rlock_t -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_KEYBOARD -\emph default - As the name implies, this facility is concerned with keyboard key presses. - The key code is usually returned in the -\emph on -int -\emph default - argument when calling the attached hooks. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_VBLANK -\emph default - This facility is very useful for graphic-oriented software which need to - synchronize operations with the video refresh rate. - The frequency of a vertical blank interrupt varies with the underlaying - hardware, but usually consists of 50Hz for PAL (europe) and 60Hz for NTSC - (american) systems. - This is very useful to implement double buffering, and can also be used - to synchronize audio events like music and sound effects with animations. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_TRAP -\emph default -* These type of facilities can be directly tied to user traps which may - remain available, and associated to a related -\emph on -_cause() -\emph default - function to allow user tasks to both attach handlers to receive those events - and call -\emph on -_cause() -\emph default - to trigger such events. - However, because of the Xisop -\emph on -sys_custom() -\emph default - system call, the use of such facilities become questionable. - -\emph on -XXX -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_FLOPPYSYNC -\emph default - Triggered when a floppy drive notifies that it found the sync code of a - track. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_FLOPPYBLOCK -\emph default - Triggered when the floppy drive finished reading a requested block to memory. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_AUDIO -\emph default - Notification that an audio channel finished playing a sample, or starts - looping back the supplied sample buffer again. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_BLITTERREADY -\emph default - Notification by a parallel hardware blitter that it is done with the requested - operations and may now be ordered new instructions again. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_COPPER -\emph default - A hardware raster parrallel blitter originated interrupt -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_SERIAL -\emph default - A generic serial interrupt -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_SERIALRBF -\emph default - A serial Read Buffer Full interrupt -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_FACILITY_SERIALTBE -\emph default - A serial Transmit Buffer Empty interrupt -\layout Standard - -Many other types of facilities may exist, although what should be taken - as an example consists of the clear names that they are given, which directly - reference to their origin as much as possible, while attempting to avoid - cryptic names such as KBD for keyboard, etc. - Where required, the label can be long enough as long as it remains meaningful. -\layout Subsection - -Kernel statistics -\layout Standard - -The -\emph on -src/common/kernel/statistic. -\emph default -( -\emph on -c -\emph default -| -\emph on -h -\emph default -) module defines primitives for statistic counters. -\layout Standard - - -\emph on -XXX -\layout Subsection - -Xisop binaries and executables -\layout Standard - -The Xisop kernel currently has no ELF or a.out relocatable executable loader, - and no custom format was implemented, which would require a GCC ld BFD - backend to be written. - This means that at current time, all the shared libraries, devices, handlers - and user tasks need to be started by the kernel at startup. - This is easily done however, but prevents the microkernel from using all - it's features of attaching required components at runtime as wanted, although - it was designed to eventually be able to do so efficiently. - It however currently allows Xisop to be useable in embedded systems which - have defined components, like for monolithic kernels. -\layout Subsection - -Xisop devices -\layout Standard - -Xisop devices generally consist of a medium-level backend to hardware-assisted - services, such as keyboard input, tty output, RS-232 communication, etc. - As such, they are generally architecture-dependent. - Of course, machine-independent devices may be written as wanted, where - the high-level handler interface is considered unadequate and that shared - access to some kind of ressource is wanted, however. -\layout Standard - -The Xisop devices are implemented around the message port system. - There were two main reasons which determined this decision compared to - using a shared library type system. - First, the message receiving responsiveness and speed can be determined - by the task priority, which allows the administrator to decide which devices - and tasks to prioritize over others. - Secondly, the message passing system already provides reliable FIFO queuing, - and each message/request can be replied to when wanted, allowing a device - to easily serve resources in a multitasking-friendly, asynchroneous manner - to the simultaneous requesters. -\layout Standard - -A device is thus implemented by a task, which decides to attach a system - device node and then takes the responsibility to serve the expected requests. - Each task may only attach one device to the system lists, and has to specify - the device name and version which are used for other tasks to open the - device. - This means that a device name may have several simultaneous versions running - on the system. -\layout Standard - -Of course, there are cases where only a single device may control a specific - hardware resource for instance, and in this case the versionning system - becomes less useful, in which case version 0 is usually used. - However, the version may still be useful if the various versions of the - device had changes to the user interface. - In this case, using the version is still useful, as opening using the wrong - version (the one a task expects) will at least always fail cleanly with - an error, rather than leaving the task to open a device which does not - act as expected when sending requests. -\layout Subsubsection - -User interface -\layout Standard - -Here are described the device interface functions. - Let's first present the functions which are intended for client tasks to - access device server ones: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -device_t\SpecialChar ~ -*device_open(const\SpecialChar ~ -char\SpecialChar ~ -*name,\SpecialChar ~ -u_int32_t\SpecialChar ~ -version,\SpecialChar ~ -u_int32_t\SpecialChar ~ -unit) -\emph default - Allows the task to open the unit number -\emph on -unit -\emph default - of device -\emph on -name -\emph default - of version -\emph on -version -\emph default -. - NULL is returned on failure, which can occur because of lack of memory, - or if the specified device name of the specified version does not exist. - Otherwise, a -\emph on -device_t -\emph default - handle pointer is returned, which may then be used at -\emph on -iorequest_init() -\emph default -. - Device names are case-sensitive. - If the task exists and that open devices have not been explicitely closed, - the kernel automatically closes them. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -device_t\SpecialChar ~ -*device_close(device_t\SpecialChar ~ -*handle) -\emph default - Closes a device handle which previously was opened using -\emph on -device_open() -\emph default -. - Always returns NULL. - Any -\emph on -iorequest_t -\emph default - associated to this -\emph on -device_t -\emph default - may not be used anymore, as it becomes invalid, unless it be reinitialized - again using -\emph on -iorequest_init() -\emph default - using a new -\emph on -device_t -\emph default - handle. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_init(iorequest_t\SpecialChar ~ -*message,\SpecialChar ~ -device_t\SpecialChar ~ -*handle,\SpecialChar ~ -port_t\SpecialChar ~ -*replyport) -\emph default - Initializes an -\emph on -iorequest_t -\emph default - -\emph on -message -\emph default -, which is necessary to use other -\emph on -iorequest_ -\emph default -* -\emph on -() -\emph default - functions to perform device requests. - -\emph on -handle -\emph default - specifies the -\emph on -device_t -\emph default - which will serve requests for this message during future requests, and - -\emph on -replyport -\emph default - of a generally -\emph on -iorequest_t -\emph default --specific private port which was previously created, through which request - result messages will be sent back to us by the device. - The -\emph on -iorequest_t -\emph default - buffer is the responsibility of the task, just like -\emph on -port_t -\emph default - -\emph on -message_t -\emph default - are. - Returns TRUE on success, or FALSE on failure (invalid arguments or out - of memory). - The device may optionally internally allocate device-specific additional - data which will then attach to the -\emph on -iorequest_t -\emph default -. - These will however be allocated on the current task's memory pool, and - are therefore released automatically if the task exists. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_destroy(iorequest_t\SpecialChar ~ -*message) -\emph default - Invalidates the -\emph on -iorequest_t -\emph default - -\emph on -message -\emph default - which was previously initialized using -\emph on -iorequest_init() -\emph default -. - As devices may internally allocate device-specific additional data and - attach it to an -\emph on -iorequest_t -\emph default - at initialization, a task should call this function when it no longer needs - the -\emph on -iorequest_t -\emph default -. - Of course, if the task exists, the resources are automatically released - back to the system, however. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_sync(iorequest_t\SpecialChar ~ -*message) -\emph default - Permits to send a synchroneous request to a device, via -\emph on -message -\emph default -. - This means that the task is suspended until the request completes. - The reply result is also automatically extracted from the reply port associated - to the -\emph on -iorequest_t -\emph default -. - Before sending a request, some fields of the -\emph on -iorequest_t -\emph default - message should be set. - When it completes, the result fields will have been set. - Both can have device-dependent semantics, although there is generally a - standard, which is described in the internals section. - Returns TRUE if the request could be sent, or FALSE if there was an internal - problem (invalid -\emph on -message -\emph default -, or no longer existing device). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_async(iorequest_t\SpecialChar ~ -*message) -\emph default - Very similar to -\emph on -iorequest_sync() -\emph default -, but permits to launch the request without waiting until it completes, - performing an asynchroneous request. - Upon completion, the device will internally -\emph on -port_reply() -\emph default - into the reply port associated with -\emph on -message -\emph default -, and the task is then responsible for extracting the reply message from - the reply port. - This allows to launch several asynchroneous requests and to monitor signals - or ports to detect when they occur. - For instance, a task may launch an asynchroneous request to read one character, - and when the request completes, specifying that data exists to read. - It can then send synchroneous requests to read larger blocks until no more - data is available, in which case it may then again send an asynchroneous - request and resume normal activity. - TRUE is returned if the request could be launched, or FALSE if it failed - (invalid -\emph on -message -\emph default - or no longer existing device). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_abort(iorequest_t\SpecialChar ~ -*message) -\emph default - If -\emph on -message -\emph default - currently consists of an asynchroneous request which was made using -\emph on -iorequest_async() -\emph default - and is still pending, an abort request is sent to cancel it. - Like usual, the device will reply still as soon as the request could be - aborted, and the task becomes responsible to unlink the reply message from - the reply port associated with -\emph on -message -\emph default -. - TRUE is returned on success, or FALSE if -\emph on -message -\emph default - does not consist of a currently pending asynchroneous request. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_wait(iorequest_t\SpecialChar ~ -*message) -\emph default - Waits until a currently pending (or aborted which not yet replied) asynchoneous - request terminates, and automatically unlinks the reply message received - through the reply port of -\emph on -message -\emph default -. - This can especially be useful after an -\emph on -iorequest_abort() -\emph default -. - Returns TRUE on success, or FALSE if -\emph on -message -\emph default - is not currently a pending (or aborted which did not yet return) asynchroneous - request. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_pending(iorequest_t\SpecialChar ~ -*message) -\emph default - Returns TRUE if -\emph on -message -\emph default - currently consists of an asynchroneously pending request, or FALSE otherwise. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_aborted(iorequest_t\SpecialChar ~ -*message) -\emph default - Returns TRUE if -\emph on -message -\emph default - consists of a request which just completed, but which was an asynchroneous - request and was aborted. -\layout Standard - -These utility functions, although performing the most basic Xisop device - operations, are provided to minimize code duplication, for very simple - synchroneous I/O. - Normally, tasks will address requests using -\emph on -iorequest_sync() -\emph default - and -\emph on -iorequest_async() -\emph default - as needed, but this can be useful to have: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -ssize_t\SpecialChar ~ -device_read(iorequest_t\SpecialChar ~ -*req,\SpecialChar ~ -void\SpecialChar ~ -*buf,\SpecialChar ~ -size_t\SpecialChar ~ -len) -\emph default - Similarily to unix -\emph on -read() -\emph default -, reads at most -\emph on -len -\emph default - bytes of data from the opened device and unit associated with -\emph on -req -\emph default - into -\emph on -buf -\emph default -, and returns the number of actually read bytes, or -1 on error. - The current task is suspended until the operation completes, since -\emph on -iorequest_sync() -\emph default - is internally used. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -ssize_t\SpecialChar ~ -device_write(iorequest_t\SpecialChar ~ -*req,\SpecialChar ~ -void\SpecialChar ~ -*buf,\SpecialChar ~ -size_t\SpecialChar ~ -len) -\emph default - Like unix -\emph on -write() -\emph default -, writes at most -\emph on -len -\emph default - bytes of data from -\emph on -buf -\emph default -, to the opened device and unit associated with -\emph on -req -\emph default -, and returns the number of actually written bytes, or -1 on error. - The current task is suspended until the operation completes as it internally - uses -\emph on -iorequest_sync() -\emph default -. -\layout Subsubsection - -Device server interface -\layout Standard - -Here follows functions which are only useful to device server tasks to call: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -device_attach(const\SpecialChar ~ -char\SpecialChar ~ -*name, u_int32_t\SpecialChar ~ -version, port_t\SpecialChar ~ -*port, void\SpecialChar ~ -(*clean)(vo -id), bool\SpecialChar ~ -(*open)(void\SpecialChar ~ -**,\SpecialChar ~ -u_int32_t), void\SpecialChar ~ -(*close)(void\SpecialChar ~ -*,\SpecialChar ~ -u_int32_t), void\SpecialChar ~ -*(*iorini -t)(void), void\SpecialChar ~ -(*iordestroy)(void\SpecialChar ~ -*), u_int8_t\SpecialChar ~ -flags) -\emph default - -\newline -Allows the current task to become a system device. - -\emph on -name -\emph default - consists of the unique case-sensitive device name to assign to the system - device node, which will be required to use at -\emph on -device_open() -\emph default -, and will be truncated to 32 characters if longer. - -\emph on -version -\emph default - specifies the version number to use, which will also need to match at -\emph on -device_open() -\emph default -, for this device name. - -\emph on -port -\emph default - consists of the device server's private port, through which requests should - be sent. - -\emph on -flags -\emph default - consists of one or combination of -\emph on -DNF_ -\emph default -* flags described in the header file, like -\emph on -DNF_RESIDENT -\emph default - which tells Xisop to never cause the device task to exit if there exist - no more client open instances. - The various function pointers which must be supplied are explained below: -\begin_deeper -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -(*clean)(void) -\emph default - is a function which the device task can provide for Xisop to call when - no more client open instances exist for this device, unless the device - is resident (and -\emph on -flags -\emph default - comported -\emph on -DNF_RESIDENT -\emph default - at device creation). - This function is responsible to restore the hardware which this device - may have been serving to a consistant and known state. - It will also be called automatically by Xisop when the task exits normally. - Note that -\emph on -clean() -\emph default - should not comport any special function to cause the task to end. - Xisop will send a -\emph on -SIGTERM -\emph default - signal when the task should do so. - If the task exits by itself, -\emph on -clean() -\emph default - will be called automatically nevertheless. - Because this function may be called under the context of any other task, - it should not expect to execute under the device's task memory pool (and - therefore should normally not call allocation functions). - It is possible to specify NULL for this function if the device has no need - for any special cleanup function. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -(*open)(void\SpecialChar ~ -**udata,\SpecialChar ~ -u_int32_t\SpecialChar ~ -unit) -\emph default - All devices are required to provide this function. - It's purpose is to validate if -\emph on -unit -\emph default - can be opened (some devices limit the number of open instances of a unit, - to protect their resources), and to optionally allocate any needed device-speci -fic data which it may need to attach to -\emph on -device_t -\emph default - nodes. - -\emph on -open() -\emph default - is called at each -\emph on -device_open() -\emph default - function instance called on this device. - It is expected to return FALSE if it refuses to open the specified -\emph on -unit -\emph default - or if it cannot allocate any required resources, or TRUE on success. - If the task allocates data which is needed to be attached to the -\emph on -device_t -\emph default - handle, it should supply the address of the allocated data block into the - supplied -\emph on -udata -\emph default -. - It should set NULL there otherwise. - Although the device may at it's discretion maintain counters on the number - of currently opened units, etc, Xisop will automatically send a SIGTERM - to the device task if it is non-resident and that there exist no more openers. - Note that this function is called under the context of the task which calls - -\emph on -device_open() -\emph default -. - As such, the memory allocations, such as the optional -\emph on -udata -\emph default - block will be automatically freed when the other task ends, not ours. - For this reason, the function can use -\emph on -malloc() -\emph default - and companions safely, but should not use lower-level Xisop kernel allocation - primitives. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -(*close)(void\SpecialChar ~ -*udata,\SpecialChar ~ -u_int32_t\SpecialChar ~ -unit) -\emph default - This function is also required for all device tasks to provide, and is - called by -\emph on -device_close() -\emph default - on a -\emph on -device_t -\emph default - handle which was previously associated to this task by -\emph on -device_open() -\emph default -. - The function is responsible for calling -\emph on -free() -\emph default - on the supplied -\emph on -udata -\emph default - pointer if needed, and to perform the necessary device-specific cleanup - required when a device handle closes. - -\emph on -unit -\emph default - specifies the unit which was opened by this handle. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*(*iorinit)(void) -\emph default - Devices may optionally provide this function to allocate -\emph on -iorequest_t -\emph default - message specific data which it might need, very similarily to -\emph on -open() -\emph default - which can attach data to a -\emph on -device_t -\emph default - handle. - NULL can be supplied if there is no need for -\emph on -iorequest_t -\emph default - specific extention data. - This function is called under the context of the task calling -\emph on -iorequest_init() -\emph default - and as such no Xisop low-level allocation functions should be called. - The function may allocate the data block with -\emph on -malloc() -\emph default -, initialize it and return a pointer to it, or NULL on failure (out of memory). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -(iordestroy)(void\SpecialChar ~ -*udata) -\emph default - May also be supplied NULL if NULL was supplied for -\emph on -iorinit() -\emph default -. - Otherwise, this function is responsible to -\emph on -free() -\emph default - the supplied -\emph on -udata -\emph default -, which corresponds to a block of memory which was returned by a previous - -\emph on -iorinit() -\emph default - call. -\end_deeper -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -iorequest_satisfy(iorequest_t\SpecialChar ~ -*message,\SpecialChar ~ -bool\SpecialChar ~ -result) -\emph default - Is a useful utility function to set the main request success result code - and reply to the task that it has completed. -\layout Standard - -Various macros of interest may be used by device tasks: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*DEVICEHANDLE_UDATA(device_t\SpecialChar ~ -*handle) -\emph default - Returns the -\emph on -udata -\emph default - pointer associated with the supplied -\emph on -device_t -\emph default - -\emph on -handle -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -*IOREQUEST_UDATA(iorequest_t\SpecialChar ~ -*message) -\emph default - Returns the -\emph on -udata -\emph default - pointer associated with the supplied -\emph on -iorequest_t message -\emph default -. -\layout Subsubsection - -Internals -\layout Standard - -This system based upon the Xisop message ports system and the previously - described functions permit to open or provide devices, and to communicate - requests from the client-side and completion from the server-side, through - a special message, the -\emph on -iorequest_t -\emph default -. -\layout Standard - - -\emph on -XXX -\layout Subsection - -Xisop handlers -\layout Standard - -Handlers provide a higher-level abstraction to devices or resources. - It should be noted that unlike devices, these are implemented in the form - of a standard shared library format. - This means that devices are usually a nice abstraction to mount handlers - on, as devices naturally perform the queuing, etc. - -\emph on -XXX -\layout Subsection - -Xisop shared libraries -\layout Standard - -The concept of Xisop shared libraries is both very simple, and unusual. - It is important that all functions a library provides publically be reentrant. - Opening a library basically obtains the pointer to a structure which is - necessary to access it's function pointers. - As such, only one resident copy is required for all applications, and new - applications can -\begin_inset Quotes eld -\end_inset - -attach -\begin_inset Quotes erd -\end_inset - - the libraries they need as required. - The system keeps track of how many times it is currently being open by - various tasks, and can therefore know when the library should be expunged - from memory. - Obviously, when a library is requested which is not currently in RAM, it - should be loaded in the system from disk. -\layout Standard - -Each library may have concurrent versions on the same system, in memory - and on disk. - When an application requests access to a library, it optionally specifies - the expected version, without which the latest is assumed. - This way, it is possible for the administrator to get rid of the obsolete - libraries but only after making sure that no applications require them - anymore. - While software is being developped, it becomes possible to have concurrent - versions of applications each using their respectively related material. -\layout Standard - - -\emph on -XXX -\layout Subsubsection - -The Xisop library -\layout Standard - - -\emph on -XXX -\layout Subsection - -Xisop system calls -\layout Standard - -System calls are different than normal functions in that they allow userspace - tasks to execute instructions which are normally only allowed to call in - supervisor mode, or in kernel space. - Moreover, system calls are currently uninterruptible in Xisop, which means - that the task is guaranteed to not be preempted while executing a system - call function, until it returned. - These are internally implemented using processor traps, by the port-specific - code. - However, the system call functions themselves are portable and part of - the Xisop common code. - Because Xisop does not use MMU facilities, system calls are very fast to - execute compared to on unix systems. - Xisop design attempts to require the less of these possible however, because - they also disable the scheduler when executing. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -struct\SpecialChar ~ -xisop_root\SpecialChar ~ -*sys_getroot(void) -\emph default - Permits a task to obtain the address of the main Xisop control structure, - where system lists are stored. - Obviously, if a task uses this information in any way, it has to be careful - not to disrupt Xisop activities. - It is recommended to disable the scheduler and/or interrupts where required - to access the information which that structure provides. - It is made for people who know Xisop inside out only. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sys_int_disable(void) -\emph default - This internally calls -\emph on -_splhigh() -\emph default - which ensures to mask all interrupts, including that of the preemptive - scheduler. - Precautions should be made about the calls used similarly to when disabling - the scheduler. - However, this call permits a task to completely take control over Xisop. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sys_int_enable(void) -\emph default - Internally calling -\emph on -_spl0() -\emph default -, this re-enables all interrupts. - -\emph on -XXX -\emph default - heh actually, can the -\emph on -_syscall() -\emph default - trap actually occur after a -\emph on -sys_int_disable() -\emph default -? Will need to check this out. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sys_idle(void) -\emph default - Permits to suspend the processor until the next trap, interrupt or exception - occurs. - This internally calls the -\emph on -_idle() -\emph default - processor-specific function. - This is mostly used by Xisop -\emph on -main() -\emph default - which is returned control to when no tasks are currently on the ready queue. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -sys_custom(void\SpecialChar ~ -*res,\SpecialChar ~ -void\SpecialChar ~ -(*func)(void\SpecialChar ~ -*,\SpecialChar ~ -void\SpecialChar ~ -*),\SpecialChar ~ -void\SpecialChar ~ -*args) -\emph default - A very special system call, allows user tasks to execute arbitrary code - in supervisor mode, uninterruptibly (scheduler will not preempt, but interrupts - can still take place). - -\emph on -func -\emph default - specifies the function to call, which will be passed -\emph on -res -\emph default - as the first argument and -\emph on -args -\emph default - as the second argument, which can be used by the function to acquire parameters - and return results. - -\emph on -res -\emph default - and -\emph on -args -\emph default - can be NULL when they are not needed. - Because Xisop attempts to be more useful to the programmer than to secure - the kernel against userland, this was beleived to be a very useful function, - where user tasks can create their custom system calls as required. -\layout Subsection - -Xisop general programming interfaces -\layout Standard - -In an attempt to keep the code unified and clean, multipurpose interfaces - were provided. -\layout Subsubsection - -Byte alignment macros -\layout Standard - -In -\emph on - -\emph default - the following macros are provided for byte alignment. -\layout Standard - -These macros permit object size related byte alignment: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -size_t\SpecialChar ~ -OALIGN_CEIL(size_t\SpecialChar ~ -v,\SpecialChar ~ -o) -\emph default - -\emph on -o -\emph default --aligns -\emph on -v -\emph default -. - This macro rounds -\emph on -v -\emph default - to the nearest larger unit as required. - -\emph on -o -\emph default - should be any native C or custom structure type, to which -\emph on -v -\emph default - should be aligned relative to. - -\emph on -v -\emph default - is not modified, the new value is returned. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -size_t\SpecialChar ~ -OALIGN_FLOOR(size_t\SpecialChar ~ -v,\SpecialChar ~ -o) -\emph default - -\emph on -o -\emph default --aligns -\emph on -v -\emph default -. - Unlike -\emph on -OALIGN_CEIL() -\emph default - this macro rounds to the nearest smaller unit as required. -\layout Standard - -And these macros permit byte size related alignment: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -size_t\SpecialChar ~ -BALIGN_CEIL(size_t\SpecialChar ~ -v,\SpecialChar ~ -size_t\SpecialChar ~ -s) -\emph default - This macro aligns -\emph on -v -\emph default - to the nearest larger unit relative to -\emph on -s -\emph default - size as required. - -\emph on -v -\emph default - is not modified, the new value is returned. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -size_t\SpecialChar ~ -BALIGN_FLOOR(size_t\SpecialChar ~ -v,\SpecialChar ~ -size_t\SpecialChar ~ -s) -\emph default - Very similar to -\emph on -BALIGN_CEIL() -\emph default -, but rounds -\emph on -v -\emph default - to the nearest smaller unit relative to -\emph on -s -\emph default - size as required. -\layout Subsubsection - -Byte order manipulation macros -\layout Standard - -In -\emph on - -\emph default - the following macros are provided for byte order/endian conversions. - These are most useful for network Remote Procedure Call implementations, - as well as for binary file formats which can be in network order so that - multiple architectures may easily use the same file format. - Depending on the native host byte order (the -\emph on -_ARCH_BIG_ENDIAN -\emph default - and -\emph on -_ARCH_LITTLE_ENDIAN -\emph default - definitions defined by processor-specific code), these will perform no - action where no conversion is necessary. - The network order should be used for transferring over networks or writing - to binary files, and actually corresponds to the native host byte order - on big endian architectures. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int16_t\SpecialChar ~ -BYTEORDER_NETWORK16(u_int16_t) -\emph default - Converts the specified 16-bit word to network order for sending through - the network or writing to a binary file. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int16_t\SpecialChar ~ -BYTEORDER_HOST16(u_int16_t) -\emph default - Converts the specified network order 16-bit word to native host order after - reading from a binary file or receiving through the network. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int32_t\SpecialChar ~ -BYTEORDER_NETWORK32(u_int32_t) -\emph default - Converts the specified 32-bit word to network order for sending through - the network or writing to a binary file. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int32_t\SpecialChar ~ -BYTEORDER_HOST32(u_int32_t) -\emph default - Converts the specified network order 32-bit word to native host order after - reading from a binary file or receiving through the network. -\layout Subsubsection - -Doubly linked lists -\layout Standard - -These macros, as well as the -\emph on -list_t -\emph default - and -\emph on -node_t -\emph default - types are defined in -\emph on - -\emph default - and -\emph on - -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_INIT(list_t\SpecialChar ~ -*list) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_APPEND(list_t\SpecialChar ~ -*list,\SpecialChar ~ -node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_INSERT(list_t\SpecialChar ~ -*list,\SpecialChar ~ -node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_INSERTAT(list_t\SpecialChar ~ -*list,\SpecialChar ~ -node_t\SpecialChar ~ -*atnode,\SpecialChar ~ -node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_SWAP(list\SpecialChar ~ -t\SpecialChar ~ -*dstlist,\SpecialChar ~ -list_t\SpecialChar ~ -*srclist,\SpecialChar ~ -node_t\SpecialChar ~ -*srcnode,\SpecialChar ~ -bool\SpecialChar ~ -insert) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_UNLINK(list_t\SpecialChar ~ -*list,\SpecialChar ~ -node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int32_t\SpecialChar ~ -DLIST_NODES(list_t\SpecialChar ~ -*list) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -node_t\SpecialChar ~ -*DLIST_TOP(list_t\SpecialChar ~ -*list) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -node_t\SpecialChar ~ -*DLIST_BOTTOM(list_t\SpecialChar ~ -*list) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -node_t\SpecialChar ~ -*DLIST_NEXT(node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -node_t\SpecialChar ~ -*DLIST_PREV(node_t\SpecialChar ~ -*node) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -DLIST_FOREACH(list_t\SpecialChar ~ -*list,\SpecialChar ~ -node_t\SpecialChar ~ -*iterator) -\layout Standard - - -\emph on -XXX -\layout Subsubsection - -Hash based fast lookup tables -\layout Standard - -The prototypes and types for these are defined in -\emph on - -\emph default - and -\emph on - -\emph default -. -\layout Standard - - -\emph on -XXX -\layout Subsubsection - -FIFO (First In, First Out) buffers -\layout Standard - -These macros as well as the default FIFO types are defined in -\emph on - -\emph default - and -\emph on - -\emph default -. -\layout Standard - - -\emph on -XXX -\layout Subsubsection - -LIFO (Last In, First Out / Stack) buffers -\layout Standard - -These macros as well as the default LIFO types are defined in -\emph on - -\emph default - and -\emph on - -\emph default -. -\layout Standard - - -\emph on -XXX -\layout Subsection - -Xisop source tree organization -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -doc/ -\emph default - This directory holds this file, as well as various notes of interest -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ -\emph default - Where all source resides -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/ -\emph default - All machine-independent Xisop source -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/kernel/ -\emph default - Xisop kernel main code -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/kernlib/ -\emph default - Xisop kernel main machine-independent libraries -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/library/ -\emph default - Xisop machine-independent shared libraries -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/device/ -\emph default - Xisop machine-independent devices -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/handler/ -\emph default - Xisop machine-independent handlers -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/common/task/ -\emph default - Xisop machine-independent resident tasks -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/processors/ -\emph default - Holds all processor-specific code -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/processors/m68k/ -\emph default - The Motorola m68k support (MC68000L8/L10) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/processors/m68k/kernlib/ -\emph default - m68k specific replacement functions for wanted standard machine-independent - kernlib ones (optional) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/ -\emph default - Holds all port-specific code, including boot loaders -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/ -\emph default - The Amiga port of Xisop code resides here -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/kernlib/ -\emph default - Amiga-specific replacement functions for wanted standard machine-independent - kernlib ones (optional) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/boot/ -\emph default - The Amiga-specific code to generate a bootable kernel -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/library/ -\emph default - Amiga-specific shared libraries (optional) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/device/ -\emph default - Amiga-specific devices (optional) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/handler/ -\emph default - Amiga-specific handlers (optional) -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/ports/amiga/task/ -\emph default - Amiga-specific resident tasks (optional) -\layout Subsection - -The build process -\layout Standard - -Here is described the way the Xisop source is built to create a binary kernel - image. - -\emph on -/bin/sh -\emph default - is also assumed to exist for the building process. - The convention for the script names are as follows: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/generic_makedefs.sh -\emph default - contains various sh functions and variables assigned to local utilities - which are required by all -\emph on -clean.sh -\emph default - scripts, and the main -\emph on -src/make.sh -\emph default - script. - Those scripts -\emph on -source -\emph default - this file to obtain the common information. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/makedefs.sh -\emph default - consists of a symbolic link to -\emph on -port/makedefs.sh -\emph default -, which contains the configuration information required to build the for - the target port system. - The paths to the various useful utilities are assigned to shell variables. - If functions need to be supplied for other build scripts, they also should - be defined here. - This file is sourced (included) by all other build scripts. - They all should use the variables supplied by this file when accessing - the cross-compile or local utilities. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/make.sh -\emph default - allows to fully compile the kernel to result in a kernel image. - Requires the target port name to be specified, as it also sets up required - symbolic links. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -src/clean.sh -\emph default - cleans the source tree, that is, deletes all files which may have been - created by the build process. -\layout List -\labelwidthstring 00.00.0000 - -* -\emph on -/make.sh -\emph default - The various sections described below will need such a script which should - perform the necessary steps to compile the section. - These -\emph on -source -\emph default - src/ -\emph on -makedefs.sh -\emph default - to know which commands to invoke and access useful -\emph on -/bin/sh -\emph default - macros.. -\layout List -\labelwidthstring 00.00.0000 - -* -\emph on -/clean.sh -\emph default - The sections also need such a script which is expected to delete all files - which the -\emph on -make.sh -\emph default - script counterpart creates. - These -\emph on -source -\emph default - -\emph on -src/generic_makedefs.sh -\emph default -. -\layout Paragraph - -Cleaning the whole source tree -\layout Standard - -The -\emph on -src/clean.sh -\emph default - script ensures to clean the whole source tree by calling the -\emph on -clean.sh -\emph default - script for each section, including all ports and processors. - The invoker is expected to be in the -\emph on -src/ -\emph default - directory. -\layout Paragraph - -Building the system -\layout Standard - -The -\emph on -src/make.sh -\emph default - script builds the entire system. - The main steps performed to compile the system are described as follows, - in order. -\layout Subsubsection - -Preliminary building process setup -\layout Standard - -The -\emph on -src/processor, -\emph default - -\emph on -src/port -\emph default - and -\emph on -src/makedefs.sh -\emph default - symbolic links should point to their corresponding -\emph on -src/processors/ -\emph default - and -\emph on -src/ports/ -\emph default - and -\emph on -src/ports//makedefs.sh -\emph default -. - These are setup depending on the target system for which Xisop is being - built. - Each of these (port and processor sections) supplies a -\emph on -support.h -\emph default - headerfile which should be sufficient for the rest of the kernel code to - access the functionality of the hardware specific code they provide. - Moreover, each of them will after building provide -\emph on -ar -\emph default - archives ( -\emph on -.a -\emph default - files) into their respective -\emph on -ar/ -\emph default - directory, resulting from their various object files, which will be sufficient - to link with the rest of the kernel code to achieve the end result. - The -\emph on -src/make.sh -\emph default - script creates these symbolic links when supplied with a valid -\emph on -target -\emph default - (using the -\emph on --t -\emph default - parameter). -\layout Standard - - -\emph on -src/make.sh -\emph default - also ensures to set the -\emph on -$SRCDIR -\emph default - environment variable to the absolute path to the current directory ( -\emph on -src/ -\emph default -), which should be used by other build scripts when compiling modules so - that -\emph on -#include -\emph default - directives in the source can locate the file using -\emph on --I -\emph default - parameter, etc. -\layout Subsubsection - -Building the processor-specific support code -\layout Standard - -Control is delegated to -\emph on -src/processor -\emph default -/ -\emph on -make.sh -\emph default -. - This is expected to assemble and compile the various sections it comports - to binary objects independently ( -\emph on -.o -\emph default -) using -\emph on --c -\emph default - parameter to -\emph on -gcc -\emph default - command, and to then archive them as -\emph on -ar -\emph default - archives into the -\emph on -src/processor/ar -\emph default - directory using the -\emph on -ar -\emph default - and -\emph on -ranlib -\emph default - commands. - This final object will be linked with the kernel code by another section - of the build process. - It is to be noted that it will be linked before the general common machine-inde -pendent kernel library, so that it is possible to provide processor-specific - replacements to standard low-level functions, such as -\emph on -memcpy() -\emph default -, -\emph on -memset() -\emph default -, etc. - These could however be overriden by the port-specific support code. - When control is given to -\emph on -make.sh -\emph default - of this section, the current directory will have been changed as well so - that it is safe to access the section files relatively to the current (section) - directory. -\layout Subsubsection - -Building the port-specific support code -\layout Standard - -Control is given to -\emph on -src/port/make.sh -\emph default - to compile this section, and very similarly to the processor-specific section, - the goal is to generate one or more -\emph on -ar -\emph default - archive in the -\emph on -src/port/ar -\emph default - directory. - -\emph on -src/port/support.h -\emph default - will also contain all necessary information for the rest of the kernel - code to use the port-specific support. - This code will be linked with the global kernel before s -\emph on -rc/processor/ar/*.a -\emph default -, which means that it is possible to provide port-specific standard functions - overriding the processor-specific ones, as well as kernel machine-independent - common ones. - This could allow for instance to provide -\emph on -memcpy() -\emph default - and -\emph on -memset() -\emph default - functions using specialized data moving hardware such as blitters, etc. - It is however recommended that libraries be built in a way to not force - the whole library to be included into the final kernel if only a few of - the functions were necessary. - To do this, a library could consists of a directory, with all functions - isolated in their own -\emph on -.c -\emph default - file. - The -\emph on -ar -\emph default - archive then results in a bunch of very small -\emph on -.o -\emph default - files which will be ignored by the linker when unrequired. - It is important to also run -\emph on -ranlib -\emph default - on the -\emph on -ar -\emph default - archive. -\layout Standard - - -\emph on -XXX -\emph default - -\emph on -Hmm I should find a nice way to define the resident libraries, devices and - handlers, both common and port-specific ones. - Also, which tasks should be initially started, etc. - Actually, resident devices and handlers, being tasks, would just need to - be included in the tasks to start, I guess... -\layout Standard - - -\emph on -XXX This next paragraph is currently invalid. -\layout Standard - -The -\emph on -ar/*.a -\emph default - result should also include -\emph on -_init_libraries() -\emph default -, -\emph on -_init_devices() -\emph default - and -\emph on -_init_handlers() -\emph default - functions, which should as required attach the wanted shared libraries, - devices and handlers in the kernel by calling their init function. - These also should initialize machine-independent ones. - If there are port-dependent ones, their code should be located into the - -\emph on -library/ -\emph default -, -\emph on -device/ -\emph default - and -\emph on -handler/ -\emph default - directories in -\emph on -src/port/ -\emph default -. -\layout Subsubsection - -Building the machine-independent main Xisop code -\layout Standard - -The -\emph on -src/common/kernlib/ -\emph default - directory comports a directory for each internal kernel library, which - each contain functions isolated into a single file each. - These are built separately as object modules, and are archived using -\emph on -ar -\emph default - and -\emph on -ranlib -\emph default - into -\emph on -src/common/kernlib/ar -\emph default -directory. - The reason for this is that it allows the resulting kernel image to be - smaller when not all of the functions of a particular library are used. - If all string functions were located into the same -\emph on -string.c -\emph default - file for instance, all of the string functions would automatically be linked - within the result even if only two string functions were actually used, - for instance. -\layout Standard - -The -\emph on -src/common/kernel/ -\emph default - and -\emph on -src/common/kernlib/ -\emph default - sections containing only portable C code are compiled, and their modules - archived with -\emph on -ar -\emph default - and -\emph on -ranlib -\emph default -, to -\emph on -src/common/kernel/ar/*.a -\emph default - and -\emph on -src/common/kernlib/ar/*.a -\emph default - files. - At current time, -\emph on -src/common/library/ -\emph default -, -\emph on -src/common/device/ -\emph default - and -\emph on -src/common/handler/ -\emph default - sections are all compiled and archived together as -\emph on -src/common/ar/*.a -\emph default -. - -\emph on -XXX This last statement is false as nothing is done for libraries, devices - and handlers at current time.. -\layout Subsubsection - -Linking the final kernel -\layout Standard - - -\emph on -src/common/kernel/kernel -\emph default -. -\emph on -a -\emph default -, -\emph on -src/port/support. -\emph default -a, -\emph on -src/processor/support.a -\emph default -, -\emph on -src/common/kernlib/kernlib.a -\emph default - and -\emph on -src/common/shared.a -\emph default - are linked together, in that order, into the ELF relocatable -\emph on -src/xisop.o -\emph default - file (using -\emph on --r -\emph default - option to ld). - This allows processor-specific libraries to replace -\emph on -common/kernlib -\emph default - functions, and port-specific ones to override both processor-specific and - common ones. -\layout Subsubsection - -Linking the final kernel and building the bootable Xisop result -\layout Standard - -After building both the machine dependent and independent sections described - above, the control is then left to -\emph on -src/port/boot/make.sh -\emph default -, after changing to the -\emph on -src/port/boot directory -\emph default -. - The role of this final script is to complete the linking and building process. - Here is what currently happens: -\layout Standard - -As a general rule, image_script.ld file in that directory comports the necessary - information to statically link monolithically the whole kernel as a binary - image. - Here is an excerpt of what -\emph on -src/ports/amiga/boot/make.sh -\emph default - does: -\layout Itemize - -show $C_COMPC -I$SRCDIR init.c -\layout Itemize - -A=`$L_LS ../../../common/kernel/ar/*.a ../ar/*.a ../../../processor/ar/*.a ../.. - /../common/kernlib/ar/*.a` -\layout Itemize - -show $C_LD -nostdlib -e _start -Ttext 0x005f8000 -o image.o init.o $A -\layout Itemize - -show $C_LD -T image_script.ld -nostdlib -o image.bin init.o $A -\layout Itemize - -... -\layout Standard - -The first operation compiles it's initialization code, which provides the - -\emph on -_start -\emph default - entrypoint, which eventually calls Xisop -\emph on -main() -\emph default -. - Then is compiled a list of the various -\emph on -ar -\emph default - archives which should be linked. - The order of these archives is important, as it permits the processor-specific - code to override the common code, and the port-specific code to override - the processor specific and common code. -\layout Standard - -Then follows the linking process, which is done two time. - The first instance creates -\emph on -image.o -\emph default - which can then be viewed and disassembled using the -\emph on -objdump -\emph default - utility. - This is mostly used for debugging so that at runtime in the emulator it - is possible to stop the emulation process and fall into the debugger, which - then discloses the current executing address. - That same address in image.o disassembly should match, and this is where - it can be handy. -\layout Standard - -The second linking command creates the binary Xisop kernel image using the - -\emph on -image_script.ld -\emph default - linker script, to result in -\emph on -image.bin -\emph default -. - This is the actual image, which expects to be loaded into memory at the - address 0x005f8000, and jumped to. - (See the -\emph on -image_script.ld -\emph default - and -\emph on -make.sh -\emph default - scripts for more information). -\layout Standard - -The script then proceeds to compile the disk boot loader (floppy in this - case), which is located into the -\emph on -bootf/ -\emph default - directory. - It then compiles the tools which are needed to assemble the result and - fix the bootblock checksum using the the local compiler (not the cross - compiler, although the same compiler could be used for both local and cross, - if the target and the build system are the same). - It finally uses those tools to create the final xisop.adf floppy image, - and advertizes the location of this file to the user. -\layout Standard - -Those last steps are very port-specific and are best done by someone with - a good amount of experience for the particular port to ensure that it works - right. - It is important to advertize the location of the final result to the user - at the very end. -\layout Section -\pagebreak_top -Hardware specific development notes -\layout Standard - -This chapter describes which hardware specific sections are required to - support Xisop. - They in fact provide the low-level glue which all the machine-independent - common code replies on. - As such, they should be small, effective, and as efficient and stable as - possible. - They should be well tested before releasing an official new Xisop port. -\layout Standard - -To aid in having a well organized source tree, and to prevent code duplication, - hence enhancing stability with time, the processor-specific and port-specific - sections have been separated into two. - Several ports may then take advantage of the same processor-specific code, - such as atomic locking primitives, which are known to work well, which - helps alot to speed up development. -\layout Subsection - -Microprocessor specific notes -\layout Subsubsection - -Required backend functions and support -\layout Standard - -Each processor is different but it is great to abstract most CPU-specific - functions into a standard set. - The headerfile which will be invoked by the common machine-independent - parts of the kernel to acquire support for the hardware specific functions - is -\emph on -processor/support.h -\emph default -, where -\emph on -processor -\emph default - will consist of a symbolic link to the actual -\emph on -processor -\emph default - directory in use in the -\emph on -processors -\emph default - directory. - Although the general organization of the processor specific code is implementat -ion dependent, it is important that -\emph on -support.h -\emph default - loads support for all necessary functions and data types which are processor-sp -ecific, and that -\emph on -ar/*.a -\emph default - be the only necessary modules to link with the rest of the kernel. -\layout Standard - -It is allowed if desired to also supply processor specific functions to - replace some of the common machine-independent ones, which may be desired - for speed at occasions. - When this is done, the functions should behave identically as expected, - should bear the same names, and no prototypes should be provided for them - in -\emph on -support.h -\emph default -. - The processor-specific code will be linked to the final kernel before the - common libraries and those functions will replace the machine-independent - ones then. - These functions could be for instance: -\emph on -memcmp() -\emph default -, -\emph on - memcpy() -\emph default -, -\emph on -memset() -\emph default -, etc. -\layout Standard - -Here are the various recommended functions which each CPU should support, - and make public to the rest of the kernel, at a minimum: -\layout Paragraph - -Context manipulation -\layout Standard - -The -\emph on -_ctx_t -\emph default - structure should be defined by the CPU-specific support headerfile and - should be used as an abstract type representing all required information - to save or restore a context, thus all registers, status register (SR), - stack pointer (SP), and program counter (PC). - The load and save context code sections are generally port-specific are - called from an interrupt, and as needed some care will be taken to save - the user stack pointer (USP) rather than the supervisor stack pointer (SSP), - as their purpose consist of task switching. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_ctx_init(_ctx_t\SpecialChar ~ -*context,\SpecialChar ~ -u_int32_t\SpecialChar ~ -*stack,\SpecialChar ~ -size_t\SpecialChar ~ -stacksize,\SpecialChar ~ -void\SpecialChar ~ -*start) -\emph default - Allows to create a new CPU context. - On some systems the stack grows downwards while upwards on others. - For this reason, the -\emph on -stacksize -\emph default - argument is used which permits to set the stack pointer as required, because - -\emph on -stack -\emph default - should be a pointer to the top of the stack. - -\emph on -start -\emph default - is a function pointer to the code to execute (stack startup address). - Usually, SP and PC are set accordingly in -\emph on -context -\emph default -, SR set to the current one, and other registers zeroed. - In some cases it may be good to also ensure to turn off the supervisor - bit from SR in the context, because user tasks are expected to run in userstate - processor mode. -\layout Paragraph - -Simple lock support -\layout Standard - - -\emph on -_lock_t -\emph default - should also be defined for abstraction, and help to perform various synchroniza -tion tasks. - These need not be symetric multiprocessor (SMP) safe, but they should at - least be atomic for the current processor. - Atomic in the sense that test-and-set must be performed at once to acquire - a lock. - If a processor does not allow to make this atomic, it is possible to provide - these by the port-specific code, in which case it could disable interrupts - (at least the scheduler interrupt) before performing it's tasks, so that - operations seem atomic in a multitasking environment. - These lock primitives should not be nestled or recursive, they are intended - for exclusive access. -\layout Standard - -In any case, all following lock primitives should be callable by normal - user tasks, which means that when required a trap can be used internally - to swich to supervisor mode if the processor requires to perform privileged - instructions to achieve the expected atomic behavior, both for -\emph on -_lock_t -\emph default - and -\emph on -_rlock_t -\emph default - primitives. - Fortunately, they can usually be implemented properly using normal instructions. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_init(_lock_t\SpecialChar ~ -*lock) -\emph default - Permits to initialize a -\emph on -_lock_t -\emph default - entity as required for future operations on this -\emph on -lock -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_acquire(_lock_t\SpecialChar ~ -*lock) -\emph default - Allows to obtain exclusive access on the supplied -\emph on -lock -\emph default -, or wait looping indefinitely until the lock could be obtained, in order - to obtain it as fast as possible. - It is important that this operation be atomic so that in the event of scheduled - context switching race conditions do not occur. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_lock_release(_lock_t\SpecialChar ~ -*lock) -\emph default - Should free the specified -\emph on -lock -\emph default -, which will enable any other requester to acquire the lock to obtain it. - This operation also should be atomic. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_lock_try(_lock_t\SpecialChar ~ -*lock) -\emph default - Attempts to obtain exclusive access to -\emph on -lock -\emph default -, returning TRUE/1 if it could obtain it immediately, or FALSE/0 if the - lock is already being held, in which case it also returns immediately. - It is important that this be implemented atomically, in a single test-and-set - instruction. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -bool\SpecialChar ~ -_lock_available(_lock_t\SpecialChar ~ -*lock) -\emph default - Verifies if -\emph on -lock -\emph default - is available. - This is not to be used to implement -\emph on -_lock_try() -\emph default -, it is used in situations where we only want to make sure that no lockers - currently own the lock, but that we still do not want to obtain it ourselves. - An example of this is where a lock is used as an ON/OFF switch, which can - be implemented using this mechanism, without disabling the event which - needs to access a resource, which may serve other functions but will skip - executing the critical code if the scheduler lock is held. - This is usually best implemented using recursive -\emph on -_rlock_t -\emph default - however, which will be described below. -\layout Standard - -The following locking primitives are different in that a lock may be locked - by any number of lockers, but has to be unlocked the same number of times - for the lock to become free again. - These are called recursive locks. - A useful example consists of the scheduler which wants to ensure that no - task disabled the scheduler temporarily before performing a context switch. - It then evaluates the lock using -\emph on -_rlock_available() -\emph default -, or -\emph on -_rlock_try() -\emph default - if it needs to prevent recursion, and only performs the switch if it is - (and hence the lock counter equals to 0, or 1). - It is recommended that the -\emph on -_rlock_t -\emph default - type consist of an -\emph on -int32_t -\emph default - (signed), but the processor-specific code is left to define it differently - if need be. -\layout Standard - -Although for several architectures C code can also be used to implement - these, it is a good idea to implement them in assembly because there is - no guarantee that the compiler will always use atomic increase and decrease - operations (GCC 2.95.3 at least seems to not always do so for m68k with C - macros, it often loads the value from the lock counter, increase it during - other processing and posts back the new value over the counter, instead - of always generating an atomic increment instruction which m68k is well - capable of). - Moreover, for some other architectures the use of an internal -\emph on -_lock_t -\emph default - or -\emph on -_splhigh() -\emph default - may be required to implement these properly, and if there are privileged - instructions required to implement these, a trap may be needed. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_init(_rlock_t\SpecialChar ~ -*rlock) -\emph default - Initializes -\emph on -rlock -\emph default - to 0. - This normally is rarely done except at system initialization, or lock creation. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_acquire(_rlock_t\SpecialChar ~ -*rlock) -\emph default - Atomically increases the -\emph on -rlock -\emph default - counter by one. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_release(_rlock_t\SpecialChar ~ -*rlock) -\emph default - Atomically decreases the -\emph on -rlock -\emph default - counter by one. - There is no need to perform any check against 0 in this function. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_try(_rlock_t\SpecialChar ~ -*rlock) -\emph default - Permits to atomically increase the -\emph on -rlock -\emph default - counter by one, and returns TRUE if the caller consists of the only locker - (in which case the lock counter should now be 1). - If the counter is higher, it means that more than one locker exists and - the function is then expected to decrease the counter atomically again, - and return FALSE. - This allows exclusive access to a recursive lock. - This function is both used by the scheduler and public interrupt facility - systems. - Because they want to make sure that noone holds the lock when they execute - their critical tasks, and that they also need to lock it to prevent potential - self-recursion, this call is a great facility to use. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_rlock_available(_rlock_t\SpecialChar ~ -*rlock) -\emph default - Returns TRUE if the -\emph on -rlock -\emph default - counter equals to 0, or FALSE otherwise (in which case there at least remains - one current locker). - This function is provided for callers which do not need to prevent possible - recursion, but only need to make sure that the lock is currently free. - Following -\emph on -_rlock_available() -\emph default - with -\emph on -_rlock_acquire() -\emph default - is not safe, and -\emph on -_rlock_try() -\emph default - should be used instead when this is desired. -\layout Paragraph - -Byte order conversion support -\layout Standard - -The processor-specific code needs to #define -\emph on -_ARCH_BIG_ENDIAN -\emph default - or -\emph on -_ARCH_LITTLE_ENDIAN -\emph default - in their -\emph on -support.h -\emph default - depending on their native byte order. - These will be used at a higher level in the libraries for the endian-conversion - functions between network (big endian) and host order (big or little endian). - These are most useful when saving a binary file format which needs to be - loadable by another processor of another endian order as well as in the - implementation of networking based Remote Procedure Calls, etc. - Moreover, the two following functions should be provided: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int16_t\SpecialChar ~ -_bswap16(u_int16_t) -\emph default - Swaps the order of the two bytes held in the supplied 16-bit word and returns - the result. - For instance, 0x1234 becomes 0x3412. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -u_int32_t\SpecialChar ~ -_bswap32(u_int32_t) -\emph default - Reverses the order of the four bytes held in the supplied 32-bit word and - returns the result. - For instance, 0x12345678 becomes 0x78563412. -\layout Paragraph - -String library optimizations support -\layout Standard - -Note that the following are not necessary to consider if a specially optimized - library functions for string and memory are implemented in assembly for - the architecture. -\layout Standard - -Every other architecture should -\emph on -#define -\emph default - the architecture-specific -\emph on -__ARCH_INT_BITS -\emph default - macro, which should be set to the native word size used by the particular - processor for int, using the compiler. - This should be expressed in bits, not in bytes. - The most common value is 32, but it can vary. -\layout Standard - -It is also important to -\emph on -#define -\emph default - the -\emph on -_ARCH_LOWCACHE -\emph default - macro (with no value), if it is beleived that loop unrolling is of no benefit. - This can be the case on architectures with very low instruction caches, - or ones which are using none. - If loop unrolling is wanted, this should not be defined. -\layout Standard - -The -\emph on -_ARCH_USEINDEXING -\emph default - macro also should be -\emph on -#defined -\emph default - with no value if it is beleived that the compiler generates better code - for this particular processor when using indexed instructions rather than - many post-increment/pre-decrement pointer based instructions. - For instance, the i386 processor has no such special support, and using - indexing can generate better code using GCC2. - For m68k, it is usually better not to use indexing. - Note that this is only taken in consideration if -\emph on -_ARCH_LOWCACHE -\emph default - is not defined, as it only affects loop unrolling of the C string and memory - library. -\layout Standard - -These definitions are expected to be found in the -\emph on -support.h -\emph default - file for every particular processor. -\layout Paragraph - -CPU-saving -\layout Standard - -On CPUs which support this, it is very useful to not hug the processor constantl -y in a loop where the only event that is awaited for consists of an interrupt. - On microprocessors which do not provide such a feature, it is safe to just - make this function do nothing. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_idle(void) -\emph default - Suspends execution of instructions by the current processor until the next - interrupt, trap or exception occurs. -\layout Paragraph - -Interrupt level control -\layout Standard - -Most microprocessors support several interrupt levels, where the higher - the level the better precedence of execution over others. - Manipulating the interrupt priority level (IPL) using Set Priority Level - functions becomes useful for critical code sections which need to disable - all interrupts at the specified level and under. - Although port-specific code attempts to provide it's own finer grained - interrupt control code when considered required, these should be available. - The -\emph on -_ipl_t -\emph default - type itself is left to be defined with -\emph on -typedef -\emph default - by the processor-specific code to the best variable type to hold the processor - IPL state. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_ipl_t\SpecialChar ~ -_spl -\emph default -n -\emph on -(void) -\emph default - Immediately sets the current priority level to the one specified by -\emph on -n -\emph default -. - Thus, functions such as -\emph on -_spl0() -\emph default -, -\emph on -_spl1() -\emph default -, -\emph on -_spl2() -\emph default -, etc should be provided, for each interrupt level. - -\emph on -_spl0() -\emph default - should enable all interrupt levels to occur. - The returned value serves to eventually restore the previous interrupt - level using -\emph on -_splx() -\emph default -, and is an abstract type defined by the processor-specific code. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_ipl_t\SpecialChar ~ -_splhigh(void) -\emph default - Usually a macro to the highest -\emph on -_spl -\emph default -n -\emph on -() -\emph default - function, it disables all interrupts by setting the highest priority level, - thus masking all interrupts. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_splx(_ipl_t\SpecialChar ~ -state) -\emph default - Permits to restore the previous interrupt priority level which was active - before a call to an -\emph on -_spl -\emph default -* -\emph on -() -\emph default - function was made, using the state value which was supplied by them. -\layout Subsubsection - -m68k -\layout Standard - -The Motorola MC68000L8 and MC68000L10 processors were the first to run Xisop. - No support for MMU is present, such memory management units usually come - on other external circuits for this processor, and there are various types. - As Xisop does not need MMU, those processors were an ideal target. - Although internally built as 16-bit processors, these processors behave - as 32-bit ones from the programming point of view. - It is also expected to run the same (or with minor modifications to disable - their MMU) on the other processors of the 680x0 family, which are fully - 32-bit. - The assembly code observes the following rules to properly work with GCC - compiled C modules: -\layout Itemize - -Stack pointer consists of A7/SP and frame pointer of A6/FP. - In supervisor mode, the user stack pointer consists of USP and specialized - instructions need to be used to access and manipulate it. -\layout Itemize - -Registers A0 and D0 serve the special purpose of return code for functions. - Where the C code expects A0 or D0 to be used depends on the function prototype - as seen from C. - Functions expected to return a pointer should do so in A0, and D0 is used - for other integer values. - Assembly functions expected to be called from C must have a C function - prototype defined in a headerfile which the C code must include. -\layout Itemize - -Assembly functions save all the registers they modify, and restore them - before returning. - As such, functions returning nothing (void) are expected to never return - with a different register state. - However, this is not always true of GCC generated code. - Of course, the D0 register in the case of integer returning functions, - and A0 for pointer returning ones should as expected modify the corresponding - register as well. - Registers to be saved are pushed on the stack, which grows upwards. -\layout Itemize - -Because there are various registers which GCC generated code modifies without - always saving, exception handlers save all general purpose registers A0-A6 - and D0-D7 registers, and restore them before returning with RTE. - It was a false assumption to previously only backup A0 and D0 which are - used as function return codes, and many problems occurred back then with - this attempt. -\layout Itemize - -When an assembly function calls a C function, it needs to push the arguments - in the stack, growing upwards, in reverse order, before calling it. - After the C function returned, the stack pointer should be updated by additioni -ng the number of bytes that were pushed. - In the case where 16-bit or 8-bit values are passed as arguments, GCC still - expects a stack entry of 32-bit size. -\layout Itemize - -An assembly function expected to be called from C must obtain the arguments - (if any) from the stack. - These are ordered growing downwards, as they were inserted in reverse order - in the stack, growing upwards. - Obviously, when registers are temporarily saved on the stack to preserve - their state and restore them before returning, the offset at which these - parameters are found on the stack changes, and the code has to account - for this. -\layout Itemize - -The -\emph on -_ctx_t -\emph default - manipulation functions had to be implemented as follows: -\emph on -_ctx_init() -\emph default - can be called from usermode and only creates a context with zero registers, - etc. - However, -\emph on -_yield() -\emph default - had to be implemented using a trap to execute in supervisor mode, and the - scheduler preemptive interrupt also executes in supervisor mode. - Both save the current context to -\emph on -root->curctx -\emph default -, call -\emph on -schedule() -\emph default - and load back the context from -\emph on - root->curctx -\emph default -, as expected. - They need to use privileged instructions to change SR (status register) - and USP (user stack pointer), because SR/A7 becomes the SSP (supervisor - stack pointer) when in supervisor mode. - To make sure to respect the PC (program counter) address of the contexts, - they are manipulated on the supervisor stack (SSP), where the m68k saves - them when jumping to the exception handler. - As such, RTE (return from exception) automatically jumps where it should - for the current context. - The offset to the SR 16-bit register is usually %sp@ and the one for PC - 32-bit one in %sp@(2) when initially intering the trap or interrupt exception. - This offset has to be recalculated as registers are being saved on the - stack, of course. -\layout Standard - -Other m68k specific notes about aspects which had to be taken in consideration: -\layout Itemize - -At kernel initialization, room for the supervisor stack pointer needs to - be setup, and the Supervisor Stack Pointer (SSP/A7) should be set properly. - To do this it is necessary to go in supervisor mode, and then set the A7 - register to the right address. - The way this must be done depends on the architecture. - Because at bootup ROM code may have taken control already and one must - use it's own facilities to obtain supervisor privileges. -\layout Itemize - -Dropping to user state from supervisor state to call Xisop -\emph on -main() -\emph default - is rather simple. - 1024 bytes are taken from the current SSP (A7), and assigned to the USP. - The supervisor bit in SR is then unset, and a jump to -\emph on -main() -\emph default - is made. - The function is very tiny and only ensures to launch the various initial - tasks, then waits forever in a loop using -\emph on -_idle() -\emph default - calls via -\emph on -sys_idle() -\emph default -. - It corresponds to the -\emph on -_scontext -\emph default - -\emph on -_ctx_t -\emph default - in -\emph on -root->curctx -\emph default - when no tasks are on the ready queue. - Such a small stack buffer is then safe. -\layout Itemize - -Using GCC 2.95.3, -O2 and -fomit-frame-pointer compilation directives seem - to generate both well optimized and small m68k code. - I however noted that using -fno-function-cse was also required with -O2, - without which the resulting code crashed. - -m68000 was used to generate true MC68000 code (no support for 020+ specific - instructions which wouldn't run on a plain 68000). -\layout Itemize - -Although m68k is very good to produce position-independent code, the default - output GCC produces still comports instructions using direct addressing, - except when -fpic is used, in which case additional symbols, with a .got - table need to also be in the code, even if m68k generally doesn't require - these for position-independent code (it has all the relative addressing - instructions required for large memory model). - As the only solution I found to properly relocate the code upon loading - would be to write an ELF or a.out loader, which isn't done yet, the kernel - code is loaded at a specific location, defined before compilation. - A GCC ld BFD backend will need to be written, or an ELF loader, to allow - to relocate the kernel, as well as file executable binaries. -\layout Itemize - -The -\emph on -_spl -\emph default -n -\emph on -() -\emph default - and -\emph on -_splhigh() -\emph default - functions were implemented as macros, calling the assembly -\emph on -_spl() -\emph default - function which takes a 16-bit argument (the new SR to apply). - -\emph on -_splx() -\emph default - assembly functions restores the previous SR. - As SR is 16-bit, the -\emph on -_ipl_t -\emph default - type was defined as an -\emph on -u_int16_t -\emph default - internally. - This allowed to generate very compact code for the eight interrupt priority - level control functions which m68k required. -\layout Itemize - -The -\emph on -_lock_ -\emph default -* -\emph on -() -\emph default - functions were implemented using the TAS instruction for atomicity, and - the -\emph on -_lock_t -\emph default - data type was internally defined as an -\emph on -u_int8_t -\emph default -. -\layout Itemize - -The -\emph on -_rlock -\emph default -* -\emph on -() -\emph default - functions could be implemented without the use of an internal -\emph on -_lock_t -\emph default - to guarrantee atomicity, because the m68k processor is capable of addition - and substraction on a 32-bit value in a single instruction. - An -\emph on -_rlock_t -\emph default - consists of a -\emph on -int32_t -\emph default - for this architecture. -\layout Itemize - -Before the port-specific code calls Xisop -\emph on -main() -\emph default -, it is necessary to switch back to user processor mode. - The -\emph on -_usermode() -\emph default - function was implemented for this and added to the m68k set of processor-specif -ic functions, which allows to create a 1024 bytes user stack from the current - supervisor stack, switches to usermode, and jumps to the specified function. -\layout Subsection - -Port specific notes -\layout Subsubsection - -Required backend and support functions -\layout Standard - -Each architecture needs a specific initialization section, such as setting - up exceptions, interrupts and memory. - Although this can also be CPU-specific, the various architectures using - the same processor would most likely still need these to be different. - They are thus considered as port-specific low-level backend support. - Similarly to the processor-specific support code, -\emph on -support.h -\emph default - and -\emph on -ar/*.a -\emph default - are the main targets that should be provided to allow the rest of the kernel - to use it, as it will include -\emph on -port/support.h -\emph default - and will link in -\emph on -port/ar/ -\emph default -*. -\emph on -a -\emph default -, where -\emph on -port -\emph default - consists of a symbolic link to the actual -\emph on -ports/ -\emph default - directory. -\layout Standard - -It is allowed if desired to also supply port specific functions to replace - some of the common machine-independent ones, which may be desired for speed - at occasions. - When this is done, the functions should behave identically as expected, - should bear the same names, and no prototypes should be provided for them - in -\emph on -support.h -\emph default -. - The port-specific -\emph on -ar/*.a -\emph default -modules will be linked before the processor-specific and Xisop common libraries - and those functions will replace them if they are supplied. - These functions could be for instance: -\emph on -memcmp() -\emph default -, -\emph on - memcpy() -\emph default -, -\emph on -memset() -\emph default -, etc. -\layout Standard - -After the kernel was built, using both common, processor and port code, - control is left again to the port specific code which should handle boot - support; This can be creating a floppy image, etc. - See the section on the building process for more information. -\layout Standard - -It is important that the port-specific code provides the -\emph on -_start -\emph default - entry point. - This code should then set the processor in supervisor mode where required, - setup the supervisor mode stack pointer, disable interrupts and perform - initialization of the various systems described below. - Afterwards, it should switch back to userstate processor mode, and leave - control to the Xisop -\emph on -main() -\emph default - function, which will not return. - That -\emph on -_start -\emph default - entry point is where the boot kernel loader needs to jump to. -\layout Paragraph - -Memory initialization and requirements -\layout Standard - -The port-specific -\emph on -support.h -\emph default - should define C enumerators (enum) and definitions (#define) for the machine-in -dependent Xisop memory code. - It is recommended to also read the section on Xisop memory management for - more information. - The port-specific requirements are explained as follows: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -#define\SpecialChar ~ -_PAGE_SIZE\SpecialChar ~ - -\emph default - The memory management system needs to know the amount of bytes in which - to split pages. - On operating systems which support Memory Management Units (MMU), this - is required to match the page size which the hardware requires. - In the case of Xisop, it is safe to use any reasonable multiple of 16 bytes - here. - A common -\emph on -_PAGE_SIZE -\emph default - is 4096 bytes. - On systems with very low memory it may be useful to use 1024, or even 256. - This value is used by the page memory allocation primitives. -\layout Standard - -The -\emph on -mpool_t -\emph default -, a multi-purpose memory pool which allows management primitives such as - -\emph on -_malloc() -\emph default - and -\emph on -_free() -\emph default -, requires specific definitions: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -#define\SpecialChar ~ -_MPOOLS\SpecialChar ~ - -\emph default - This is the number of internal -\emph on -pool_t -\emph default - which are necessary to initialize for an -\emph on -mpool_t -\emph default -, to be able to use these efficient pools when dealing with byte requirements - which are too small to be rounded at page boundaries. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -#define\SpecialChar ~ -_MPOOLSTART\SpecialChar ~ - -\emph default - The smallest amount of bytes which an -\emph on -mpool_t -\emph default - can allocate, which is multiplied by two for each consecutive -\emph on -pool_t -\emph default - initialized for the -\emph on -mpool_t -\emph default - at -\emph on -mpool_init() -\emph default -. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -#define\SpecialChar ~ -_MPOOLSTEP\SpecialChar ~ - -\emph default - The number of physical -\emph on -_PAGE_SIZE -\emph default - bytes pages into a -\emph on -page_t -\emph default - for every -\emph on -pool_t -\emph default - of an -\emph on -mpool_t -\emph default -. -\layout Standard - -To explain better the previous definitions, what the -\emph on -mpool_init() -\emph default - function actually does is iterate -\emph on -_MPOOLS -\emph default - times to initialize the -\emph on -pool_t -\emph default - objects, setting the first -\emph on -pool_t -\emph default - to allocate units of -\emph on -_MPOOLSTART -\emph default - bytes, the second -\emph on -_MPOOLSTART -\emph default - * 2, and continueing to iterate multiplying the unit size by two until - -\emph on -_MPOOLS -\emph default - number of -\emph on -pool_t -\emph default - were initialized. - Larger unit sizes which cannot be handled by the -\emph on -pool_t -\emph default - will be rounded at page boundaries. - -\emph on -_MPOOLSTEP -\emph default - simply consists of the -\emph on -stepp -\emph default - argument to -\emph on -pool_init() -\emph default -. - As such, all the definitions above intimately correlate to eachother, and - are quite versatile to match various requirements an architecture may need. -\layout Standard - -For a system with a -\emph on -_PAGE_SIZE -\emph default - of 4096 bytes, an -\emph on -_MPOOLSTART -\emph default - of 16 and -\emph on -_MPOOLSTEP -\emph default - of 1, 7 consists of an ideal value for -\emph on -_MPOOLS -\emph default -. - On a system with a fair amount of memory, if it is wanted to minimize calls - to the page management primitives even more, it is possible to set a larger - -\emph on -_MPOOLSTEP -\emph default - and raise -\emph on -_MPOOLS -\emph default - accordingly, while keeping the same underlaying -\emph on -_PAGE_SIZE -\emph default -. - Basically -\emph on -_MPOOLS -\emph default - should be set just below the -\emph on -pool_init() -\emph default - breaking point, where it returns FALSE because -\emph on -sizeof(mnode_t) -\emph default - plus the current -\emph on -_MPOOLSTART -\emph default - multiple consist of too large objects to fit into a -\emph on -pool_t -\emph default - page (which in turn depends on -\emph on -_MPOOLSTEP -\emph default - which changes the -\emph on -page_t -\emph default - size for a -\emph on -pool_t -\emph default -). -\layout Standard - -It is recommended to read the source for -\emph on -mpool_init() -\emph default - which is located in -\emph on -src/common/kernel/memory.c -\emph default - for a better understanding, as well as the documentation on Xisop memory - management primitives. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -enum\SpecialChar ~ -_memtypes -\emph default - This enumeration should define the various memory types the architecture - provides, in preference order when -\emph on -_MEM_ANY -\emph default - is used (-1) when calling the allocation primitives. - The enumeration should set -\emph on -_MEM_ -\emph default -* names, the first one corresponding to 0, and the last element should consist - of -\emph on -_MEM_MAX -\emph default -, corresponding to the number of memory types the system provides. - Not all architectures provide more than a single memory type, under which - case -\emph on -_MEM_ALL -\emph default - will correspond to 0 and -\emph on -_MEM_MAX -\emph default - to 1, respectively. -\layout Standard - -Other than defining these requirements in it's -\emph on -support.h -\emph default - headerfile, the port-specific initialization code is responsible for attaching - the available physical memory pages to the system pools, before initializing - the public interrupt facilities. - This is done by first calling the -\emph on -memory_init() -\emph default - machine-independent function. - Then, the -\emph on - mchunk_init() -\emph default - and -\emph on -mchunk_attach() -\emph default - functions which are documented in the Xisop memory management section are - normally called once for each contiguous memory area which is to be used - as general purpose memory. - The video memory, or other special memory sections should not be included - in the system memory pools. - It is important to perform this step before continuing on with the next - initialization sections. - The -\emph on -mchunk_init() -\emph default - and -\emph on -mchunk_attach() -\emph default - functions are described in detail in the Xisop memory management section. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -memory_init(void -\emph default -) This function is only called once by the port-specific initialization - code before starting to attach memory chunks to the system pools. - After this function executes, it becomes possible to use the -\emph on -mchunk_init() -\emph default - and -\emph on -mchunk_attach() -\emph default - functions to attach contiguous memory regions to the system page pools. -\layout Paragraph - -Exceptions initialization and public interrupt facilities -\layout Standard - -It is recommended to maintain an -\emph on -_interrupt_depth -\emph default - variable or recursive lock, which each trap or interrupt handler should - increase at startup and decrease before returning, which can be used for - the scheduler interrupt to determine if it should call -\emph on -schedule() -\emph default - or not. - As the scheduler timer interrupt would also raise it at startup, it can - then mask interrupts and evaluate if it equals 1 afterwards, in which case - it is sure to have the right to perform a context switch. - This permits to make system calls uninterruptible for the time of their - execution and to protect the scheduler from performing context switches - while an interrupt handler is executing, which at occasions could result - in recursivity and context corruption. - As an effort is made to minimize the number of system call traps required - during normal Xisop function, the preemptive nature of the scheduler is - not bothered by having uninterruptible system calls, unless a task voluntarily - abuses -\emph on -sys_custom() -\emph default -, which is by all meals legal if one wants to. -\layout Standard - -Obviously, most exception handlers are responsible to return with the registers - unchanged, and as such should normally save all general-purpose registers - on the stack at startup, and return them before returning. - This is especially true if C functions are to be called from the interrupt - handler, where unexpected registers may be tempered with. -\layout Standard - -After setting up the memory, the public interrupt facilities can be defined - to the system and their internal handler vectors setup. - Usually, -\emph on -facilities_init() -\emph default - will be called before vectors are initialized, or if not possible, dummy - do-nothing vectors can be installed, and can then be setup definitely after - calling f -\emph on -acilities_init() -\emph default -, when it becomes safe. -\layout Standard - -This function call depends on the -\emph on -enum _facilities -\emph default - C enumerator which should be defined in the port specific -\emph on -support.h -\emph default - headerfile. - This enumerator defines each facility in the form of -\emph on -_FACILITY_ -\emph default -*, where * consists of the name of the facility. - The first entry should evaluate to 0, and the last one to the total number - of facilities ( -\emph on -_FACILITY_MAX -\emph default -). - The various interrupt handlers need to internally call -\emph on -facility_exechooks() -\emph default - on the facility they are serving for the public facilities to become alive. - At it's discretion, the handler may temporarily disable the interrupt source - when calling the function, but -\emph on -facility_exechooks() -\emph default - internally performs recursion prevention and makes sure to not execute - the hooks if a hook is currently being inserted or removed, using an -\emph on -_rlock_t -\emph default - for each facility internally. -\layout Standard - -There only is at least one facility which is required for all ports to provide. - This facility should be named -\emph on -_FACILITY_SCHEDTIMER -\emph default -, and should call the hooks at -\emph on -_SCHEDTIMER_HZ -\emph default - frequency, which should also be defined by the port-specific -\emph on -support.h -\emph default -. - This way, simple time-based Xisop applications can work portably on all - ports. - This facility should correspond to the timer interrupt which the port chose - to use for the preemptive scheduler timer. - This facility does not interfere with the scheduler activities; it is called - when the interrupt occurs even if the scheduler -\emph on -rlock_t -\emph default - is set ( -\emph on -schedule() -\emph default - handles the scheduler locked/disabled case already). - Generally, the scheduler interrupt handler works as follows: -\layout Itemize - -Increase the global -\emph on -_interrupt_depth -\emph default - variable like for all handlers -\layout Itemize - -Temporarily disable the interrupt source (by raising the IPL using -\emph on -_spl -\emph default -* -\emph on -() -\emph default - or otherwise) to prevent any possible recursion or other interruption. -\layout Itemize - -Save the current user CPU context to the -\emph on -root->curctx _ctx_t -\layout Itemize - -Execute the facility hooks using -\emph on -facility_exechooks(_FACILITY_SCHEDTIMER) -\layout Itemize - -Verify if the -\emph on -_interrupt_depth -\emph default - variable equals to 1. - If so, call -\emph on -schedule(NULL) -\emph default -, which may or may not change the -\emph on -root->curctx -\emph default - backed up context pointer and -\emph on -root->curtask -\layout Itemize - -Load back the CPU context from the new -\emph on -root->curctx -\emph default - (which possibly can be the same, but this must not be assumed) -\layout Itemize - -Re-enable the scheduler interrupt source -\layout Itemize - -Decrease the global -\emph on -_interrupt_depth -\emph default - variable like for other handlers -\layout Itemize - -Return from interrupt handler while ensuring to jump to the PC of the new - context. - Generally, the address to return to is backed up into the supervisor stack, - which needs to be modified for this. - That address within the supervisor stack pointer is where context save - and load operations obtain and set the Program Counter address. -\layout Standard - -Because of the context load/save operations, and return address hack, the - scheduler interrupt handler is usually implemented entirely in assembly - (although it calls the -\emph on -schedule() -\emph default - and -\emph on -facility_exechooks() -\emph default - C functions). -\layout Standard - -The other facilities, which are optional and can be provided by the port-specifi -c code will often be implemented as a mix of assembly and C code and will - similarily at least: -\layout Itemize - -increase global -\emph on -_interrupt_depth -\emph default - and optionally disable interrupt source -\layout Itemize - -save registers -\layout Itemize - -perform any additional wanted operation -\layout Itemize - -call -\emph on -facility_exechooks() -\emph default - on their facility -\layout Itemize - -restore registers -\layout Itemize - -re-enable the interrupt source if it was temporarily disabled, and decrease - global -\emph on -_interrupt_depth -\layout Itemize - -return -\layout Standard - -The facility public interface and -\emph on -facility_exechooks() -\emph default - are described in more details in the Xisop public facilities section. -\layout Paragraph - -System trap triggers and handlers initialization -\layout Standard - -It is important for the port-specific code to define the -\emph on -_syscall() -\emph default - and -\emph on -_yield() -\emph default - functions. - The role of the system call trap handler is to serve system call functions - uninterruptibly, internally calling -\emph on -_scatch() -\emph default - Xisop common function with the requested arguments. - Here is described the trigger, which function should be supplied by the - port-dependent code: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_syscall(u_int32_t\SpecialChar ~ -function,\SpecialChar ~ -void\SpecialChar ~ -*res,\SpecialChar ~ -void\SpecialChar ~ -*args) -\emph default - Internally places the supplied parameters into a static buffer or in registers, - and generate a processor trap interrupt. - It is safe to save the registers we modify on the stack, and restore them - from the stack after the trap returns, and then return ourselves, because - nor -\emph on -_yield() -\emph default - nor context switching are implemented via syscalls. - Although the understanding of the arguments is not necessary at this point, - -\emph on -function -\emph default - specifies the syscall number which is to be performed, -\emph on -res -\emph default - a pointer to eventual results expected from that system call (or NULL), - and -\emph on -args -\emph default - optional arguments which need to be passed to the system call (or NULL). - Although this function is also highly processor-specific, the choice of - the trap vector to implement system calls is left to the port writer, and - as such this function as well. -\layout Standard - -The other end, consisting of the system call trap handler, is responsible - for the following: -\layout Itemize - -Increment -\emph on -_interrupt_depth -\emph default - global variable -\layout Itemize - -Save all general purpose registers -\layout Itemize - -Read arguments supplied by -\emph on -_syscall() -\emph default - from the static buffer or registers, and insert them on the stack as C - arguments, then call -\emph on -_scatch() -\emph default - C function. - Fix the stack pointer to forget the pushed stack arguments. -\layout Itemize - -Restore general purpose registers we saved -\layout Itemize - -Decrement -\emph on -_interrupt_depth -\emph default - global variable -\layout Itemize - -Return -\layout Standard - -The -\emph on -_scatch() -\emph default - function (which is defined in -\emph on -src/common/kernel/syscall.c -\emph default -) is responsible for performing the necessary sanity checking on the arguments, - and does not need to be provided by the machine-specific code: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_scatch(u_int32_t\SpecialChar ~ -function,\SpecialChar ~ -void\SpecialChar ~ -*results,\SpecialChar ~ -void\SpecialChar ~ -*arguments) -\emph default - Consists of the heart of the syscall trap. - -\emph on -function -\emph default - specifies the requested syscall function number which was called. - These are standard and are described in the -\begin_inset Quotes eld -\end_inset - -System Calls -\begin_inset Quotes erd -\end_inset - - section. - -\emph on -results -\emph default - consists of a pointer to the block of memory which will be modified to - store the syscall results by this -\emph on -function -\emph default -. - It can be NULL. - -\emph on -arguments -\emph default - similarly specifies the location of the arguments expected for this -\emph on -function -\emph default -, or NULL. - This function refuses to perform any call if the supplied -\emph on -function -\emph default - is invalid (out of bounds). -\layout Standard - -After setting up the -\emph on -_syscall() -\emph default - trap vector, the interrupts can remain disabled/masked still, like since - the beginning. - More information on the generic user system calls interface is provided - in the Xisop system calls section. -\layout Standard - -Another requirement that the port-specific code must satisfy consists of - the -\emph on -_yield() -\emph default - internal function: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -_yield(task_t\SpecialChar ~ -*task) -\emph default - permits the current task to immediately perform a context switch to another - task, in fact preempting itself. - -\emph on -task -\emph default - is an optional preference of which task to switch to, or NULL, which parameter - should be passed when the trap handler internally calls -\emph on -schedule() -\emph default -. - This is usually implemented in the form of a trap like for -\emph on -_syscall() -\emph default -, which sets the supplied argument in a static buffer to prevent modifying - a register (it is unsafe to save registers on the stack as we most likely - won't be the next task to return from the trap). - The backend trap handler acts as follows: -\layout Itemize - -Increase the global -\emph on -_interrupt_depth -\emph default - variable like for all handlers -\layout Itemize - -Temporarily disable all interrupt sources (by raising the IPL using -\emph on -_splhigh() -\emph default - or equivalent to prevent any possible interruption, but without modifying - registers, which can be saved and restored safely before performing the - next steps -\layout Itemize - -Save the current user CPU context to the -\emph on -root->curctx _ctx_t -\layout Itemize - -Insert the supplied argument from the static buffer in the stack as a C - argument -\layout Itemize - -Call -\emph on -schedule() -\emph default -, which may or may not change the -\emph on -root->curctx -\emph default - backed up context pointer and -\emph on -root->curtask -\layout Itemize - -Adjust stack pointer to forget the passed argument -\layout Itemize - -Load back the CPU context from the new -\emph on -root->curctx -\emph default - (which possibly can be the same, but this must not be assumed) -\layout Itemize - -Re-enable interrupts calling -\emph on -_spl0() -\emph default - or performing equivalent taking care not to modify registers. - Using the stack is now safe. - (remember that the old level obtained from -\emph on -_splhigh() -\emph default - cannot be obtained back unless saved to a static buffer, in which case - it can be restored properly. - Saving it on the stack is also safe if the context switching function only - modified the user stack pointer and the supervisor stack pointer consists - of the active stack during the trap). -\layout Itemize - -Decrease the global -\emph on -_interrupt_depth -\emph default - variable like for other handlers -\layout Itemize - -Return from interrupt handler while ensuring to jump to the PC of the new - context. - Generally, the address to return to is backed up into the supervisor stack, - which needs to be modified for this. - That address within the supervisor stack pointer is where context save - and load operations obtain and set the Program Counter address. -\layout Paragraph - -Suggestions -\layout Standard - -The rest of the port-specific code internals which it needs to perform are - left to the implementor, as long as they suit well the purpose. - However, a few suggestions are made which can help to keep some consistency - among the various ports, in their choice of function names for instance. - This example attempts to restrict the assembly code to the minimum, while - calling C functions as much as possible to handle most exception code. -\layout Standard - -It is generally a good idea for hardware interrupts to provide one separate - assembly handler per interrupt level, to prevent the C code from having - to perform unnecessary additional conditional instructions to evaluate - the level, as it already usually needs to detect the source. - For other general-purpose trap vectors, it is allowed to provide support - to execute a single C function for all of them, passing in an argument - the required information on the trap vector number. - This however would be less desireable than having a different facility - for each, if their frequency was high and a large number of hooks were - attached, because they then would obviously all run often, evaluating one - by one if they are interested in the trap. - Suggestion names for various common facility types are shown in the Xisop - public interrupt facilities section. -\layout Standard - -It is to be noted that the timer interrupt chosen to be used as the preemptive - scheduler one is special as it needs to perform context switching, often - also implying stack pointer access and modifications. - This handler is therefore usually fully written in assembly, as previously - demonstrated. - As a general rule, the role of the exception vectors is to call a C function - which can then handle the event. -\layout Standard - -Here are various C functions which can be called by the machine language - backend to exceptions, traps and interrupts: -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_icatch -\emph default -n -\emph on -(void) -\emph default - For every hardware interrupt level, une such C function can be called. - For interrupt level 3, -\emph on -icatch3() -\emph default - would be called, for instance. - It is possible to pass parameters if required to detect the interrupt source - in the C functions. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_tcatch(int\SpecialChar ~ -vector) -\emph default - This C function can be called for all software traps which occur that do - not correspond to the syscall or yield trap vectors. - -\emph on -vector -\emph default - argument specifies the number of the trap vector. -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_ecatch(int\SpecialChar ~ -vector) -\emph default - A C function called when an hardware exception is generated, such as bus - error, division by zero, etc. - It is recommended that the code processing these do not hang or crash the - system permanently if high-reliability is required. - -\emph on -vector -\emph default - consists of the exception vector, or reason which caused it, and -\emph on -stack -\emph default - points as usual to the retrurn from exception address on the stack. - Although this is CPU-specific, port-specific exception handling code may - be provided. -\layout Paragraph - -Port-specific system shared libraries to attach and system tasks to launch -\layout Standard - -Although Xisop has a few common portable system libraries and tasks which - it initializes at startup, it is ideal for the port-specific section to - be able to describe which other tasks should be launched, and their parameters - such as priority level, stack size, etc. - To do this the port-specific code needs to provide the -\emph on -_port_init() -\emph default - function which the Xisop init task will invoke and which then can use the - required flexibility. - It should be noted that as the init task only has a 4096 bytes stack, this - function is expected to at least create a task with a larger stack if it - needs to before performing it's own initialization if it overuses the stack. - The kernel expects the current state to remain the same when the function - returns (apart of course from the new libraries and tasks which may now - exist and be resident). -\layout List -\labelwidthstring 00.00.0000 - - -\emph on -void\SpecialChar ~ -_port_init(void) -\emph default - Port-specific function who's purpose is to attach the wanted port-specific - libraries, and to launch the wanted port-specific tasks. - This function is called by the Xisop -\emph on -init -\emph default - task which runs with a stack of 4096 bytes, and runs in userstate mode - like normal tasks. -\layout Paragraph - -Last steps of the port-specific initialization code -\layout Standard - -After switching to supervisor mode, setting up memory, system call and yield - traps, as well as scheduler timer interrupt, and initializing the public - interrupt facilities, port-specific initialization code is then complete, - and it now should execute the following steps: -\layout Itemize - -Call the machine-independent -\emph on -xisop_init() -\emph default - function, which sets up various internal structures and disables the scheduler, - and then internally calls -\emph on - _spl0() -\emph default - as interrupts finally become safe to enable. -\layout Itemize - -Call the famous Xisop machine-independent -\emph on -main() -\emph default - function which is expected to never return. - If the processor currently runs into supervisor mode, it is necessary to - drop to usermode before calling -\emph on -main() -\emph default -. - The role of this function is to enable the scheduler, launch the Xisop - -\emph on -init -\emph default - task, which in turn will make sure to launch the -\emph on -task reaper -\emph default - task, and call the port-dependent -\emph on -_port_init() -\emph default - function which then can also attach and launch the wanted resources. -\newline -Note that the -\emph on -main() -\emph default - function with it's current stack becomes the initial context that the scheduler - always switches to when there remains no tasks in the ready queue to run. - As such, after launching the init task, it loops forever calling -\emph on -sys_idle() -\emph default - system call which internall calls processor-specific -\emph on -_idle() -\emph default -, which permits the processor to stop spinning until the next interrupt - or trap event occurs. -\layout Subsubsection - -Amiga -\layout Itemize - -The Amiga port uses the -\emph on -processors/m68k -\emph default - processor-specific code. -\layout Itemize - -In addition to the m68k -\emph on -_spl -\emph default -* -\emph on -() -\emph default - functions, the amiga low level library also supplies -\emph on -aspl -\emph default -* -\emph on -() -\emph default - functions using INTENA control register for finer grained control to disable - certain interrupts for a period of time. - For instance, -\emph on -asplvblank() -\emph default - disables the vertical blank interrupt, -\emph on -asplsched() -\emph default - disables the scheduler, etc. - -\emph on -asplx() -\emph default - is used to restore the previous state, as usual. - For -\emph on -asplsched() -\emph default -, a -\emph on -_lock_t -\emph default - is used to turn the scheduler ON/OFF, so that the timer interrupt it ties - to still can execute other code if required. - -\emph on -XXX -\layout Itemize - -The chosen -\emph on -_syscall() -\emph default - trap vector was 0. -\layout Itemize - -The chosen -\emph on -_yield() -\emph default - trap vector was 1. -\layout Itemize - -The Amiga has four multi-purpose timers in it's two CIA chips. - The use Xisop currently makes of them is as follows: CIA-A TimerA is reserved - for keyboard timing, which is a hardware requirement. - CIA-B Timer A is used by the Xisop scheduler, which generates high-level - hardware interrupts of high priority (IPL 6). - The B timers and TOD counters are unused and remain available for devices - and user code for each CIA. -\layout Itemize - -The two memory page pools ( -\emph on -ppool_t -\emph default -) initialized at startup by -\emph on -_init_memory() -\emph default - consist of one for CHIP RAM, and another one for FAST RAM. - The -\emph on -enum _memtypes -\emph default - as such set -\emph on -_MEM_FAST -\emph default - to 0 and -\emph on -_MEM_CHIP -\emph default - to 1, FAST memory being the prefered if -\emph on -_MEM_ANY -\emph default - is used. - Currently, the addresses mapped in the standard distribution are 0x - 0x - for CHIP (enhanced 2 megabytes agnus chip (fatter)), and 0x00200000-0x00600000 - for FAST (usual 4 first megabytes of ZorroII memory found on A2000). - This currently needs to be modified in the code itself as the booting process - currently does not detect the available RAM amounts. - The provided UAE Amiga Emulator configuration file which is configured - as such can be located in the -\emph on -src/ports/amiga/boot -\emph default - directory. - -\emph on -XXX -\layout Itemize - -To setup the initial supervisor stack, the AmigaOS SuperState() exec.library - call must be used to gain supervisor privileges. - The SSP/A7 register can then be set to the proper location. - To do this a special function is provided in assembly by the Amiga support - library, -\emph on -void\SpecialChar ~ -_supervisor(u_int32_t\SpecialChar ~ -*sp,\SpecialChar ~ -size_t\SpecialChar ~ -ssize\SpecialChar ~ -void (*func)(void)) -\emph default - which allows to set the new entry point function and stack. - To the provided -\emph on -stack -\emph default - pointer will be additionned the supplied stack size -\emph on -ssize -\emph default - automatically because of the stack which grows upwards. - The supplied function -\emph on -func -\emph default - is then given control to. - This function is expected to never return. -\the_end diff --git a/Xisop/src/clean.sh b/Xisop/src/clean.sh deleted file mode 100755 index 2576fa9..0000000 --- a/Xisop/src/clean.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ./generic_makedefs.sh - -show cd processors/m68k -./clean.sh -show cd ../../ports/amiga -./clean.sh -show cd boot -./clean.sh -show cd ../../../common -./clean.sh -show cd .. -show $L_RM processor port makedefs.sh diff --git a/Xisop/src/common/clean.sh b/Xisop/src/common/clean.sh deleted file mode 100755 index 76a9ead..0000000 --- a/Xisop/src/common/clean.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../generic_makedefs.sh - -show cd kernlib -./clean.sh -show cd ../kernel -./clean.sh -show cd .. diff --git a/Xisop/src/common/kernel/clean.sh b/Xisop/src/common/kernel/clean.sh deleted file mode 100755 index d386a45..0000000 --- a/Xisop/src/common/kernel/clean.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../generic_makedefs.sh - -cleanlib . -show $L_RM ar/*.a diff --git a/Xisop/src/common/kernel/debug.c b/Xisop/src/common/kernel/debug.c deleted file mode 100644 index 976e387..0000000 --- a/Xisop/src/common/kernel/debug.c +++ /dev/null @@ -1,408 +0,0 @@ -/* $Id: debug.c,v 1.3 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include - - - -#ifdef DEBUG - - - -static fifo8_t fifo; -static u_int8_t *fifobuf; - - - -static size_t btoa(char *, u_int32_t); -static size_t dtoa(char *, int32_t); -static size_t utoa(char *, u_int32_t); -static size_t xtoa(char *, u_int32_t); -static void fifowrite(const char *, size_t); - - - -static const char ddigits[] = "0123456789"; -static const char xdigits[] = "0123456789ABCDEF"; - - - -void debug_init(void) -{ - fifobuf = MALLOC(DEBUG); - FIFO_INIT(&fifo, fifobuf, DEBUG); - root->debugfifo = &fifo; - _lock_init(&root->debuglock); - /* Not ideal but considerably reduces kernel size compared to a static - * array buffer. Has the disadventage that debugging is only available - * after memory initialization. - */ - debug_printf("Xisop debugging enabled\n"); -} - - -void debug_printf(const char *fmt, ...) -{ - debug_va_list ap; - register char c; - register const char *ptr = fmt, *optr; - - if (ptr == NULL) - return; - - lock_acquire(&root->debuglock); - - debug_va_start(ap, fmt); - optr = ptr; - while ((c = *ptr++) != '\0') { - if (c == '%') { - ptr--; - /* Output pending chars */ - if (optr < ptr) - fifowrite(optr, ptr - optr); - ptr++; - /* "%\0" ! */ - if ((c = *ptr++) == '\0') { - ptr--; - break; - } - - /* Process debug_va_arg */ - switch (c) { - case '%': - ptr--; - break; - case 'B': /* Boolean */ - { - register bool t = debug_va_arg(ap, bool); - - if (t) - fifowrite("TRUE", 4); - else - fifowrite("FALSE", 5); - } - break; - case 'b': /* Binary 32-bit */ - { - char buf[34]; - - btoa(buf, debug_va_arg(ap, u_int32_t)); - fifowrite(buf, 33); - } - break; - case 'c': /* Character */ - { - char ch = debug_va_arg(ap, char); - - fifowrite(&ch, 1); - } - break; - case 'd': /* 32-bit decimal */ - { - char buf[12]; - size_t len; - - len = dtoa(buf, debug_va_arg(ap, int32_t)); - fifowrite(buf, len); - } - break; - case 'p': /* 32-bit pointer */ - { - char buf[11]; - register void *p = debug_va_arg(ap, void *); - - if (p != NULL) { - xtoa(buf, (u_int32_t)p); - fifowrite(buf, 10); - } else - fifowrite("NULL", 4); - } - break; - case 's': /* String */ - { - register const char *s = debug_va_arg(ap, char *); - - if (s != NULL) - fifowrite(s, strlen(s)); - else - fifowrite("", 6); - } - break; - case 'T': /* Current task and PC address, no va_arg() */ - { - register task_t *t = CURTASK(); - register void *pc = root->curctx->pc; - char str[24]; - register char *ptr = str; - - *ptr++ = '['; - xtoa(ptr, (u_int32_t)t); - ptr += 10; - *ptr++ = '.'; - xtoa(ptr, (u_int32_t)pc); - ptr += 10; - *ptr++ = ']'; - *ptr = '\0'; - fifowrite(str, 23); - } - case 'u': /* 32-bit unsigned decimal */ - { - char buf[11]; - size_t len; - - len = utoa(buf, debug_va_arg(ap, u_int32_t)); - fifowrite(buf, len); - } - break; - case 'x': /* 32-bit hexadecimal */ - { - char buf[11]; - - xtoa(buf, debug_va_arg(ap, u_int32_t)); - fifowrite(buf, 10); - } - break; - default: /* Display %, it's a bug, and we debug! */ - { - char s[2]; - - s[0] = '%'; - s[1] = c; - fifowrite(s, 2); - } - break; - } - /* Adjust optr for our pending chars record */ - optr = ptr; - } - } - debug_va_end(ap); - - /* Any pending chars remaining? */ - if (optr < ptr) - fifowrite(optr, ptr - optr); - - _lock_release(&root->debuglock); -} - - -/* XXX Need to work on stdarg-like system and vsnprintf() instead of everything - * in debug_printf(). -void dprintf2(const char *file, const char *function, u_int32_t line, - const char *fmt, ...) -{ - debug_printf("%s:%s():%d - %s", file, func, line); -} -*/ - - - -/* This function writes into the debug FIFO buffer in a way to cause automatic - * recycling so that the last DEBUG bytes will always be available in the - * history until read. We do not use the lock here, because we only want - * full lines to be recorded, we let debug_printf() do it. - */ -static void fifowrite(const char *buf, size_t len) -{ - register fifo8_t *f = &fifo; - - while (len > 0) { - FIFO_PUT(f, buf); - buf++; - len--; - } - - /* XXX This would be more efficient if it worked :) I need to debug this. - if (len == 1) - FIFO_PUT(f, buf); - else { - u_int8_t *ptr; - size_t size; - register size_t l = len; - - if ((size = FIFO_AVAIL(f)) < l) { - l -= size; - - while (size ) XXX; - size = l; - FIFO_FREE(f, &ptr, &size, l); - } - - while (l > 0) { - FIFO_ALLOC(f, &ptr, &size, l); - memcpy(ptr, buf, size); - buf += size; - l -= size; - } - } - */ -} - - -/* Allows to read data from the FIFO buffer. The bytes are unlinked from the - * buffer dynamically when they are read. - */ -size_t dread(char *buf, size_t len) -{ - register fifo8_t *f = &fifo; - register size_t l = len; - - if (buf == NULL || len == 0) - return 0; - - lock_acquire(&root->debuglock); - - while (l > 0) { - if (FIFO_EMPTY(f)) - break; - FIFO_GET(f, buf); - buf++; - l--; - } - len = len - l; - - /* XXX Debug this more efficient alternative - if (len == 1) { - if (!FIFO_EMPTY(f)) - FIFO_GET(f, buf); - else - len = 0; - } else { - u_int8_t *ptr; - int size; - register int l = len, i; - - len = 0; - for (i = 0; i < 2 && l > 0; i++) { - FIFO_FREE(f, &ptr, &size, l); - if (size == 0) - break; - memcpy(buf, ptr, size); - buf += size; - len += size; - l -= size; - } - } - */ - - _lock_release(&root->debuglock); - - return len; -} - - -/* Buffer should at least be 34 bytes. Performs 32-bit value to ASCII binary - * convertion. Returns length of string. - */ -static size_t btoa(char *buf, u_int32_t val) -{ - register int i; - register char *ptr = buf; - - *ptr++ = '%'; - for (i = 31; i > -1; i--) - *ptr++ = (val & (1L << i)) ? '1' : '0'; - *ptr = '\0'; - - return (ptr - buf); -} - - -/* Buffer should be at least 12 bytes. Converts signed 32-bit value to decimal - * ASCII representation. Returns length of string. - */ -static size_t dtoa(char *buf, int32_t val) -{ - register int32_t v = val; - register char *ptr = buf; - register const char *d = ddigits; - - if (v < 0) { - *ptr++ = '-'; - v = -v; - } - for (; v > 9; v /= 10) - *ptr++ = d[v % 10]; - *ptr++ = d[v]; - *ptr = '\0'; - - return (ptr - buf); -} - - -/* Buffer should be at least 11 bytes. Unsigned 32-bit value to decimal ASCII - * convertion. Returns length of string. - */ -static size_t utoa(char *buf, u_int32_t val) -{ - register u_int32_t v = val; - register char *ptr = buf; - register const char *d = ddigits; - - for (; v > 9; v /= 10) - *ptr++ = d[v % 10]; - *ptr++ = d[v]; - *ptr = '\0'; - - return (ptr - buf); -} - - -/* Buffer should be at least 11 bytes. Converts 32-bit value to hexadecimal - * ASCII representation. Returns length of string. - */ -static size_t xtoa(char *buf, u_int32_t val) -{ - register u_int32_t v = val; - register char *ptr = buf; - register const char *d = xdigits; - register int i; - - *ptr++ = '0'; - *ptr++ = 'x'; - for (i = 32 - 4; i > -1; i -= 4) - *ptr++ = d[v >> i & 15]; - *ptr = '\0'; - - return (ptr - buf); -} -#endif diff --git a/Xisop/src/common/kernel/debug.h b/Xisop/src/common/kernel/debug.h deleted file mode 100644 index 5f3f113..0000000 --- a/Xisop/src/common/kernel/debug.h +++ /dev/null @@ -1,104 +0,0 @@ -/* $Id: debug.h,v 1.3 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_DEBUG_H -#define KERNEL_DEBUG_H - - - -#include -#include - - - -/* This implements various debugging primitives. Macros are defined - * so that no debugging code be compiled in the kernel if DEBUG - * is not defined. - */ - - - -#ifndef DEBUG - -/* Debugging disabled, ensure that unnecessary code doesn't get compiled in. - * if (DEBUG_TRUE(condition)) will always cause the condition to be TRUE, while - * if (DEBUG_FALSE(condition)) will always cause the condition to be FALSE. - * DEBUG_PRINTF() will do nothing. - */ - -#define DEBUG_PRINTF(s, ...) -#define DEBUG_READ(b, s) 0 -#define DEBUG_TRUE(c) /* CONSTCOND */1 -#define DEBUG_FALSE(c) /* CONSTCOND */0 - -#else - -/* Debugging enabled, macros must now do something */ - -#define DEBUG_PRINTF debug_printf -#define DEBUG_READ(b, s) debug_read(b, s) -#define DEBUG_TRUE(c) (c) -#define DEBUG_FALSE(c) (c) - - - -/* These should eventually be available even if no debugging is wanted. - * However, these are really simple and are mostly made to serve 32-bit - * values (although characters also work). - */ - -typedef u_int32_t * debug_va_list; - -#define debug_va_start(a, l) (a) = (u_int32_t *)(&(l) + sizeof(*(l))) -#define debug_va_arg(a, t) (t)(*a++) -#define debug_va_copy(d, s) (d) = (s) -#define debug_va_end(a) - - - -void debug_init(void); -void debug_printf(const char *, ...); -/*void dprintf2(const char *, const char *, int, const char *, ...);*/ -size_t debug_read(char *, size_t); - - - -#endif - - - -#endif diff --git a/Xisop/src/common/kernel/device.c b/Xisop/src/common/kernel/device.c deleted file mode 100644 index c8105e8..0000000 --- a/Xisop/src/common/kernel/device.c +++ /dev/null @@ -1,525 +0,0 @@ -/* $Id: device.c,v 1.8 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* Allows current task to open a devicenode_t, obtaining a device_t handle */ -device_t *device_open(const char *name, u_int32_t ver, u_int32_t unit) -{ - device_t *dh = NULL; - - if (name != NULL) { - register devicenode_t *dn; - - SYSTABLE_RLOCK(SYSTABLE_DEVICES); - dn = (devicenode_t *)hashtable_lookup(SYSTABLE(SYSTABLE_DEVICES), - name, strnlen(name, 32)); - SYSTABLE_UNLOCK(SYSTABLE_DEVICES); - if (dn != NULL && (dn->version == ver || ver == 0)) { - if ((dh = (device_t *)spool_alloc(POOL_DEVICEHANDLE)) != NULL) { - if (dn->open(&dh->udata, unit)) { - /* Validate object and set dependancy. We also register - * it since iorequest_t depend on device_t. - */ - OBJECT_VALIDATE(dh, OBJECT_DEVICEHANDLE); - OBJECT_REGISTER(dh); - OBJECT_SETDEP(dh, dn); - dh->devnode = dn; - dn->usecount++; - /* Initialize other device_t fields */ - dh->devport = dn->port; - dh->owner = CURTASK(); - dh->unit = unit; - /* Attach to task resources for automatic freeing */ - SCHED_DISABLE(); - DLIST_APPEND(&CURTASK()->resources.devices, &dh->tasknode); - SCHED_ENABLE(); - } else { - dh = (device_t *)spool_free(POOL_DEVICEHANDLE, - (pnode_t *)dh); - DEBUG_PRINTF("- %T device_open(%s, %u, %u) - Refused\n", - name, ver, unit); - } - } else - DEBUG_PRINTF("* %T device_open(%s, %u, %u) - Out of memory\n", - name, ver, unit); - } else - DEBUG_PRINTF("- %T device_open(%s, %u, %u) - Unknown device\n", - name, ver, unit); - } else - DEBUG_PRINTF("* %T device_open(%s, %u, %u) - Illegal parameters\n", - name, ver, unit); - - return dh; -} - - -/* Closes and frees a device_t from the task it belongs to */ -device_t *device_close(device_t *dh) -{ - if (OBJECT_VALID(dh, OBJECT_DEVICEHANDLE)) { - if (OBJECT_DEPENDS(dh, dh->devnode)) { - register devicenode_t *dn = dh->devnode; - - SYSTABLE_RLOCK(SYSTABLE_DEVICES); - /* devicenode_t for this device_t still exists */ - dn->close(dh->udata, dh->unit); - if ((--(dn->usecount)) == 0 && (dn->flags & DNF_RESIDENT) == 0) { - if (OBJECT_VALID(dn->task, OBJECT_TASK)) - signal_send(dn->task, SIGMASK(SIGTERM)); - } - SYSTABLE_UNLOCK(SYSTABLE_DEVICES); - } else - DEBUG_PRINTF("* %T device_close(%p) - Device has died\n", dh); - /* Unlink task resource and free handle */ - SCHED_DISABLE(); - DLIST_UNLINK(&(dh->owner->resources.devices), &dh->tasknode); - SCHED_ENABLE(); - OBJECT_INVALIDATE(dh); - spool_free(POOL_DEVICEHANDLE, (pnode_t *)dh); - } else - DEBUG_PRINTF("* %T device_close(%p) - Invalid device_t pointer\n", - dh); - - return NULL; -} - - -/* Initializes an iorequest_t for use with specified device_t, necessary - * before using it to send device requests. - */ -bool iorequest_init(iorequest_t *req, device_t *dh, port_t *rport) -{ - bool ok = FALSE; - - if (OBJECT_VALID(dh, OBJECT_DEVICEHANDLE) && - OBJECT_DEPENDS(dh, dh->devnode) && - OBJECT_VALID(rport, OBJECT_PORT)) { - req->udata = NULL; - if (dh->devnode->iorinit == NULL || - (req->udata = dh->devnode->iorinit()) != NULL) { - /* Validate object and register dependancy on device_t */ - OBJECT_VALIDATE(req, OBJECT_IOREQUEST); - OBJECT_SETDEP(req, dh); - req->devhandle = dh; - /* Initialize other iorequest_t fields */ - req->devport = dh->devport; - req->rport = rport; - req->flags = 0; - req->success = FALSE; - req->result = 0; - req->actual = 0; - ok = TRUE; - } else - DEBUG_PRINTF("* %T iorequest_init(%p, %p, %p) - Out of memory\n", - req, dh, rport); - } else - DEBUG_PRINTF( - "* %T iorequest_init(%p, %p, %p) - Invalid device_t pointer\n", - req, dh, rport); - - return ok; -} - - -bool iorequest_destroy(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if (OBJECT_DEPENDS(req, req->devhandle) && - OBJECT_DEPENDS(req->devhandle, req->devhandle->devnode)) { - register devicenode_t *dn = req->devhandle->devnode; - - if (dn->iordestroy != NULL && req->udata != NULL) - dn->iordestroy(req->udata); - } - OBJECT_INVALIDATE(req); - } else - DEBUG_PRINTF( - "* %T iorequest_destroy(%p) - Invalid iorequest_t poinder\n", - req); - - return ok; -} - - -/* Sends the iorequest_t message to it's corresponding device, and waits for - * results to be obtained, then returns. This consists of a synchroneous - * device request. - */ -bool iorequest_sync(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) == 0) { - if (port_send(req->devport, req->rport, (message_t *)req)) { - register sigmask_t sigmport = PORT_SIGMASK(req->devport); - - req->flags = IOF_SYNC | IOF_PENDING; - while (((signal_wait(sigmport, NULL)) & sigmport) == 0) ; - port_get(req->devport); - /* Request satisfied */ - req->flags &= ~(IOF_SYNC & IOF_PENDING); - ok = TRUE; - } else - DEBUG_PRINTF("* %T iorequest_sync(%p) - port_send()\n", req); - } else - DEBUG_PRINTF( - "* %T iorequest_sync(%p) - iorequest_t already pending\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_sync(%p) - Invalid iorequest_t pointer\n", - req); - - return ok; -} - - -/* Sends the iorequest_t message to it's corresponding device, but returns - * immediately, without waiting for results. This consists of an asynchroneous - * request. The application is responsible to monitor the reply port status - * for the request completion, and to unqueue the reply from the reply port - * before performing another request using this iorequest_t. - */ -bool iorequest_async(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) == 0) { - if (port_send(req->devport, req->rport, (message_t *)req)) { - req->flags = IOF_ASYNC | IOF_PENDING; - ok = TRUE; - } else - DEBUG_PRINTF("* %T iorequest_async(%p) - port_send()\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_async(%p) - iorequest_t already pending\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_async(%p) - Invalid iorequest_t pointer\n", - req); - - return ok; -} - - -/* Aborts a pending asynchroneous request which has not yet completed. - * This in fact sends back a new request using the same iorequest_t, but - * does not expect a reply back from the device for the abort request. However, - * the reply port will be sent the reply as usual when the aborted iorequest_t - * ends (which always happens even when a request is aborted). - */ -bool iorequest_abort(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) != 0 && (req->flags & IOF_ASYNC) != 0) { - req->function = IO_ABORT; - if (port_send(req->devport, req->rport, (message_t *)req)) { - req->flags |= IOF_ABORTING; - ok = TRUE; - } else - DEBUG_PRINTF("* %T iorequest_abort(%p) - port_send()\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_abort(%p) - iorequest_t not pending\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_abort(%p) - Invalid iorequest_t pointer\n", - req); - - if (!ok) - DEBUG_PRINTF("* %T iorequest_abort(%p)\n", req); - - return ok; -} - - -/* Waits until the currently pending asynchroneous request completes. The reply - * message is automatically unqueued from the reply port in this case. - */ -bool iorequest_wait(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) != 0 && (req->flags & IOF_ASYNC) != 0) { - register sigmask_t sigmport = PORT_SIGMASK(req->devport); - - while (((signal_wait(sigmport, NULL)) & sigmport) == 0) ; - port_get(req->devport); - /* Request satisfied */ - req->flags &= ~(IOF_ASYNC & IOF_PENDING); - ok = TRUE; - } else - DEBUG_PRINTF( - "* %T iorequest_wait(%p) - iorequest_t not pending\n", - req); - } else - DEBUG_PRINTF( - "* %T iorequest_wait(%p) - Invalid iorequest_t pointer\n", - req); - - return ok; -} - - -/* Returns TRUE if the request is asynchroneous and still pending. */ -bool iorequest_pending(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) != 0 && (req->flags & IOF_ASYNC) != 0) - ok = TRUE; - } else - DEBUG_PRINTF( - "* %T iorequest_pending(%p) - Invalid iorequest_t pointer\n", - req); - - return ok; -} - - -/* Returns TRUE if the request last terminated by iorequest_abort(). */ -bool iorequest_aborted(iorequest_t *req) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_ABORTED) != 0) - ok = TRUE; - } else - DEBUG_PRINTF( - "* %T iorequest_aborted(%p) - Invalid iorequest_t pointer\n", - req); - - return ok; -} - - -/* Made for devices to satisfy a user iorequest_t, at the same time setting - * the boolean result code for it. - */ -bool iorequest_satisfy(iorequest_t *req, bool result) -{ - bool ok = FALSE; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - if ((req->flags & IOF_PENDING) != 0) { - req->flags &= ~(IOF_PENDING | IOF_SYNC | IOF_ASYNC); - if ((req->flags & IOF_ABORTING) != 0) { - req->flags &= ~IOF_ABORTING; - req->flags |= IOF_ABORTED; - req->success = result; - } - if (!(ok = port_reply((message_t *)req))) - DEBUG_PRINTF( - "* %T iorequest_satisfy(%p, %B) - port_reply(%p)\n", - req, result, req); - } - } else - DEBUG_PRINTF("* %T iorequest_satisfy(%p, %B) - Invalid iorequest_t\n", - req, result); - - return ok; -} - - -/* Allows a task to attach a new device to the system lists. It then of course - * should serve requests through it's port. The task may only become one - * device, that is, it may not attach more than a single device. - * It however can serve multiple units on that device, of course. - */ -bool device_attach(const char *name, u_int32_t version, port_t *port, - void (*clean)(void), bool (*open)(void **, u_int32_t), - void (*close)(void *, u_int32_t), void *(*iorinit)(void), - void (*iordestroy)(void *), u_int8_t flags) -{ - if (CURTASK()->resources.device == NULL && name != NULL && - OBJECT_VALID(port, OBJECT_PORT) && open != NULL && close != NULL) { - register bstr_t *bstr; - - if ((bstr = bstr_new(name, 32, FALSE)) != NULL) { - register devicenode_t *dn; - - SYSTABLE_RLOCK(SYSTABLE_DEVICES); - if ((dn = (devicenode_t *)hashtable_lookup( - SYSTABLE(SYSTABLE_DEVICES), - bstr->data, bstr->len)) == NULL || - version != dn->version) { - if ((dn = (devicenode_t *)spool_alloc(POOL_DEVICENODE)) - != NULL) { - /* Validate and register for dependancies */ - OBJECT_VALIDATE(dn, OBJECT_DEVICENODE); - OBJECT_REGISTER(dn); - /* Initialize other devicenode_t fields */ - dn->version = version; - dn->name = bstr; - dn->usecount = 0; - dn->flags = flags; - dn->port = port; - dn->task = CURTASK(); - dn->clean = clean; - dn->open = open; - dn->close = close; - dn->iorinit = iorinit; - dn->iordestroy = iordestroy; - /* Attach */ - SYSTABLE_UPGRADE(SYSTABLE_DEVICES); - (void) hashtable_link(SYSTABLE(SYSTABLE_DEVICES), - (hashnode_t *)dn, bstr->data, - bstr->len, FALSE); - SYSTABLE_UNLOCK(SYSTABLE_DEVICES); - - return TRUE; - } else - DEBUG_PRINTF("* %T device_attach() - Out of memory\n"); - } else - DEBUG_PRINTF( - "* %T device_attach() - Device exists already\n"); - - SYSTABLE_UNLOCK(SYSTABLE_DEVICES); - bstr_free(bstr); - } else - DEBUG_PRINTF("* %T device_attach() - Out of memory\n"); - } else - DEBUG_PRINTF("* %T device_attach() - Invalid parameters\n"); - - DEBUG_PRINTF("* %T device_attach(%s, %u, %p, %p, %p, %p, %p, %p, %x)\n", - name, version, port, clean, open, close, iorinit, iordestroy, - (u_int32_t)flags); - - return FALSE; -} - - -bool device_detach(devicenode_t *dn) -{ - bool ok = FALSE; - - if (OBJECT_VALID(dn, OBJECT_DEVICENODE)) { - SYSTABLE_WLOCK(SYSTABLE_DEVICES); - hashtable_unlink(SYSTABLE(SYSTABLE_DEVICES), (hashnode_t *)dn); - SYSTABLE_UNLOCK(SYSTABLE_DEVICES); - if (dn->clean != NULL) - dn->clean(); - OBJECT_INVALIDATE(dn); - if (dn->name != NULL) - bstr_free(dn->name); - spool_free(POOL_DEVICENODE, (pnode_t *)dn); - } else - DEBUG_PRINTF( - "* %T device_detach(%p) - Invalid devicenode_t pointer\n", - dn); - - return ok; -} - - - -/* Utility functions for very simple synchroneous I/O */ - -/* Like read(), but on a Xisop device */ -ssize_t device_read(iorequest_t *req, void *buf, size_t size) -{ - ssize_t len = -1; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - req->function = IO_READ; - req->len = size; - req->data = buf; - if (iorequest_sync(req)) { - if (req->success) - len = req->actual; - } else - DEBUG_PRINTF( - "* %T device_read(%p, %p, %u) - iorequest_sync(%p)\n", - req, buf, size, req); - } else - DEBUG_PRINTF( - "* %T device_read(%p, %p, %u) - Invalid iorequest_t pointer\n", - req, buf, size); - - return len; -} - - -/* Like write(), but on a Xisop device */ -ssize_t device_write(iorequest_t *req, void *buf, size_t size) -{ - ssize_t len = -1; - - if (OBJECT_VALID(req, OBJECT_IOREQUEST)) { - req->function = IO_WRITE; - req->len = size; - req->data = buf; - if (iorequest_sync(req)) { - if (req->success) - len = req->actual; - } else - DEBUG_PRINTF( - "* %T device_read(%p, %p, %u) - iorequest_sync(%p)\n", - req, buf, size, req); - } else - DEBUG_PRINTF( - "* %T device_write(%p, %p, %u) - Invalid iorequest_t ptr\n", - req, buf, size); - - return len; -} diff --git a/Xisop/src/common/kernel/device.h b/Xisop/src/common/kernel/device.h deleted file mode 100644 index 7276d3a..0000000 --- a/Xisop/src/common/kernel/device.h +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id: device.h,v 1.2 2004/01/18 17:42:59 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_DEVICE_H -#define KERNEL_DEVICE_H - - - -#include -#include -#include -#include -#include -#include -#include - - - -/* devicenode/device_t flags */ -#define DNF_RESIDENT (1 << 0) - -/* iorequest_t flags */ -#define IOF_SYNC (1 << 0) -#define IOF_ASYNC (1 << 1) -#define IOF_PENDING (1 << 2) -#define IOF_ABORTING (1 << 3) -#define IOF_ABORTED (1 << 4) - -/* Standard device commands */ -enum _devicecommands { - IO_ABORT = 0, - IO_READ, - IO_WRITE, - IO_CONTROL /* General purpose like unix ioctl() */ -}; - - - -/* For device task functions to access user data they associated with - * device_t and iorequest_t handles (if any, or NULL). - */ -#define DEVICEHANDLE_UDATA(d) (d)->udata -#define IOREQUEST_UDATA(r) (r)->udata - - - -/* This structure holds the only necessary information which Xisop needs to - * know. A device has to internally handle other information but which is of - * no use to Xisop itself. - */ -struct devicenode { - /* System link and information, for devices system list */ - hashnode_t node; - u_int32_t version; - bstr_t *name; - u_int32_t usecount; - u_int8_t flags; - /* Validity sceal. device_t objects depend on us */ - u_int32_t object_magic, object_id; - - /* Port used to send device requests to */ - port_t *port; - /* Task associated with device */ - task_t *task; - - /* Functions provided by device, described in Xisop documentation. */ - void (*clean)(void); - bool (*open)(void **, u_int32_t); - void (*close)(void *, u_int32_t); - void *(*iorinit)(void); - void (*iordestroy)(void *); -}; - -/* Consists of a device handle, returned to tasks when opening a device */ -struct devicehandle { - pnode_t usernode; /* Used by device for optional queuing */ - node_t tasknode; /* Used to remember task resource */ - /* Validity and dependancy sceal, we depend on devicenode_t */ - u_int32_t object_magic, object_id, objdep_magic, objdep_id; - devicenode_t *devnode; - /* Other fields */ - task_t *owner; /* Owner task of this handle */ - port_t *devport; /* Device port to use */ - u_int32_t devnodeid; /* Id of devnode */ - u_int32_t unit; /* Unit opened on device */ - void *udata; /* Device may link custom data here */ -}; - -/* An iorequest_t consists of a message. This also means that the device task - * may queue the message into custom list_t as required after they obtain it, - * as long as they unlink it before they return it of course. - */ -struct iorequest { - message_t msg; /* An iorequest_t is a message */ - /* Validity sceal and dependancy link */ - u_int32_t object_magic, objdep_magic, objdep_id; - device_t *devhandle; - /* Other */ - port_t *devport, *rport; - void *udata; - u_int8_t flags; - - /* The following are the operation request control fields */ - u_int32_t function, subfunction; - size_t len; - size_t offset; /* Useful for block devices */ - void *data; - - /* And operation results fields */ - bool success; - int result; - size_t actual; -}; - - - -/* User API functions */ -device_t *device_open(const char *, u_int32_t, u_int32_t); -device_t *device_close(device_t *); -bool iorequest_init(iorequest_t *, device_t *, port_t *); -bool iorequest_destroy(iorequest_t *); -bool iorequest_sync(iorequest_t *); -bool iorequest_async(iorequest_t *); -bool iorequest_abort(iorequest_t *); -bool iorequest_wait(iorequest_t *); -bool iorequest_pending(iorequest_t *); -bool iorequest_aborted(iorequest_t *); - -/* Device task functions */ -bool iorequest_satisfy(iorequest_t *, bool); -bool device_attach(const char *, u_int32_t, port_t *, void (*)(void), - bool (*)(void **, u_int32_t), void (*)(void *, u_int32_t), - void *(*)(void), void (*)(void *), u_int8_t); -bool device_detach(devicenode_t *); - -/* Useful but very simple synchroneous functions */ -ssize_t device_read(iorequest_t *, void *, size_t); -ssize_t device_write(iorequest_t *, void *, size_t); - - - -#endif diff --git a/Xisop/src/common/kernel/exception.c b/Xisop/src/common/kernel/exception.c deleted file mode 100644 index 5fe0f7f..0000000 --- a/Xisop/src/common/kernel/exception.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id: exception.c,v 1.4 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* These are the machine-independant kernel frontend to interrupt hooks - * facilities. They internally use a recursive _rlock_t which allows to - * ensure reliability when adding and removing hooks to a facility, - * while removing the need for system call traps to access the functionality. - */ - -hookid_t hook_attach(u_int32_t facility, u_int32_t skipcount, - u_int32_t runcount, void (*code)(hookid_t, int, void *), void *data) -{ - register hookid_t id = 0; - - if (facility < (enum _facilities)_FACILITY_MAX && code != NULL) { - register facility_t *f; - register hook_t *hook; - - f = (facility_t *)&root->int_facilities[facility]; - _rlock_acquire(&f->rlock); - if ((hook = (hook_t *)pool_alloc(&f->pool, FALSE)) != NULL) { - if (++f->idcnt == 0) - f->idcnt++; - id = hook->id = f->idcnt; - hook->skipcount = skipcount; - hook->runcount = runcount; - hook->code = code; - hook->data = data; - DLIST_APPEND(&f->hooks, (node_t *)hook); - STAT(STAT_HOOKS_ATTACHED, 1); - } else { - STAT(STAT_HOOKS_ATTACHED_NOMEM, 1); - DEBUG_PRINTF("* %T hook_attach() - Out of memory\n"); - } - _rlock_release(&f->rlock); - } else { - STAT(STAT_HOOKS_ATTACHED_FAILED, 1); - DEBUG_PRINTF("* %T hook_attach(%u, %u, %u, %p, %p)\n", - facility, skipcount, runcount, code, data); - } - - return id; -} - - -bool hook_detach(u_int32_t facility, hookid_t id) -{ - register bool ok = FALSE; - - if (facility < (enum _facilities)_FACILITY_MAX && id != 0) { - register facility_t *f; - register hook_t *node, *next; - - f = (facility_t *)&root->int_facilities[facility]; - _rlock_acquire(&f->rlock); - - for (node = DLIST_TOP(&f->hooks); node != NULL; node = next) { - next = DLIST_NEXT(node); - if (node->id == id) { - DLIST_UNLINK(&f->hooks, (node_t *)node); - pool_free((pnode_t *)node); - ok = TRUE; - STAT(STAT_HOOKS_DETACHED, 1); - break; - } - } - if (node == NULL) - STAT(STAT_HOOKS_DETACHED_NOEXIST, 1); - - _rlock_release(&f->rlock); - } else { - STAT(STAT_HOOKS_DETACHED_FAILED, 1); - DEBUG_PRINTF("* %T hook_detach(%u, %u)\n", facility, id); - } - - return ok; -} - - -void facility_disable(u_int32_t facility) -{ - if (facility < (enum _facilities)_FACILITY_MAX) { - _rlock_acquire(&(root->int_facilities[facility].rlock)); - STAT(STAT_FACILITY_DISABLED, 1); - } else { - STAT(STAT_FACILITY_DISABLED_FAILED, 1); - DEBUG_PRINTF("* %T facility_disable(%u)\n", facility); - } -} - - -void facility_enable(u_int32_t facility) -{ - if (facility < (enum _facilities)_FACILITY_MAX) { - _rlock_release(&(root->int_facilities[facility].rlock)); - STAT(STAT_FACILITY_ENABLED, 1); - } else { - STAT(STAT_FACILITY_ENABLED_FAILED, 1); - DEBUG_PRINTF("* %T facility_enable(%u)\n", facility); - } -} - - -/* This is called by the port-specific code to execute the hooks associated - * with a facility. Note that a recursive lock is internally maintained which - * ensures to prevent recursion, or to execute the hooks while new ones are - * being added, or when a hook is being deleted. - */ - - -/* Execute the hooks and transparently delete expired ones */ -void facility_exechooks(u_int32_t facility, int origin) -{ - if (facility < (enum _facilities)_FACILITY_MAX) { - register facility_t *f = &root->int_facilities[facility]; - - if (_rlock_try(&f->rlock)) { - register list_t *hooks = &f->hooks; - register hook_t *node, *tmp; - - STAT(STAT_FACILITY_EXECUTED, 1); - node = DLIST_TOP(hooks); - while (node != NULL) { - if (node->skipcount > 0) { - node->skipcount--; - STAT(STAT_HOOKS_SKIPPED, 1); - node = DLIST_NEXT(node); - } else { - node->code(node->id, origin, node->data); - STAT(STAT_HOOKS_EXECUTED, 1); - if (node->runcount != 0) { - tmp = DLIST_NEXT(node); - if ((--node->runcount) == 0) { - /* This hook is temporary and expired, - * extract it. - */ - DLIST_UNLINK(hooks, (node_t *)node); - pool_free((pnode_t *)node); - STAT(STAT_HOOKS_EXPIRED, 1); - } - node = tmp; - } else - node = DLIST_NEXT(node); - } - } - _rlock_release(&f->rlock); - } else - STAT(STAT_FACILITY_EXECUTED_LOCKED, 1); - } else { - STAT(STAT_FACILITY_EXECUTED_FAILED, 1); - DEBUG_PRINTF("* %T facility_exechooks(%u, %d)\n", facility, origin); - } -} - - -/* Initialize all facility_t */ -void facilities_init(void) -{ - register u_int32_t i; - - for (i = 0; i < (enum _facilities)_FACILITY_MAX; i++) { - register facility_t *f = &root->int_facilities[i]; - - f->idcnt = 0; - _spl0(); - pool_init(&f->pool, 1, 1, 1, sizeof(hook_t), 0); - _splhigh(); - DLIST_INIT(&f->hooks); - _rlock_init(&f->rlock); - _rlock_acquire(&f->rlock); - } - for (i = 0; i < (enum _facilities)_FACILITY_MAX; i++) { - register facility_t *f = &root->int_facilities[i]; - - _rlock_release(&f->rlock); - } -} diff --git a/Xisop/src/common/kernel/exception.h b/Xisop/src/common/kernel/exception.h deleted file mode 100644 index 760bdb6..0000000 --- a/Xisop/src/common/kernel/exception.h +++ /dev/null @@ -1,84 +0,0 @@ -/* $Id: exception.h,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_EXCEPTION_H -#define KERNEL_EXCEPTION_H - - - -#include -#include -#include -#include -#include - - - -/* Used to hold user code hooks which should be executed at exceptions - * depending on the facility they are attached to. - */ -struct _int_hook { - pnode_t node; - hookid_t id; - u_int32_t skipcount, runcount; - void (*code)(hookid_t, int, void *); - void *data; -}; - -/* There are _FACILITIES_MAX of these in the root->facilities array. - * The facilities are defined by the port-specific code. - */ -struct _int_facility { - hookid_t idcnt; - list_t hooks; - pool_t pool; - _rlock_t rlock; -}; - - -hookid_t hook_attach(u_int32_t, u_int32_t, u_int32_t, - void (*)(hookid_t, int, void *), void *); -bool hook_detach(u_int32_t, hookid_t); -void facility_disable(u_int32_t); -void facility_enable(u_int32_t); - -void facilities_init(void); -void facility_exechooks(u_int32_t, int); - - - -#endif diff --git a/Xisop/src/common/kernel/main.c b/Xisop/src/common/kernel/main.c deleted file mode 100644 index 8232cc7..0000000 --- a/Xisop/src/common/kernel/main.c +++ /dev/null @@ -1,234 +0,0 @@ -/* $Id: main.c,v 1.8 2004/06/04 02:25:15 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -COPYRIGHT("\0\nXisop Copyright 2001-2003, Matthew Mondor, \ -All rights reserved.\n"); - - - -/* The famous global structure where all Xisop control information is stored */ -struct xisop_root root[1]; - -static const char *systables_names[SYSTABLE_MAX] = { - "systable_publicports", - "systable_libraries", - "systable_devices", - "systable_handlers", - "systable_volumes" -}; - - - -/* Xisop main code. The port-specific code should switch to supervisor mode, - * setup kernel stack, disable interrupts and setup it's interrupt handlers, - * setup the memory ppools, call xisop_init(), switch back to usermode, and - * jump definitively to this function. - */ -int main(void) -{ - /* And we're Xisop-hosted! */ - - /* Setup and launch our main Xisop init task. It's source is in - * src/common/kernel/task.c. - */ - { - register task_t *task; - - if ((task = task_alloc(task_init, NULL, NULL, 0, 4096, TF_KERNEL)) - != NULL) - task_start(task); - } - - /* Here we enable the scheduler, which means that this current context - * will soon be the first to be saved in root->curctx, which currently - * consists of the _scontext _ctx_t buffer. When no more tasks are - * in the ready queue, _scontext will also be the restored context, - * in which case we want to avoid wasting power and overheating the - * CPU unnecessarily, and are using _idle() in an endless loop to do that. - * Because we are in usermode, we use sys_idle(). - */ - SCHED_ENABLE(); - - for (;;) { - /* Just idle processor */ - /* XXX Amiga-specific, can be taken out, purple color on blitter to - * show that the system is all idle - */ - CUSTOM->COLOR[0] = 0x0F0F; - sys_idle(); - } - - /* NOTREACHED */ - return 0; -} - - -void xisop_init(void) -{ - /* Enable interrupts and therefore syscalls, facilities and scheduler - * timer as well. Note that until we SCHED_ENABLE(), the scheduler will - * not attempt to perform contex switches, even though the scheduler - * timer interrupt is enabled. - */ - -#ifdef STATISTICS - statistic_init(); -#endif - - /* Unique number generator */ - _lock_init(&root->unique_lock); - root->unique = 0; - - /* Kernel memory allocators */ - _lock_init(&root->kernpool_lock); - spools_init(); /* memory.h */ - if ((root->kernpool = (mpool_t *)spool_alloc(POOL_MPOOL)) == NULL) { - /* XXX Panic */ - CUSTOM->COLOR[0] = 0x0F00; - } - if (!mpool_init(root->kernpool)) { - /* XXX Panic */ - CUSTOM->COLOR[0] = 0x0F00; - } - - /* And task multitasking scheduler */ - scheduler_init(); /* scheduler.c */ - - /* Syscalls service */ - syscall_init(); - -#ifdef DEBUG - /* Debugging messages FIFO */ - debug_init(); -#endif - - /* System hash tables */ - /* XXX Hmm the following calls kmalloc() which calls _kmalloc() which - * in turn calls lock_acquire(&root->kernpool_lock) which finally calls - * _yield(NULL) if it cannot immediately obtain the lock. However, _yield() - * function requires the scheduler interrupt to be running, and the - * scheduler lock to be released, of course. This appears to be the reason - * why the system now locks in trap_catch1() which corresponds to the - * _yield() handler... But, why can't the lock be obtained immediately? - * Since it is properly initialized first... - * I tried this in xisop_init(), in start of main() and in main() after - * SCHED_ENABLE(), always with the same results. Would it be possible that - * something we lock a lock, and are calling something which also attempts - * to lock it (and we already hold it)? If so, it would be either - * _kmalloc() or pages_alloc(). But they are both using a different lock.. - * Or, would it be possible that I messed up port.c locking? - * XXX Oh! It works fine when I strip out DEBUG and STATISTICS. This - * probably means that the problem is the the xisop kernel size and boot - * loader which need adjusting. - */ - { - register int i; - - for (i = 0; i < (enum systables)SYSTABLE_MAX; i++) { - rwlock_init(&root->systables[i].lock); - if (!hashtable_init(SYSTABLE(i), systables_names[i], - HT_DEFAULT_CAPACITY, kmalloc, kfree, - memcmp, memhash32, TRUE)) { - /* XXX PANIC! */ - CUSTOM->COLOR[0] = 0x0F00; - } - } - } - - /* Enable interrupts */ - _spl0(); -} - - -u_int32_t unique_id(void) -{ - register u_int32_t id; - - lock_acquire(&root->unique_lock); - id = (++root->unique); - _lock_release(&root->unique_lock); - - return id; -} - - -hashtable_t *systable_lock(u_int32_t systable, bool exclusive) -{ - hashtable_t *list = NULL; - - if (systable < (enum systables)SYSTABLE_MAX) { - if (exclusive) - SYSTABLE_WLOCK(systable); - else - SYSTABLE_RLOCK(systable); - list = SYSTABLE(systable); - } - - return list; -} - - -void systable_unlock(u_int32_t systable) -{ - if (systable < (enum systables)SYSTABLE_MAX) - SYSTABLE_UNLOCK(systable); -} - - -void systable_upgrade(u_int32_t systable) -{ - if (systable < (enum systables)SYSTABLE_MAX) - SYSTABLE_UPGRADE(systable); -} diff --git a/Xisop/src/common/kernel/main.h b/Xisop/src/common/kernel/main.h deleted file mode 100644 index 90dc56a..0000000 --- a/Xisop/src/common/kernel/main.h +++ /dev/null @@ -1,155 +0,0 @@ -/* $Id: main.h,v 1.5 2004/01/19 18:07:11 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_MAIN_H -#define KERNEL_MAIN_H - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* To access and manipulate system lists */ -#define SYSTABLE(l) (&(root->systables[(enum systables)(l)].table)) -#define SYSLOCK(l) (&(root->systables[(enum systables)(l)].lock)) -#define SYSTABLE_RLOCK(l) rwlock_acquire(SYSLOCK(l), FALSE) -#define SYSTABLE_WLOCK(l) rwlock_acquire(SYSLOCK(l), TRUE) -#define SYSTABLE_UNLOCK(l) rwlock_release(SYSLOCK(l)) -#define SYSTABLE_UPGRADE(l) rwlock_upgrade(SYSLOCK(l)) - - -/* A system list. The lock allows simultaneous read-only access, or exclusive - * access when write operations are required. - */ -struct systable { - rwlock_t lock; - hashtable_t table; -}; - -enum systables { - SYSTABLE_PUBLICPORTS = 0, - SYSTABLE_LIBRARIES, - SYSTABLE_DEVICES, - SYSTABLE_HANDLERS, - SYSTABLE_VOLUMES, - SYSTABLE_MAX -}; - - -/* The Xisop main root structure */ -struct xisop_root { - - /* Do not change the order of the following block fields, as port-specific - * assembly code may assume their offsets. - */ - - /* Scheduling */ - _rlock_t sched_lock; - list_t tasks_ready, tasks_wait, tasks_dead; - task_t *curtask; - _ctx_t *curctx; - - /* The remaining fields are only accessed by common C code. */ - task_t *task_init, *task_reaper; - - /* Memory management. First are the system page pools */ - ppool_t ppools[(enum _memtypes)_MEM_MAX]; - /* Then the system object pools */ - _lock_t spools_locks[(enum _syspools)POOL_MAX]; - pool_t spools[(enum _syspools)POOL_MAX]; - /* And the kernel general purpose pool */ - _lock_t kernpool_lock; - mpool_t *kernpool; - - /* Interrupts abstraction system */ - facility_t int_facilities[(enum _facilities)_FACILITY_MAX]; - - /* Various important system lists */ - struct systable systables[(enum systables)SYSTABLE_MAX]; - - /* System calls */ - void (**syscalls)(void *, void *); - - /* Useful counter to create unique IDs for arbitrary objects, like for - * ports, using the UNIQUE() macro. Should normally be used when the - * scheduler is disabled. - */ - _lock_t unique_lock; - u_int32_t unique; - -#ifdef STATISTICS - /* Statistics support */ - u_int32_t stats[(enum stat_keys)STAT_MAX]; -#endif -#ifdef DEBUG - /* dprintf() support */ - _lock_t debuglock; - fifo8_t *debugfifo; -#endif -}; - - - -/* xisop global data */ -extern struct xisop_root root[1]; - - - -int main(void); -void xisop_init(void); -u_int32_t unique_id(void); - -hashtable_t *systable_lock(u_int32_t, bool); -void systable_upgrade(u_int32_t); -void systable_unlock(u_int32_t); - - - -#endif diff --git a/Xisop/src/common/kernel/make.sh b/Xisop/src/common/kernel/make.sh deleted file mode 100755 index fbd47d8..0000000 --- a/Xisop/src/common/kernel/make.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../makedefs.sh - -buildlib . -show $C_AR ar/kernel.a *.o -show $C_RANLIB ar/kernel.a diff --git a/Xisop/src/common/kernel/memory.c b/Xisop/src/common/kernel/memory.c deleted file mode 100644 index 3811e14..0000000 --- a/Xisop/src/common/kernel/memory.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* $Id: memory.c,v 1.9 2004/06/04 03:09:48 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Support for multiple memory types and dynamically attaching pages at - * runtime was implemented the 25 Febuary 2003, when this code was rewritten - * from scratch. - * - * This memory management system works with physical pages. This means that - * we must provide facilities to work with actual physical contiguous pages - * when large memory areas are required. Pages only consist of useful units - * for management; They thus can be of any size (although multiples of 16 - * bytes), and do not need to correspond to the page size required by the - * MMU system (if any). - * - * It may not be the best or most efficient way to deal with this, as I - * wrote this code from scratch using my own ideas, without reference. - * But it works well and seems quite fast. Moreover, _PAGE_SIZE, _MEM_MAX - * and _MPOOLS are provided by the port-specific code, and allows to adapt - * the system to a variety of situations. It thus well serves it's intended - * purpose. We provide operations on pages, on basic fixed-sized pools and - * multiple block size pools for general purpose memory management functions. - * - * A previous pool_t implementation attempted to not have to delete all the - * nodes from a page when moving an unused page to the page cache, and - * statistics would be kept to know when to free them, at which time their - * pnode_t nodes were unlinked as well. Some care was taken to append freed - * nodes of less used pages at the end of the list and insert freed nodes of - * very used ones at the top of the list, so that over time hopefully - * the system would stabilize well. It used to result in more fragmentation - * than the current method which still caches unused pages and uses statistics - * to free them less often, but immediately removes all nodes of a page from - * the free nodes list when a page is unused, and has to re-initialize all - * those nodes for a page when retreiving a page back from the cache. - * Because Xisop works with actual physical pages and that it requires actual - * contiguous pages for large data blocks, it is very important to do what is - * necessary to avoid fragmentation as much as possible, in favor of stability - * and performance over long uptimes periods, and so I reverted to this method. - * We favor reuse of recently used nodes and pages as much as possible. - * - * It would be nice if the free list consisted of nodes linking to the next - * contiguous pages block rather than only individual pages. This would speed - * up multiple page allocations, which currently requires running among free - * pages to locate contiguous ones. Possibly that freeing could also adapt - * the pages index dynamically so that nodes could be restored without running - * among individual pages to know where to insert the node. - * - * The system was first tested on NetBSD in userspace, to ensure that - * everything works as expected before the code was imported in Xisop. - * - * Matt - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* Used by spools_init() */ -static const struct syspools_params syspools_params - [(enum _syspools)POOL_MAX] = { - {"tasks_pool", 1, 0, 0, sizeof(task_t)}, - {"ports_pool", 1, 0, 0, sizeof(port_t)}, - {"devicenodes_pool", 1, 0, 0, sizeof(devicenode_t)}, - {"devices_pool", 1, 0, 0, sizeof(device_t)}, - {"mpools_pool", 1, 0, 0, sizeof(mpool_t)} -}; - - - -/* This function is required to call once before initializing the memory - * pages, by the port-specific code. - */ -void memory_init(void) -{ - register u_int32_t i; - - for (i = 0; i < (enum _memtypes)_MEM_MAX; i++) { - _lock_init(&root->ppools[i].lock); - DLIST_INIT(&root->ppools[i].mchunks); - } -} - - -/* This function is extremely useful to prepare a given contiguous memory area - * for it to be attached to the system pages using mchunk_attach(). - * Sanity checking is performed to fix page alignment if needed, and the - * internal control structures are automatically prepared. - * Returns a pointer to an mchunk_t, or NULL if the supplied memory area is - * too small (under two valid pages). - */ -mchunk_t *mchunk_init(void *mem, size_t size) -{ - mchunk_t *mchunk = NULL; - void *begin, *end; - u_int32_t pages; - - /* Page-align pointers, and calculate number of supplied memory pages */ - end = mem + size; - begin = (void *)BALIGN_CEIL(mem, _PAGE_SIZE); - end = (void *)BALIGN_FLOOR(end, _PAGE_SIZE); - pages = (end - begin) / _PAGE_SIZE; - - if (pages > 1) { - void *reserved; - page_t **index, *page; - u_int32_t extrapages; - size_t extrabytes; - - /* Evaluate how many pages are required to be reserved to setup the - * mchunk_t and it's components. As we evaluate this on the number of - * available pages, which will shrink a bit after we reserve the area, - * we will re-evaluate it later, but will still be using the same - * reserved area, thus loosing a few bytes. The loss is however quite - * negligable. - */ - extrabytes = (size_t)OALIGN_CEIL(sizeof(mchunk_t), u_int32_t); - extrabytes += (sizeof(page_t *) + sizeof(page_t)) * pages; - extrapages = extrabytes / _PAGE_SIZE; - if (extrabytes % _PAGE_SIZE) - extrapages++; - reserved = begin; - begin += extrapages * _PAGE_SIZE; - pages -= extrapages; - - /* Now our necessary reserved area is at , and has little - * more room than required to store all the control data. We have to - * setup pages, starting at and ending at . - * First setup our control structures pointers. - */ - mchunk = (mchunk_t *)reserved; - reserved += sizeof(mchunk_t); - reserved = (void *)OALIGN_CEIL(reserved, u_int32_t); - page = reserved; - reserved += sizeof(page_t) * pages; - reserved = (void *)OALIGN_CEIL(reserved, u_int32_t); - index = reserved; - - /* Run through pages filling the control index and headers, while - * linking the page_t nodes into the mchunk_t. - */ - DLIST_INIT(&mchunk->free); - mchunk->index = index; - mchunk->pages = pages; - { - register u_int8_t *run = begin; - register list_t *l = &mchunk->free; - register u_int32_t i; - - for (i = 0; i < pages; i++, run += _PAGE_SIZE) { - register page_t *p = &page[i]; - - p->mchunk = mchunk; - p->address = run; - p->last = NULL; - p->id = i; - p->state = PS_FREE; - p->pool = NULL; - index[i] = p; - DLIST_APPEND(l, (node_t *)p); - } - } - } - - if (mchunk != NULL) - OBJECT_VALIDATE(mchunk, OBJECT_MCHUNK); - - return mchunk; -} - - -/* Allows to dynamically attach new memory at runtime. This can be useful - * for instance to assign memory for a hotplug device such as PCMCIA RAM. - * The mchunk_t should be setup using mchunk_init(). It is recommended to - * read the Xisop documentation for more information. One of the existing - * memory types supplied by the port-specific code should be chosen to which - * attach the chunk. mchunk_attach() is also used by the port-specific code - * to attach the initial memory pages. - */ -bool mchunk_attach(int memtype, mchunk_t *mchunk) -{ - bool ok = FALSE; - - if (memtype < (enum _memtypes)_MEM_MAX && memtype != _MEM_ANY && - OBJECT_VALID(mchunk, OBJECT_MCHUNK)) { - register ppool_t *p; - register mchunk_t *m; - - p = &root->ppools[memtype]; - mchunk->ppool = p; - - /* Obtain the system pages protection lock */ - lock_acquire(&p->lock); - - /* Make sure that this chunk is not already in the pool. We can - * afford this as this is a rare call, although dangerous. - */ - DLIST_FOREACH(&p->mchunks, m) { - if (m == mchunk) - break; - } - if (m == NULL) { - DLIST_APPEND(&p->mchunks, (node_t *)mchunk); - ok = TRUE; - STAT(STAT_MCHUNKS_ATTACH, 1); - } - - _lock_release(&p->lock); - } - - if (!ok) { - STAT(STAT_MCHUNKS_ATTACH_FAILED, 1); - DEBUG_PRINTF("* %T mchunk_attach(%d, %p)\n", memtype, mchunk); - } - - return ok; -} - - -/* Permits to dynamically detach memory at runtime, which was previously - * attached using mchunk_attach(). Note that this function fails with FALSE - * if any page of memory currently remains allocated, or if the mchunk_t is - * not currently attached. - */ -bool mchunk_detach(int memtype, mchunk_t *mchunk) -{ - bool ok = FALSE; - - if (memtype < (enum _memtypes)_MEM_MAX && memtype != _MEM_ANY && - OBJECT_VALID(mchunk, OBJECT_MCHUNK)) { - register ppool_t *p; - register mchunk_t *m; - - p = &root->ppools[memtype]; - - /* Lock system pages safely lock */ - lock_acquire(&p->lock); - - /* Make sure that this chunk is attached in the expected memory type, - * and also make sure that all pages are free (unallocated). - */ - DLIST_FOREACH(&p->mchunks, m) { - if (m == mchunk) - break; - } - if (m == mchunk) { - if (m->pages == DLIST_NODES(&m->free)) { - DLIST_UNLINK(&p->mchunks, (node_t *)m); - ok = TRUE; - STAT(STAT_MCHUNKS_DETACH, 1); - } - } - - _lock_release(&p->lock); - } - - if (!ok) { - STAT(STAT_MCHUNKS_DETACH_FAILED, 1); - DEBUG_PRINTF("* %T mchunk_detach(%d, %p)\n", memtype, mchunk); - } - - return ok; -} - - -/* Requests obtention of one or more contiguous physical pages from the system. - * Returns a pointer to the first page_t on success, or NULL on failure - * (out of memory). If is true, the returned memory area will be - * cleared to 0x00 bytes. To properly be freed, pages_free() is expected to - * be called on the same supplied pointer, which will free back all pages - * which were allocated at once with this function. On success, - * pages_t->address can be used to access our requested memory. - */ -page_t *pages_alloc(int memtype, u_int32_t many, bool zero) -{ - register ppool_t *fp = NULL, *tp = NULL; - page_t *pages = NULL; - bool ok; - - /* If a memory type was specified, only run through that ppool_t, but - * run through each ppool_t in order otherwise until we satisfy the - * request. It is safe to do this interruptible as the memory types - * pools always remain static. - */ - ok = TRUE; - if (many < 1) - ok = FALSE; - else { - if (memtype > -1) { - if (memtype < (enum _memtypes)_MEM_MAX) { - /* Will only try requested memory type */ - fp = tp = &root->ppools[memtype]; - tp++; - } else - ok = FALSE; - } else if (memtype == _MEM_ANY) { - /* Will try all memory types sequencially in order */ - fp = &root->ppools[0]; - tp = &root->ppools[(enum _memtypes)_MEM_MAX]; - tp++; - } else - ok = FALSE; - } - - if (ok) { - /* Loop through ppool_t types */ - for (; fp < tp; fp++) { - register mchunk_t *m; - - lock_acquire(&fp->lock); - - /* Loop through mchunk_t nodes of the ppool_t */ - DLIST_FOREACH(&fp->mchunks, m) { - /* Skip any mchunk_t which doesn't have enough pages */ - if (DLIST_NODES(&m->free) >= many) { - if (many == 1) { - register page_t *p; - - /* No need to look for contiguous pages as only a - * single one was requested. Detach the first page. - */ - p = DLIST_TOP(&m->free); - DLIST_UNLINK(&m->free, &p->node); - p->node.next = p->node.prev = NULL; - p->last = p; - p->state = PS_ALLOCATED; - _lock_release(&fp->lock); - if (zero) - pageclr(p->address, 1); - pages = p; - STAT(STAT_PAGES_ALLOC, 1); - goto end; - } else { - register page_t *n, *o; - register u_int32_t c, oid; - - /* Scan for contiguous pages in this mchunk_t */ - c = 1; - o = DLIST_TOP(&m->free); - oid = o->id; - for (n = DLIST_NEXT(o); n != NULL; n = DLIST_NEXT(n)) { - if (++oid == n->id) { - /* Contiguous, count and continue */ - c++; - if (c == many) - break; - } else { - /* Not contiguous, reset and continue */ - c = 1; - o = n; - } - } - if (c == many) { - register node_t *next, *prev; - - /* contiguous pages were found, starting at - * o and ending at n, unlink them all at once - * efficiently and set last pointer. - */ - prev = o->node.prev; - next = n->node.next; - if (prev) - prev->next = next; - else - m->free.top = next; - if (next) - next->prev = prev; - else - m->free.bottom = prev; - o->node.prev = n->node.next = NULL; - o->last = n; - m->free.nodes -= c; - - /* Then initialize the pages. Unfortunately - * we need to perform this with lock held - * because freeing pages runs among pages - * looking for PS_FREE nodes. - */ - for (n = o; c > 0; - n = (page_t *)n->node.next, c--) - n->state = PS_ALLOCATED; - - /* Finished with system pools, restore level */ - _lock_release(&fp->lock); - - /* It's safe to do the following interruptible */ - if (zero) - pageclr(o->address, many); - pages = o; - STAT(STAT_PAGES_ALLOC, many); - goto end; - } - } - } - } - - _lock_release(&fp->lock); - } - /* If we reach this point the allocation process desperatly failed */ - } - -end: - if (pages == NULL) { - STAT(STAT_PAGES_ALLOC_NOMEM, 1); - DEBUG_PRINTF("- %T pages_alloc(%d, %u, %B) - Out of memory\n", - memtype, many, zero); - } - - return pages; -} - - -/* Frees one or more contiguous pages of physical memory which were obtained - * using pages_alloc(). It is important to call this function on the same - * page_t pointer which was obtained from pages_alloc(). - */ -bool pages_free(page_t *pages) -{ - bool ok = FALSE; - - if (pages != NULL && pages->last != NULL) { - register mchunk_t *m; - register page_t **idx, *fp, *lp, *lfp, *llp; - register u_int32_t id; - - /* Find mchunk_t we belong to, setup variables */ - fp = pages; - lp = pages->last; - m = pages->mchunk; - idx = m->index; - - lock_acquire(&m->ppool->lock); - - /* Reset pages fields. Because the freeing process requires running - * among pages looking for PS_FREE ones, we need to perform this - * while we own the lock. - */ - for (lfp = fp; lfp != NULL; lfp = (page_t *)lfp->node.next) - lfp->state = PS_FREE; - - /* Determine where in the free list_t of our mchunk_t should our page_t - * nodes be inserted. It is important that the free list always remain - * sorted. Using the page index ID of our first and last allocated - * pages, we can run up and down among pages to obtain this - * information. Another possible method would be to use a minheap - * implementation. - */ - for (id = fp->id - 1; id > -1 && idx[id]->state != PS_FREE; id--) ; - if (id == -1 || idx[id]->state == PS_ALLOCATED) - lfp = NULL; - else - lfp = idx[id]; - for (id = lp->id + 1; id < m->pages && idx[id]->state != PS_FREE; - id++) ; - if (id == m->pages || idx[id]->state == PS_ALLOCATED) - llp = NULL; - else - llp = idx[id]; - - /* Now lfp == free page_t to attach first page_t to (or NULL) - * and llp == free page_t to attach last page_t to (or NULL). - * We also know that within this mchunk_t no pages should exist - * between our first and last allocated pages because they are - * contiguous; We thus can safely insert our allocated pages in one - * efficient step between lfp and llp. We could have done the following - * immediately after checking for ID boundaries in the previous loops, - * but decide to perform NULL checking instead for code clarity. - * Link lfp (or top of list) to fp in both directions, and make sure - * to set the list top and bottom pointers when necessary as well. - */ - if (lfp == NULL) { - m->free.top = (node_t *)fp; - fp->node.prev = NULL; - } else { - lfp->node.next = (node_t *)fp; - fp->node.prev = (node_t *)lfp; - } - /* Link llp (or bottom of list) to lp in both directions */ - if (llp == NULL) { - m->free.bottom = (node_t *)lp; - lp->node.next = NULL; - } else { - llp->node.prev = (node_t *)lp; - lp->node.next = (node_t *)llp; - } - /* Fix number of free nodes counter */ - m->free.nodes += (lp->id - fp->id) + 1; - - _lock_release(&m->ppool->lock); - - STAT(STAT_PAGES_FREE, (lp->id - fp->id) + 1); - - /* Make sure to not agree to free these anymore until this page_t * - * is obtained again from pages_alloc(). As the page may have been - * part of a pool_t, we also must zero the pool pointer. - */ - pages->last = NULL; - pages->pool = NULL; - - ok = TRUE; - } - - if (!ok) { - STAT(STAT_PAGES_FREE_FAILED, 1); - DEBUG_PRINTF("* %T pages_free(%p)\n", pages); - } - - return ok; -} - - -/* Initializes a pool_t and allocates the required minimum pages if required. - * The pages of a pool_t can be virtually sized as large as required by - * specifying a steppages larger than 1. steppages * _PAGE_SIZE is the - * actual size of a pool_t page. A pool can then be used to allocate objects - * exceeding _PAGE_SIZE. No locking or synchronization is used by - * pool_t functions, those must be provided externally by the caller if - * needed. Of course internal page allocation/free will be done protected by - * the system pages pool lock. A pool_t links the pages to it's lists via - * the pages_t->poolnode node_t. If minpages == 0, no pages are allocated - * until the first pool_alloc() is called on the pool_t. If maxpages == 0 - * the pool will always attempt to grow dynamically if required (and pnode_t - * allocations will fail if out of memory). If minpages and maxpages are - * non-zero and the same, pages are pre-allocated immediately and the pool - * will never shrink or grow. This can be very useful in the case of critical - * code sections which need to allocate and free objects in an interrupt - * context. A pool_t, unlike an mpool_t, will not allow to specify which - * memory type to allocate at each pnode_t allocation. It is however safe to - * use _MEM_ANY for memtype here in which case any free memory will be used, - * requested and freed as necessary. - */ -bool pool_init(pool_t *pool, u_int32_t steppages, u_int32_t minpages, - u_int32_t maxpages, size_t nodesize, int memtype) -{ - bool ok = FALSE; - - if (pool != NULL && steppages != 0 && nodesize >= sizeof(pnode_t) && - memtype < (enum _memtypes)_MEM_MAX && memtype > -2) { - register size_t psize; - register u_int32_t nodesperpage, step = steppages; - - /* Evaluate how many nodes can fit a page, and that it's realistic. - * There is no point in using a pool_t if we cannot fit at least two - * pnode_t objects per page_t. So we'll automatically increase - * steppages if needed here, upto 8 maximum, and return FALSE if - * we couln't reach a decent size relatively to the object size. - * The reason we're doing this is that Xisop system objects pools - * should grow steppages automatically if needed, and are always sure - * to be small enough to at least fit into 8 pages (usually 1-2). - * We want main.c's spools_init() to always succeed even if - * an object was slightly too large for a single page. - */ - OBJECT_INVALIDATE(pool); - nodesize = (size_t)OALIGN_CEIL(nodesize, u_int32_t); - /* All your optimization are belong to us. */ - for (psize = _PAGE_SIZE * step; - (nodesperpage = psize / nodesize) < 2 && step < 9; - psize = _PAGE_SIZE * (++step)) - STAT(STAT_POOLS_ENLARGED, 1); - if (nodesperpage > 1) { - pool->nodesperpage = nodesperpage; - pool->steppages = step; - pool->minpages = minpages; - pool->maxpages = maxpages; - pool->avgtotal = pool->avgcnt = minpages; - pool->nodesize = nodesize; - pool->memtype = memtype; - DLIST_INIT(&pool->pages); - DLIST_INIT(&pool->fpages); - DLIST_INIT(&pool->nodes); - pool->mpool = NULL; - /* Allocate and initialize pages and nodes if needed */ - for (; minpages > 0; minpages--) { - register page_t *p; - - if ((p = pages_alloc(memtype, step, FALSE)) != NULL) { - register u_int8_t *ptr, *toptr; - - /* pool_t pages are linked via page_t->poolnode */ - p->pnodes = nodesperpage; - p->pool = pool; - DLIST_APPEND(&pool->pages, &p->poolnode); - for (ptr = (u_int8_t *)p->address, toptr = ptr + psize; - ptr + nodesize < toptr; - ptr += nodesize) { - ((pnode_t *)ptr)->page = p; - DLIST_APPEND(&pool->nodes, (node_t *)ptr); - } - } else - break; - } - OBJECT_VALIDATE(pool, OBJECT_POOL); - if (minpages == 0) - ok = TRUE; - else if (minpages < pool->minpages) { - /* Some of minpages were allocated, we need to free them */ - pool_destroy(pool); - DEBUG_PRINTF( - "* %T pool_init(%p, %u, %u, %u, %u, %d) - Out of memory\n", - pool, steppages, minpages, maxpages, nodesize, memtype); - } - } - } - - if (ok) - STAT(STAT_POOLS_CREATED, 1); - else { - STAT(STAT_POOLS_CREATED_FAILED, 1); - DEBUG_PRINTF("* %T pool_init(%p, %u, %u, %u, %u, %d)\n", - pool, steppages, minpages, maxpages, nodesize, memtype); - } - - return ok; -} - - -/* Frees all memory allocated by a pool_t, thus rendering any allocated - * pnode_t objects invalid as well. The pool_t is then marked as invalid, - * it can only be valid again if initialized using pool_init(). - * FALSE is returned if the pool_t is invalidated already. - */ -bool pool_destroy(pool_t *pool) -{ - bool ok = FALSE; - - if (OBJECT_VALID(pool, OBJECT_POOL)) { - register node_t *p, *t; - - /* Just free all pages allocated by the pool, and mark the pool - * as freed/nonfunctional. All nodes on the list will be reset if - * a new pool is initialized using this pool_t *. They become - * invalid as soon as pages are freed, since they only consist of - * pointers into those pages. Remember that pool pages are tied - * up in the list_t via the page_t->poolnode node_t. - */ - for (p = DLIST_TOP(&pool->pages); p != NULL; p = t) { - t = DLIST_NEXT(p); - pages_free((page_t *)(--p)); - } - for (p = DLIST_TOP(&pool->fpages); p != NULL; p = t) { - t = DLIST_NEXT(p); - pages_free((page_t *)(--p)); - } - OBJECT_INVALIDATE(pool); - ok = TRUE; - } - - if (ok) - STAT(STAT_POOLS_DESTROYED, 1); - else { - STAT(STAT_POOLS_DESTROYED_FAILED, 1); - DEBUG_PRINTF("* %T pool_destroy(%p)\n", pool); - } - - return ok; -} - - -/* Attempts to allocate a pnode_t from the specified pool_t, and optionally - * clear the object to 0x00 bytes if zero is TRUE. NULL is returned if - * no memory was available or if the pool was setup to not be able to hold - * more objects. The size of the pnode_t prefixed object depends on the - * attributes which were set forthe pool_t at pool_init(). As each node - * object should start with a pnode_t structure, we return a pointer to - * the object structure itself at the same time. The type of memory used - * can only be the one the pool_t was initialized for. The pnode_t allocation - * process is efficient, compared to managing page_t. Special care is taken - * to avoid calling page primitives as much as possible using buffering, - * while still allowing a pool_t to be dynamically resizing if wanted. - */ -pnode_t *pool_alloc(pool_t *pool, bool zero) -{ - pnode_t *pnode = NULL; - - if (OBJECT_VALID(pool, OBJECT_POOL)) { - register pnode_t *pn; - - /* If there are pre-buffered nodes, simply return the first one. */ - if ((pn = DLIST_TOP(&pool->nodes)) != NULL) { - DLIST_UNLINK(&pool->nodes, (node_t *)pn); - pn->page->pnodes--; - if (zero) { - register page_t *p; - - p = pn->page; - memclr(pn, pool->nodesize); - pn->page = p; - } - pnode = pn; - } else { - register page_t *p = NULL; - register node_t *n; - - /* No pnode_t left, we need to allocate a new page_t to grow and - * initialize the new bnode_t objects. First verify if there is - * any available page already in our cache, which pool_free() - * maintains using statistics, to minimize calls to page - * primitives functions. If there are none, allocate a new page_t. - * Remember that we link the pages via the page_t->poolnode node_t. - */ - if (pool->maxpages == 0 || - DLIST_NODES(&pool->pages) < pool->maxpages) { - if ((n = DLIST_TOP(&pool->fpages)) != NULL) { - DLIST_UNLINK(&pool->fpages, n); - p = (page_t *)(--n); - STAT(STAT_PAGES_REUSED, pool->steppages); - } else - p = pages_alloc(pool->memtype, pool->steppages, FALSE); - if (p != NULL) { - register u_int8_t *ptr, *toptr; - register size_t nodesize = pool->nodesize; - - p->pnodes = pool->nodesperpage; - p->pool = pool; - DLIST_APPEND(&pool->pages, &p->poolnode); - for (ptr = (u_int8_t *)p->address, - toptr = ptr + _PAGE_SIZE * pool->steppages; - ptr + nodesize < toptr; - ptr += nodesize) { - ((pnode_t *)ptr)->page = p; - DLIST_APPEND(&pool->nodes, (node_t *)ptr); - } - /* Now grab first pnode_t */ - pn = DLIST_TOP(&pool->nodes); - DLIST_UNLINK(&pool->nodes, (node_t *)pn); - p->pnodes--; - if (zero) - memclr(pn, nodesize); - pn->page = p; - pnode = pn; - } - } else { - STAT(STAT_POOLS_ALLOC_NOMEM, 1); - DEBUG_PRINTF("- %T pool_alloc(%p, %B) - Out of memory\n", - pool, zero); - } - } - } else { - STAT(STAT_POOLS_ALLOC_FAILED, 1); - DEBUG_PRINTF("* %T pool_alloc(%p, %B)\n", pool, zero); - } - - if (pnode != NULL) - STAT(STAT_POOLS_ALLOC, 1); - - return pnode; -} - - -/* Used to free a node previously allocated using pool_alloc(). - * Keeps statistics and a page cache to reduce the frequency at which - * pages_*() functions need to be called. - */ -pnode_t *pool_free(pnode_t *pnode) -{ - if (pnode != NULL && OBJECT_VALID(pnode->page->pool, OBJECT_POOL)) { - register page_t *p = pnode->page; - register pool_t *pool = p->pool; - register u_int32_t exceeding; - - /* Efficiently return this node in the free list */ - DLIST_INSERT(&pool->nodes, (node_t *)pnode); - p->pnodes++; - STAT(STAT_POOLS_FREE, 1); - if ((pool->minpages < pool->maxpages) || - (pool->minpages == 0 && pool->maxpages == 0)) { - register u_int32_t pages = DLIST_NODES(&pool->pages); - - /* This is a pool_t which can shrink, book-keep statistics on - * average pages usage. - */ - pool->avgtotal += pages; - pool->avgcnt++; - if (pool->avgcnt > - ((pool->steppages * _PAGE_SIZE / pool->nodesize) * 3)) { - pool->avgcnt = 1; - pool->avgtotal = pages; - } - - if (p->pnodes == pool->nodesperpage && pool->minpages < pages) { - register u_int8_t *ptr, *toptr; - register size_t nodesize; - - /* All pnode_t objects belonging to this page_t were freed. - * Swap the page to the cache to be freed. We also need - * to sequencially unlink all the pnode_t objects this page - * supplied in the free nodes list_t. Remember that pages - * are linked via the page_t->poolnode node_t. - */ - for (ptr = (u_int8_t *)p->address, - toptr = ptr + _PAGE_SIZE * pool->steppages, - nodesize = pool->nodesize; - ptr + nodesize < toptr; - ptr += nodesize) - DLIST_UNLINK(&pool->nodes, (node_t *)ptr); - /* Insert to preferably reuse recently used pages */ - DLIST_SWAP(&pool->fpages, &pool->pages, &(p->poolnode), TRUE); - STAT(STAT_PAGES_BUFFERED, pool->steppages); - } - - /* Do statistics suggest that we should shrink the pool? If so, - * free pages from our cache back to the system. - */ - if ((exceeding = (DLIST_NODES(&pool->pages) + - DLIST_NODES(&pool->fpages)) - - (pool->avgtotal / pool->avgcnt)) > 0) { - register list_t *fpages = &pool->fpages; - register node_t *n; - - /* Preferably free pages which haven't been used recently */ - for (; exceeding > 0 && (n = fpages->bottom) != NULL; - exceeding--) { - DLIST_UNLINK(fpages, n); - p = (page_t *)(--n); - pages_free(p); - STAT(STAT_PAGES_UNBUFFERED, pool->steppages); - } - } - } - } else { - STAT(STAT_POOLS_FREE_FAILED, 1); - DEBUG_PRINTF("* %T pool_free(%p)\n", pnode); - } - - return NULL; -} - - -/* Finally, the higher-level general purpose allocation system consists of - * a bunch of pool_t, as well as a page_t list_t for requests which exceed - * in size and need to be rounded at page boundaries. Memory of all available - * types may be allocated and freed at will, and of arbitrary sized blocks. - * The current implementation requires more memory for mpool setup than - * previously, there however are advantages in versatility, performance - * and code quality over the latter. - * We depend on _PAGE_SIZE and _MPOOLS which should be defined by the - * port-specific code (port/support.h). - * No special synchronization is performed in these functions, the caller - * is required to provide it where necessary (i.e. shared mpool_t). However, - * the underlaying page_t primitives use the system pages pool lock. - */ -bool mpool_init(mpool_t *mpool) -{ - bool ok = FALSE; - - if (mpool != NULL) { - register int t, p; - register size_t c = _MPOOLSTART; - - DLIST_INIT(&mpool->pages); - ok = TRUE; - OBJECT_VALIDATE(mpool, OBJECT_MPOOL); - for (p = 0; p < _MPOOLS; p++) { - for (t = 0; t < (enum _memtypes)_MEM_MAX; t++) { - if (!pool_init(&mpool->pools[p][t], _MPOOLSTEP, 0, 0, - sizeof(mnode_t) + c, t)) - ok = FALSE; - else - mpool->pools[p][t].mpool = mpool; - } - c *= 2; - } - if (!ok) { - /* Make sure to free everything if part of the system only could be - * setup - */ - mpool_destroy(mpool); - } else { - mpool->shared = FALSE; - _lock_init(&mpool->lock); - mpool->usecount = 0; - } - } - - if (ok) - STAT(STAT_MPOOLS_CREATED, 1); - else { - STAT(STAT_MPOOLS_CREATED_FAILED, 1); - DEBUG_PRINTF("* %T mpool_init(%p)\n", mpool); - } - - return ok; -} - - -bool mpool_destroy(mpool_t *mpool) -{ - bool ok = FALSE; - - if (OBJECT_VALID(mpool, OBJECT_MPOOL)) { - register int t, p; - register node_t *pg, *tmp; - register u_int32_t usecount = 0; - - if (mpool->shared) { - lock_acquire(&mpool->lock); - usecount = --mpool->usecount; - _lock_release(&mpool->lock); - } - if (usecount < 1) { - /* All your pool_t are belong to us. */ - for (p = 0; p < _MPOOLS; p++) - for (t = 0; t < (enum _memtypes)_MEM_MAX; t++) - pool_destroy(&mpool->pools[p][t]); - /* And rounded page requests too. Remember that they are tied via - * the page_t->poolnode node_t in our list_t. - */ - for (pg = DLIST_TOP(&mpool->pages); pg != NULL; pg = tmp) { - tmp = DLIST_NEXT(pg); - pages_free((page_t *)(--pg)); - } - OBJECT_INVALIDATE(mpool); - ok = TRUE; - STAT(STAT_MPOOLS_DESTROYED, 1); - } - } else { - STAT(STAT_MPOOLS_DESTROYED_FAILED, 1); - DEBUG_PRINTF("* %T mpool_destroy(%p)\n", mpool); - } - - return ok; -} - - -/* malloc() clone which can be specified mpool_t to use, memory type - * and optional memory clear flag. - */ -void *_malloc(mpool_t *mpool, int memtype, size_t size, bool zero) -{ - void *mem = NULL; - - if (OBJECT_VALID(mpool, OBJECT_MPOOL) && - (memtype == _MEM_ANY || memtype < (enum _memtypes)_MEM_MAX)) { - register int p; - register size_t rsize; - - /* Synchronization for cases where multiple tasks share an mpool_t */ - if (mpool->shared) - lock_acquire(&mpool->lock); - - /* Verify if any of our pool_t can serve the requested size */ - rsize = (size_t)OALIGN_CEIL(sizeof(mnode_t), u_int32_t); - rsize += size; - for (p = 0; p < _MPOOLS; p++) { - if (mpool->pools[p][0].nodesize >= rsize) { - register mnode_t *n = NULL; - - /* This pool can serve this request. */ - if (memtype == _MEM_ANY) { - register int t; - - /* Try available memory types in order */ - for (t = 0; t < (enum _memtypes)_MEM_MAX; t++) { - n = (mnode_t *)pool_alloc(&mpool->pools[p][t], zero); - if (n != NULL) - break; - } - } else - n = (mnode_t *)pool_alloc(&mpool->pools[p][memtype], zero); - if (n != NULL) { - /* Best case, everything went fine */ - n->type = MNT_PNODE; - OBJECT_VALIDATE(n, OBJECT_MNODE); - mem = (++n); - break; - } else { - STAT(STAT_MPOOLS_ALLOC_NOMEM, 1); - DEBUG_PRINTF( - "- %T _malloc(%p, %d, %u, %B) - Out of memory\n", - mpool, memtype, size, zero); - } - } - } - if (p == _MPOOLS) { - register u_int32_t many; - register page_t *p; - - /* We need to round size on page boundaries and allocate pages. - * If we were requested zeroed memory, the pageclr() will be used - * internally which is more efficient than memclr(). - */ - many = rsize / _PAGE_SIZE; - if (rsize % _PAGE_SIZE) - many++; - if ((p = pages_alloc(memtype, many, zero)) != NULL) { - register mnode_t *n = p->address; - - /* Link in our pages list via the page_t->poolnode node_t */ - DLIST_APPEND(&mpool->pages, &p->poolnode); - n->u.pgnode.pages = p; - n->u.pgnode.mpool = mpool; - n->type = MNT_PAGES; - OBJECT_VALIDATE(n, OBJECT_MNODE); - mem = (++n); - } else { - STAT(STAT_MPOOLS_ALLOC_NOMEM, 1); - DEBUG_PRINTF("- %T _malloc(%p, %d, %u, %B) - Out of memory\n", - mpool, memtype, size, zero); - } - } - - if (mpool->shared) - _lock_release(&mpool->lock); - } else { - STAT(STAT_MPOOLS_ALLOC_FAILED, 1); - DEBUG_PRINTF("* %T _malloc(%p, %d, %u, %B)\n", - mpool, memtype, size, zero); - } - - if (mem != NULL) - STAT(STAT_MPOOLS_ALLOC, 1); - - return mem; -} - - -/* free() clone for _malloc() */ -void *_free(void *block) -{ - register mpool_t *mpool = NULL; - - if (block != NULL) { - register mnode_t *mn = block; - - mn--; - if (OBJECT_VALID(mn, OBJECT_MNODE)) { - - OBJECT_INVALIDATE(mn); - switch (mn->type) { - case MNT_PNODE: - /* A pool_t pnode_t which needs to be freed back. Track our - * mpool_t for synchronization if required. - */ - if ((mpool = mn->u.pnode.page->pool->mpool) != NULL) { - if (mpool->shared) - lock_acquire(&mpool->lock); - else - mpool = NULL; - } - pool_free((pnode_t *)mn); - break; - case MNT_PAGES: - { - register page_t *p = mn->u.pgnode.pages; - - /* A page_t which needs to be unlinked and freed. - * Remember that pages are linked via page_t->poolnode - * node_t. Track our mpool_t for synchronization if needed. - */ - mpool = mn->u.pgnode.mpool; - if (mpool->shared) - lock_acquire(&mpool->lock); - else - mpool = NULL; - DLIST_UNLINK(&mn->u.pgnode.mpool->pages, &p->poolnode); - pages_free(p); - break; - } - } - STAT(STAT_MPOOLS_FREE, 1); - } else { - STAT(STAT_MPOOLS_FREE_FAILED, 1); - DEBUG_PRINTF("* %T _free(%p)\n", block); - } - } else { - STAT(STAT_MPOOLS_FREE_FAILED, 1); - DEBUG_PRINTF("* %T _free(%p)\n", block); - } - if (mpool != NULL) - _lock_release(&mpool->lock); - - return NULL; -} - - - -/* This function initializes the various pool_t and _lock_t which are reserved - * to allocate specific types of Xisop system objects for efficiency. - */ -void spools_init(void) -{ - register int i; - - /* XXX Should panic on failure */ - for (i = 0; i < (enum _syspools)POOL_MAX; i++) { - _lock_init(&root->spools_locks[i]); - (void) pool_init(&root->spools[i], syspools_params[i].steppages, - syspools_params[i].minpages, - syspools_params[i].maxpages, - syspools_params[i].nodesize, 0); - } -} - - -pnode_t *spool_alloc(u_int32_t pool) -{ - pnode_t *node = NULL; - - if (pool < (enum _syspools)POOL_MAX) { - lock_acquire(&root->spools_locks[pool]); - node = pool_alloc(&root->spools[pool], FALSE); - _lock_release(&root->spools_locks[pool]); - } - - if (node == NULL) - DEBUG_PRINTF("* %T spool_alloc(%u)\n", pool); - - return node; -} - - -pnode_t *spool_free(u_int32_t pool, pnode_t *node) -{ - if (pool < (enum _syspools)POOL_MAX) { - lock_acquire(&root->spools_locks[pool]); - if (!pool_free(node)) - DEBUG_PRINTF("* %T spool_free(%u, %p)\n", pool, node); - _lock_release(&root->spools_locks[pool]); - } - - return NULL; -} - - -/* Specifically made to allocate general purpose memory for the kernel. - * Although mpool_t now can support synchronization itself when shared, - * it is faster to perform it unconditionally. - */ -void *_kmalloc(int memtype, size_t size, bool zero) -{ - void *mem = NULL; - - lock_acquire(&root->kernpool_lock); - mem = _malloc(root->kernpool, memtype, size, zero); - _lock_release(&root->kernpool_lock); - - return mem; -} - -void *_kfree(void *mem) -{ - lock_acquire(&root->kernpool_lock); - _free(mem); - _lock_release(&root->kernpool_lock); - - return NULL; -} - - -/* Closer to ANSI-C but still for general purpose kernel memory */ -void *kmalloc(size_t size) -{ - return MALLOC(size); -} - -void kfree(void *mem) -{ - FREE(mem); -} - - -/* These functions are ANSI-C standard, and only use the current task pool. */ - -void *malloc(size_t size) -{ - return _malloc(CURTASK()->mpool, _MEM_ANY, size, FALSE); -} - -void *calloc(int number, size_t size) -{ - return _malloc(CURTASK()->mpool, _MEM_ANY, number * size, TRUE); -} - -void *realloc(void *ptr, size_t size) -{ - register void *nptr = ptr; - - /* Not very efficient, but mostly provided for compatibility. */ - if (nptr != NULL) { - if (size == 0) - /* Basically a request to free the buffer */ - nptr = _free(nptr); - else { - register mnode_t *mnode; - - /* Climb up to obtain actual buffer size */ - mnode = (mnode_t *)nptr; - mnode--; - if (OBJECT_VALID(mnode, OBJECT_MNODE)) { - register size_t osize; - - switch (mnode->type) { - case MNT_PNODE: - { - osize = mnode->u.pnode.page->pool->nodesize - - sizeof(mnode_t); - break; - } - case MNT_PAGES: - { - register page_t *pages = mnode->u.pgnode.pages; - - osize = ((pages->last->id - pages->id) +1) * - _PAGE_SIZE; - break; - } - default: - nptr = NULL; - osize = 0; - break; - } - - /* Is the requested size larger than the currently available - * number of bytes? If not, don't do anything, return the - * current buffer pointer. - */ - if (nptr != NULL && osize < size) { - /* Allocate a buffer which can at least hold the requested - * number of bytes. Well at least, attempt to. If we can't - * don't do anything and return NULL. - */ - if ((nptr = malloc(size)) != NULL) { - /* Allocation successful, copy all previous buffer - * contents to the new one, then free the old buffer, - * and return the new buffer pointer. - */ - memcpy(nptr, ptr, osize); - free(ptr); - } - } - } else - nptr = NULL; - } - } else - /* A request to simply allocate */ - nptr = malloc(size); - - return nptr; -} - -void free(void *ptr) -{ - _free(ptr); -} - - -/* Xisop extentions as we support multiple memory types */ -void *tmalloc(int memtype, size_t size) -{ - return _malloc(CURTASK()->mpool, memtype, size, FALSE); -} - -void *tcmalloc(int memtype, int number, size_t size) -{ - return _malloc(CURTASK()->mpool, memtype, number * size, TRUE); -} - - - -/* The following code is only compiled in if DEBUG was #defined in config.h */ -#ifdef DEBUG - - -/* Dump the current state of all memory pages in the system. */ -void pages_dump(void) -{ - register u_int32_t ppool; - _ipl_t x; - - /* Become absolutely uninterruptible */ - x = _splhigh(); - - debug_printf("\nCURRENT STATE OF SYSTEM MEMORY PAGES\n"); - for (ppool = 0; ppool < (enum _memtypes)_MEM_MAX; ppool++) { - register mchunk_t *mchunk; - - debug_printf("\nDumping mchunks for ppool_t of _MEM_TYPE %u\n", - ppool); - DLIST_FOREACH(&(root->ppools[ppool].mchunks), mchunk) { - register page_t **index = mchunk->index; - register u_int32_t id, pages = mchunk->pages; - - debug_printf( - " Dumping pages for mchunk_t *%p (%u pages, page_t **%p)\n", - mchunk, pages, index); - debug_printf(" mchunk->free.top = "); - if (mchunk->free.top != NULL) - debug_printf( - "%u (page_t *%p)\n", ((page_t *)mchunk->free.top)->id, - mchunk->free.top); - else - debug_printf("NULL\n"); - debug_printf(" mchunk->free.bottom = "); - if (mchunk->free.bottom != NULL) - debug_printf("%u (page_t *%p)\n", - ((page_t *)mchunk->free.bottom)->id, - mchunk->free.bottom); - else - debug_printf("NULL\n"); - for (id = 0; id < pages; id++) { - register page_t *page = index[id]; - - /* Print summary information */ - debug_printf(" - %u (page_t *%p, void *%p)\n next = ", - id, page, page->address); - if (page->node.next == NULL) - debug_printf("NULL, prev = "); - else - debug_printf("%u (page_t *%p), prev = ", - ((page_t *)page->node.next)->id, - page->node.next); - if (page->node.prev == NULL) - debug_printf("NULL\n"); - else - debug_printf("%u (page_t *%p)\n", - ((page_t *)page->node.prev)->id, - page->node.prev); - - /* Rest will vary depending if page is allocated */ - if(page->state == PS_ALLOCATED) { - debug_printf(" Allocated, last = "); - if (page->last != NULL) - debug_printf("%u (page_t *%p)\n", page->last->id, - page->last); - else - debug_printf("NULL\n"); - if (page->pool != NULL) - debug_printf(" pool_t = *%p, mem %d, nodesize %u\n", - page->pool, page->pool->memtype, - page->pool->nodesize); - } else - debug_printf(" Free\n"); - - /* Perform some basic sanity checking and report problems - * which are known to disrupt the system. If those occur, - * the pools were corrupted and the system may need a reset - * for proper operation. - */ - if (page->node.next != NULL) { - register node_t *n = page->node.next; - - if (n->prev == NULL) - debug_printf( - " * page->node.next->node.prev = NULL\n"); - else if (n->prev != &page->node) - debug_printf( - " * page->node.next->node.prev != page\n"); - } - if (page->node.prev != NULL) { - register node_t *n = page->node.prev; - - if (n->next == NULL) - debug_printf( - " * page->node.prev->node.next = NULL\n"); - else if (n->next != &page->node) - debug_printf( - " * page->node.prev->node.next != page\n"); - } - if (page->id != id) - debug_printf(" * page->id != index[id]\n"); - if (page->state != PS_FREE && page->state != PS_ALLOCATED) - debug_printf(" * Unknown page->state\n"); - if (page->state == PS_FREE && page->last != NULL) - debug_printf(" * PS_FREE && last != NULL\n"); - if (page->state == PS_FREE && page->pool != NULL) - debug_printf(" * PS_FREE && page->pool != NULL"); - if (page->mchunk != mchunk) - debug_printf(" * page->mchunk != mchunk\n"); - } - } - } - - _splx(x); -} - - -#endif diff --git a/Xisop/src/common/kernel/memory.h b/Xisop/src/common/kernel/memory.h deleted file mode 100644 index 146d7b8..0000000 --- a/Xisop/src/common/kernel/memory.h +++ /dev/null @@ -1,260 +0,0 @@ -/* $Id: memory.h,v 1.4 2004/06/04 03:09:48 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_MEMORY_H -#define KERNEL_MEMORY_H - - - -#include -#include -#include -#include - - - -/* Only common memory type which is always available */ -#define _MEM_ANY -1 - -/* Page state */ -#define PS_FREE 0 -#define PS_ALLOCATED 1 - -/* mnode_t types */ -#define MNT_PNODE 0 -#define MNT_PAGES 1 - - - -/* This is a memory page node. One is required for each physical page which - * is to be included in the memory management system. The pool_t related - * fields seem to pollute the page space, but there is no better place to put - * them; Using an additional page_t based structure for pool_t page_t nodes - * would require allocating more memory. The pool_t primitives are such a - * vital element to Xisop that we can add support for it inherently. - */ -struct page { - node_t node; /* Link to pages_free of mchunk or pages_t */ - node_t poolnode; /* Used for pool_t page linking */ - mchunk_t *mchunk; /* mchunk_t we belong to for freeing */ - void *address; /* Page address in memory (should be 32-bit aligned) */ - page_t *last; /* Allocated? Link to last contiguous node, or NULL */ - pool_t *pool; /* If part of a pool_t, pointer to the pool_t */ - u_int32_t id; /* Page index offset in mchunk_t */ - u_int32_t pnodes; /* Number of free blocks in this page_t for pool_t */ - u_int32_t state; /* PS_FREE | PS_ALLOCATED */ -}; - -/* A chunk of memory consists of an arbitrary amount of contiguous pages - * of physical memory. This construct allows to dynamically append memory - * which can be mapped anytime, i.e. PCMCIA memory which just was inserted. - * Obviously, to add new memory some memory is required to be setup for the - * lists, index and page nodes. This memory should never be freed back unless - * it is certain that the device was detached, and all allocated memory on it - * is to be discarded. Each such chunk will be scanned in order for available - * memory when memory is to be allocated from a ppool_t. - */ -struct mchunk { - node_t node; /* Link to mpool_t */ - list_t free; /* List of free pages */ - ppool_t *ppool; /* Link to ppool_t we belong to */ - page_t **index; /* Index of all pages in this mchunk_t */ - u_int32_t pages; /* Number of pages in this mchunk_t */ - u_int32_t object_magic; /* Validity sceal */ -}; - -/* A pool of pages, there is one such pool per memory type. These are - * initialized by the port-specific _init_memory() function. - */ -struct ppool { - _lock_t lock; /* Secure exclusive access lock */ - list_t mchunks; /* List of mchunk_t objects */ -}; - - - -/* A pool used to allocate objects of a fixed size, which are smaller than - * half a page. maxpages permits to restrict the pool from growing more than - * wanted, minpages specifies the minimum number of pages which should always - * remain allocated (and setup as objects), avgtotal and avgcnt are used for - * statistics when freeing pages (and destroying their objects). An unused - * page is moved to fpages list, and moved back in pages list when an object - * on the page is used. If statistics show that the pool should shrink, pages - * from fpages are freed back to the system (unless minpages is reached). - * steppages specify how many pages to allocate and free at once. A page size - * for the pool consists of steppages * _PAGE_SIZE. All pool objects always - * start by a node_t, used for internal linking when freed, and can be used - * for custom linking after allocation until freed back. - */ -struct pool { - u_int32_t steppages, minpages, /* Size requirements */ - maxpages; - u_int32_t avgtotal, avgcnt; /* Statistics for page_t cache */ - u_int32_t nodesperpage; /* Number of pnode_t per page_t */ - size_t nodesize; /* 32-bit aligned size of pnode_t */ - list_t pages, fpages, /* Allocated and cached page_t's */ - nodes; /* Ready free pnode_t's */ - int memtype; /* Memory type to allocate */ - u_int32_t object_magic; /* Validity sceal */ - mpool_t *mpool; /* mpool_t we belong to (or NULL) */ -}; - -/* A pool_t node */ -struct pnode { - node_t node; /* pool_t->nodes or user list_t linking */ - page_t *page; /* page_t this pnode_t belongs to */ -}; - - - -/* And finally, the general purpose memory management functions, allowing - * blocks of memory of arbitrary size and type to be allocated and freed back, - * internally based upon the pool_t system. - */ -struct mpool { - /* All required pool_t for the various memory types and request sizes */ - pool_t pools[_MPOOLS][(enum _memtypes)_MEM_MAX]; - list_t pages; /* Large requests rounded on page boundaries */ - u_int32_t object_magic; /* Validity sceal */ - /* These are used in the case where several tasks share a common mpool_t, - * In which case the mpool_t is synchronized and only destroyed when no - * more tasks are using it. Because Xisop does not support MMU the - * requirement for this is questionable. Especially that through the - * message passing system tasks can easily synchronize on wanted shared - * memory regions. It can however save some memory on very small systems. - * All tasks could potentially share the same mpool_t if the init task - * was setup to do so, for instance. - */ - bool shared; - _lock_t lock; - u_int32_t usecount; -}; - -/* An mpool_t node, which prefixes all allocated blocks, the ones from pools - * as well as the ones made of rounded pages (which were too large to satisfy - * using the pool_t objects). Contrary to pool_*() and pages_*() functions, the - * mnode_t is abstracted and hidden in the supplied data block. The pointer - * supplied to the caller points immediately after this structure - * (32-bit aligned). We use a union to reduce as much as possible the size - * of the structure, and be able to reference back to both pnode_t or - * page_t + mpool_t objects. - */ -struct mnode { - union { - pnode_t pnode; /* We're a pnode_t */ - struct { - page_t *pages; /* We're a page_t from mpool_t */ - mpool_t *mpool; - } pgnode; - } u; - int type; /* MNT_PAGES || MNT_PNODE */ - u_int32_t object_magic; /* Validity sceal */ -}; - - - -/* The pool_t types Xisop initializes for efficient management of common - * system objects. These should correspond to the osize structure defined in - * memory.c's spools_init() function. - */ -enum _syspools { - POOL_TASK = 0, - POOL_PORT, - POOL_DEVICENODE, - POOL_DEVICEHANDLE, - POOL_MPOOL, - POOL_MAX -}; - -/* An array of these is filled in memory.c for pools initialization */ -struct syspools_params { - const char *label; - u_int32_t steppages, minpages, maxpages; - size_t nodesize; -}; - - - -/* Useful macros intended to be used by kernel code */ -#define TMALLOC(t, s) _kmalloc((t), (s), FALSE) -#define TCMALLOC(t, n, s) _kmalloc((t), (n) * (s), TRUE) -#define MALLOC(s) _kmalloc(_MEM_ANY, (s), FALSE) -#define CMALLOC(n, s) _kmalloc(_MEM_ANY, (n) * (s), TRUE) -#define FREE(p) _kfree((p)) - - - -void memory_init(void); - -void spools_init(void); -pnode_t *spool_alloc(u_int32_t); -pnode_t *spool_free(u_int32_t, pnode_t *); - -mchunk_t *mchunk_init(void *, size_t); -bool mchunk_attach(int, mchunk_t *); -bool mchunk_detach(int, mchunk_t *); - -page_t *pages_alloc(int, u_int32_t, bool); -bool pages_free(page_t *); - -bool pool_init(pool_t *, u_int32_t, u_int32_t, u_int32_t, size_t, int); -bool pool_destroy(pool_t *); -pnode_t *pool_alloc(pool_t *, bool); -pnode_t *pool_free(pnode_t *); - -bool mpool_init(mpool_t *); -bool mpool_destroy(mpool_t *); -void *_malloc(mpool_t *, int, size_t, bool); -void *_free(void *); -#define mpool_alloc _malloc -#define mpool_free _free - -void *_kmalloc(int, size_t, bool); -void *_kfree(void *); -void *kmalloc(size_t); -void kfree(void *); - -void *malloc(size_t); -void *calloc(int, size_t); -void *realloc(void *, size_t); -void free(void *); -void *tmalloc(int, size_t); -void *tcmalloc(int, int, size_t); - - - -#endif diff --git a/Xisop/src/common/kernel/object.h b/Xisop/src/common/kernel/object.h deleted file mode 100644 index f9a3e23..0000000 --- a/Xisop/src/common/kernel/object.h +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id: object.h,v 1.4 2004/06/04 19:03:36 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* For a good example of code which uses these, look at port.c's port_create(), - * port_reply() and port_destroy() functions. - */ - - - -#ifndef COMMON_KERNEL_OBJECT_H -#define COMMON_KERNEL_OBJECT_H - - - -#include - - - -/* These should be unique and quite uncommon to happen randomly */ -#define OBJECT_PORT 0x504f5254 /* PORT */ -#define OBJECT_TASK 0x5441534b /* TASK */ -#define OBJECT_POOL 0x504f4f4c /* POOL */ -#define OBJECT_MPOOL 0x4d504f4c /* MPOL */ -#define OBJECT_MNODE 0x4d4e4f44 /* MNOD */ -#define OBJECT_MCHUNK 0x4d43484b /* MCHK */ -#define OBJECT_DEVICEHANDLE 0x44455648 /* DEVH */ -#define OBJECT_DEVICENODE 0x4445564e /* DEVN */ -#define OBJECT_IOREQUEST 0x494f5251 /* IORQ */ -#define OBJECT_HASHTABLE 0x4854424c /* HTBL */ -#define OBJECT_HASHNODE 0x484e4f44 /* HNOD */ - - - -/* Validate an object */ -#define OBJECT_VALIDATE(o, m) (o)->object_magic = (m) -/* Invalidate an object */ -#define OBJECT_INVALIDATE(o) (o)->object_magic = 0 -/* Register an object which others could depend on */ -#define OBJECT_REGISTER(o) (o)->object_id = unique_id() -/* Register a dependancy for the object */ -#define OBJECT_SETDEP(o, r) do { \ - (o)->objdep_id = (r)->object_id; \ - (o)->objdep_magic = (r)->object_magic; \ -} while (/* CONSTCOND */0) - -/* Returns TRUE if the object is valid and of expected type, FALSE if not */ -#define OBJECT_VALID(o, m) ((o) != NULL && (o)->object_magic == (m)) -/* Returns TRUE if the object's dependancy matches with (d) */ -#define OBJECT_DEPENDS(o, d) ((d) != NULL && \ - (d)->object_magic == (o)->objdep_magic && \ - (d)->object_id == (o)->objdep_id) - - - -#endif diff --git a/Xisop/src/common/kernel/port.c b/Xisop/src/common/kernel/port.c deleted file mode 100644 index 8e17e36..0000000 --- a/Xisop/src/common/kernel/port.c +++ /dev/null @@ -1,337 +0,0 @@ -/* $Id: port.c,v 1.7 2004/10/14 15:05:23 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -port_t *port_create(const char *name) -{ - bstr_t *bstr = NULL; - signum_t signum; - - if (name != NULL) { - if ((bstr = bstr_new(name, 32, FALSE)) == NULL) { - STAT(STAT_PORTS_CREATED_NOMEM, 1); - DEBUG_PRINTF("* %T port_create(%p) - Out of memory\n", name); - } else { - SYSTABLE_RLOCK(SYSTABLE_PUBLICPORTS); - if ((hashtable_lookup(SYSTABLE(SYSTABLE_PUBLICPORTS), bstr->data, - bstr->len)) != NULL) { - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - STAT(STAT_PORTS_CREATED_EXISTS, 1); - DEBUG_PRINTF("* %T port_create(%p) - Port exists (%s)\n", - bstr->data); - bstr = bstr_free(bstr); - } - } - } - if (name == NULL || bstr != NULL) { - if ((signum = signal_alloc()) != -1) { - register task_t *task = CURTASK(); - register port_t *port = NULL; - - if ((port = (port_t *)spool_alloc(POOL_PORT)) != NULL) { - /* Validate object, and register it since message_t depends on - * us for reply-port validation - */ - OBJECT_VALIDATE(port, OBJECT_PORT); - OBJECT_REGISTER(port); - /* Initialize other port_t fields */ - port->sigtask = task; - port->signum = signum; - DLIST_INIT(&port->messages); - port->name = bstr; - if (bstr != NULL) { - /* Public port, link via sysnode */ - SYSTABLE_UPGRADE(SYSTABLE_PUBLICPORTS); - (void) hashtable_link(SYSTABLE(SYSTABLE_PUBLICPORTS), - (hashnode_t *)port, bstr->data, - bstr->len, FALSE); - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - } - /* Register task resource */ - SCHED_DISABLE(); - DLIST_APPEND(&task->resources.ports, &port->tasknode); - SCHED_ENABLE(); - STAT(STAT_PORTS_CREATED, 1); - - return port; - } else { - if (bstr != NULL) - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - STAT(STAT_PORTS_CREATED_NOMEM, 1); - DEBUG_PRINTF("* %T port_create(%p) - Out of memory\n", name); - } - signal_free(SIGMASK(signum)); - } else { - if (bstr != NULL) - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - STAT(STAT_PORTS_CREATED_NOSIG, 1); - DEBUG_PRINTF("* %T port_create(%p) - Out of signals\n", name); - } - } - - if (bstr != NULL) - bstr_free(bstr); - - return NULL; -} - - -/* Can destroy a port of any task. */ -port_t *port_destroy(port_t *port) -{ - if (OBJECT_VALID(port, OBJECT_PORT)) { - register task_t *task = port->sigtask; - - SCHED_DISABLE(); - OBJECT_INVALIDATE(port); - _signal_free(task, PORT_SIGMASK(port)); - /* Unlink task resource, linked via tasknode */ - DLIST_UNLINK(&task->resources.ports, &port->tasknode); - SCHED_ENABLE(); - if (port->name != NULL) { - bstr_free(port->name); - /* Unlink system resource, linked via sysnode */ - SYSTABLE_WLOCK(SYSTABLE_PUBLICPORTS); - hashtable_unlink(SYSTABLE(SYSTABLE_PUBLICPORTS), - (hashnode_t *)port); - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - } - spool_free(POOL_PORT, (pnode_t *)port); - STAT(STAT_PORTS_DESTROYED, 1); - } else { - STAT(STAT_PORTS_DESTROYED_FAILED, 1); - DEBUG_PRINTF("* %T port_destroy(%p)\n", port); - } - - return NULL; -} - - -port_t *port_find(const char *name) -{ - register port_t *port = NULL; - - if (name != NULL) { - SYSTABLE_RLOCK(SYSTABLE_PUBLICPORTS); - port = (port_t *)hashtable_lookup(SYSTABLE(SYSTABLE_PUBLICPORTS), - name, strnlen(name, 32)); - SYSTABLE_UNLOCK(SYSTABLE_PUBLICPORTS); - } - - if (port != NULL) - STAT(STAT_PORTS_FIND_FOUND, 1); - else - STAT(STAT_PORTS_FIND_NOTFOUND, 1); - - return port; -} - - -bool port_send(port_t *port, port_t *replyport, message_t *msg) -{ - bool ok = FALSE; - message_t *tmsg; - - if (OBJECT_VALID(port, OBJECT_PORT) && msg != NULL) { - ok = TRUE; - if (replyport != NULL) { - if (OBJECT_VALID(replyport, OBJECT_PORT)) { - msg->replyport = replyport; - OBJECT_SETDEP(msg, replyport); - } else - ok = FALSE; - } else - msg->replyport = NULL; - /* Queue message */ - SCHED_DISABLE(); - tmsg = DLIST_TOP(&port->messages); - DLIST_APPEND(&port->messages, (node_t *)msg); - SCHED_ENABLE(); - /* Notify that a message arrived, but only if the port was previously - * empty. - */ - if (tmsg == NULL) - signal_send(port->sigtask, PORT_SIGMASK(port)); - } - - if (ok) - STAT(STAT_PORTS_SEND, 1); - else { - STAT(STAT_PORTS_SEND_FAILED, 1); - DEBUG_PRINTF("* %T port_send(%p, %p, %p)\n", port, replyport, msg); - } - - return ok; -} - - -message_t *port_get(port_t *port) -{ - register message_t *msg = NULL; - - if (OBJECT_VALID(port, OBJECT_PORT)) { - SCHED_DISABLE(); - if ((msg = DLIST_TOP(&port->messages)) != NULL) - DLIST_UNLINK(&port->messages, (node_t *)msg); - SCHED_ENABLE(); - } else { - STAT(STAT_PORTS_GET_FAILED, 1); - DEBUG_PRINTF("* %T port_get(%p)\n", port); - } - - if (msg != NULL) - STAT(STAT_PORTS_GET, 1); - - return msg; -} - - -bool port_reply(message_t *msg) -{ - bool ok = FALSE; - - if (msg != NULL && OBJECT_DEPENDS(msg, msg->replyport)) - ok = port_send(msg->replyport, NULL, msg); - - if (ok) - STAT(STAT_PORTS_REPLY, 1); - else { - STAT(STAT_PORTS_REPLY_FAILED, 1); - DEBUG_PRINTF("* %T port_reply(%p)\n", msg); - } - - return ok; -} - - -/* Somewhat like poll(), but returns the port which caused the awakening. - * The task argument is optional, and specifies a prefered task to run next, - * or NULL. Note that a task can only wait for messages on it's own ports. - */ -port_t *port_wait(port_t **ports, u_int32_t num, task_t *yield) -{ - register port_t *port = NULL; - - if (ports != NULL && num > 0) { - register sigmask_t sigmask = 0; - register u_int32_t i; - - SCHED_DISABLE(); - /* By definition, a port has a tied signal. Form the sigmask. */ - for (i = 0; i < num; i++) { - register port_t *p = ports[i]; - - if (OBJECT_VALID(p, OBJECT_PORT)) { - sigmask |= PORT_SIGMASK(p); - if (DLIST_TOP(&p->messages) != NULL) { - port = p; - break; - } - } - } - SCHED_ENABLE(); - /* Only wait if all ports were empty */ - if (port == NULL) { - STAT(STAT_PORTS_WAIT, 1); - sigmask = signal_wait(sigmask, yield); - STAT(STAT_PORTS_WAIT_RETURNED_SLEEP, 1); - SCHED_DISABLE(); - for (i = 0; i < num; i++) { - register port_t *p = ports[i]; - - if (OBJECT_VALID(p, OBJECT_PORT) && - (sigmask & PORT_SIGMASK(p))) { - port = p; - break; - } - } - /* A big problem! We awaken, but not as the result of one of the - * port signals. When such a thing can occur, the task should - * use signal_wait() and manually include in the mask the wanted - * port signals, not port_wait(). We'll return NULL of course. - */ - if (i == num) { - STAT(STAT_PORTS_WAIT_RETURNED_NOSIG, 1); - DEBUG_PRINTF( - "- %T port_wait(%p, %u, %p) - Unexpected signal\n", - ports, num, yield); - } - SCHED_ENABLE(); - } else - STAT(STAT_PORTS_WAIT_RETURNED_IMMEDIATE, 1); - } else { - STAT(STAT_PORTS_WAIT_FAILED, 1); - DEBUG_PRINTF("* %T port_wait(%p, %u, %p)\n", ports, num, yield); - } - - return port; -} - - -/* Unlinks all currently queued messages (if any) from the supplied port_t. - * Should normally be performed on the tasks of the caller process only. - */ -bool port_flush(port_t *port) -{ - bool ok = FALSE; - - if (OBJECT_VALID(port, OBJECT_PORT)) { - ok = TRUE; - SCHED_DISABLE(); - if (DLIST_TOP(&port->messages) != NULL) - DLIST_INIT(&port->messages); - SCHED_ENABLE(); - STAT(STAT_PORTS_FLUSHED, 1); - } else { - STAT(STAT_PORTS_FLUSHED_FAILED, 1); - DEBUG_PRINTF("* %T port_flush(%p)\n", port); - } - - return ok; -} diff --git a/Xisop/src/common/kernel/port.h b/Xisop/src/common/kernel/port.h deleted file mode 100644 index 0a2ee44..0000000 --- a/Xisop/src/common/kernel/port.h +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id: port.h,v 1.2 2004/01/18 17:43:00 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_PORT_H -#define KERNEL_PORT_H - - - -#include -#include -#include -#include -#include -#include -#include -#include - - - -struct port { - hashnode_t sysnode; - node_t tasknode; /* Link to task_t ressources list_t */ - /* Validity sceal, message_t can depend on us */ - u_int32_t object_magic, object_id; - /* Other */ - task_t *sigtask; - signum_t signum; - list_t messages; - /* The following are used for public ports */ - bstr_t *name; -}; - -struct message { - pnode_t node; /* Allows for linking and using pool_t */ - /* The following two are used to allow replying back, but only to the - * actually expected reply port. - */ - port_t *replyport; - /* Object dependancy */ - u_int32_t objdep_magic, objdep_id; -}; - -/* This message type is made to pass through the special multiplexed port */ -/* XXX */ -struct mmessage { - message_t node; - int type; - union { - } u; -}; - - - -#define PORT_SIGMASK(p) SIGMASK((p)->signum) - - - -port_t *port_create(const char *); -port_t *port_destroy(port_t *); -port_t *port_find(const char *); -bool port_send(port_t *, port_t *, message_t *); -message_t *port_get(port_t *); -bool port_reply(message_t *); -port_t *port_wait(port_t **, u_int32_t, task_t *); -bool port_flush(port_t *); - - - -#endif diff --git a/Xisop/src/common/kernel/scheduler.c b/Xisop/src/common/kernel/scheduler.c deleted file mode 100644 index f9329a4..0000000 --- a/Xisop/src/common/kernel/scheduler.c +++ /dev/null @@ -1,382 +0,0 @@ -/* $Id: scheduler.c,v 1.5 2004/01/29 21:52:12 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include - - - -/* The famous initial context (the first scheduler interrupt context save - * operation saves main()'s context there. This context is resumed when there - * are no more tasks in the ready queue to run, in which case main()'s CPU - * ideling loop resumes. - */ -static _ctx_t _scontext; - - - -/* Used to initialize the xisop_root necessary fields */ -void scheduler_init(void) -{ - /* Initialize scheduler recursive lock, and obtain it. The system will - * need to SCHED_ENABLE() to start the scheduler. - */ - _rlock_init(&root->sched_lock); - _rlock_acquire(&root->sched_lock); - DLIST_INIT(&root->tasks_ready); - DLIST_INIT(&root->tasks_wait); - DLIST_INIT(&root->tasks_dead); - root->curtask = NULL; - root->curctx = &_scontext; -} - - -/* This function only has effect if the scheduler recursive lock is free, - * in which case scheduling is enabled. When so, it evaluates which task - * should run next and internally performs task and context switching if - * needed, via root->curtask and _scontext, the static context buffer used - * by the scheduler interrupt handler to store and load CPU context. We are - * only dealing with the tasks which are currently on the root->tasks_ready - * queue, and are working appropriately around the events of no tasks in the - * queue and the first context switch, and against recursion. - * - * What the scheduler timer interrupt does is disable the interrupt source, - * save the current user CPU context in root->curctx, which may be _scontext - * or old task context, execute the _FACILITY_SCHEDTIMER hooks calling - * facility_exechooks(), call us, load back the saved user CPU context - * from root->curctx, re-enable the interrupt source and return from exception - * to the new context's PC address. So basically we are between the context - * save and load operations, and can access and alter root->curtask and - * root->curctx, thus the buffer it uses to load the context back. - * - * Our task priority scheduling algorithm uses a credits attribution method - * where when starting a round, each task in the queue receives credits - * according to it's specific priority. The round expires when none of the - * tasks have any credits left, in which case a new round restarts over. - * During a round, an effort is made to both allow tasks with the most credits - * to run more often and faster than others, while still distributing as much - * as possible their turns evenly to make the signal and message port systems - * work as efficiently as possible in all cases. - * - * This does not account for how long each task has run, a task may - * take any time from 0 to the scheduler rate before it is interrupted and - * a credit is substracted from it. Another type of scheduler could be - * more suitable for a realtime system. - */ -void old_schedule(void) -{ - /* Do nothing unless the scheduler is enabled */ - if (_rlock_try(&root->sched_lock)) { - register task_t *ntsk, *old; - - if ((old = root->curtask) == NULL) - ntsk = DLIST_TOP(&root->tasks_ready); - else { - if (old->state == STATE_RUN) - old->state = STATE_READY; - for (;;) { - register task_t *tsk; - register priority_t credit; - - /* Find which task has the most credits and deserves next run, - * but continue the loop at previous task, otherwise the - * highest priority task will get all turns at once until it - * reaches equality with other tasks. - */ - credit = -128; - tsk = old; - ntsk = NULL; - for (;;) { - if ((tsk = (task_t *)tsk->node.node.next) == NULL) - tsk = DLIST_TOP(&root->tasks_ready); - if (tsk != old) { - if (credit < tsk->credits) { - credit = tsk->credits; - ntsk = tsk; - } - } else - break; - } - if (ntsk == NULL) { - /* If this happens there is only one task in the queue, - * or none. Revert back to previous task, if any. - */ - if (DLIST_NODES(&root->tasks_ready) > 0) - ntsk = old; - else break; - } - - if (credit == -128 /* XXX && ntsk != old */) { - /* All out of credits, redistribute them. This is the - * end and beginning of a new round. - */ - DLIST_FOREACH(&root->tasks_ready, tsk) { - if ((tsk->credits = tsk->priority) == -128) - tsk->credits++; - } - continue; - } - - break; - } - } - - if (ntsk != NULL) { - /* This is the next task to run */ - ntsk->credits--; - if (ntsk != old) { - /* Perform actual context switch */ - STAT(STAT_SCHED_PREEMPTED, 1); - ntsk->state = STATE_RUN; - root->curtask = ntsk; - root->curctx = &ntsk->ctx; - } - } else { - root->curtask = NULL; - root->curctx = &_scontext; - } - - _rlock_release(&root->sched_lock); - } -} - -/* Because there seems to be a bug with the previous function and that - * all we need for testing and building the rest of Xisop is at least - * round robin, here is a function which at least works for now. - */ -void schedule(task_t *pref) -{ - if (_rlock_try(&root->sched_lock)) { - register task_t *tsk; - - /* First evaluate if requested task is ok to switch to */ - if (OBJECT_VALID(pref, OBJECT_TASK) && pref != root->curtask && - pref->state == STATE_READY) - tsk = pref; - else { - if ((tsk = root->curtask) == NULL) - tsk = DLIST_TOP(&root->tasks_ready); - else { - /* The current task may not be in the ready list anymore */ - if (tsk->state == STATE_READY || tsk->state == STATE_RUN) { - tsk->state = STATE_READY; - if ((tsk = DLIST_NEXT(tsk)) == NULL) - tsk = DLIST_TOP(&root->tasks_ready); - } else - tsk = DLIST_TOP(&root->tasks_ready); - } - } - if (tsk != NULL) { - tsk->state = STATE_RUN; - root->curtask = tsk; - root->curctx = &tsk->ctx; - } else { - /* No tasks in the ready queue to run, return to the original - * main() context, which idles the CPU as much as possible - * using sys_idle(). - */ - root->curtask = NULL; - root->curctx = &_scontext; - } - _rlock_release(&root->sched_lock); - } -} - - -/* Allows to make a task sleep forcibly. The only way it can then wake up - * is by task_wakeup() using at least one of the bits in the flags. - */ -void task_sleep(task_t *task, u_int32_t flags, task_t *yield) -{ - bool current = FALSE; - - SCHED_DISABLE(); - if (OBJECT_VALID(task, OBJECT_TASK) && - (task->state == STATE_READY || task->state == STATE_RUN)) { - task->sleepflags = flags; - task->state = STATE_WAIT; - DLIST_SWAP(&root->tasks_wait, &root->tasks_ready, (node_t *)task, - FALSE); - if (task == root->curtask) - current = TRUE; - } - SCHED_ENABLE(); - if (current) - _yield(yield); -} - -/* Awakes a task which should have been put asleep using task_sleep(). - * The task is only awaken if at least one of the reasons in flags matches. - */ -bool task_wakeup(task_t *task, u_int32_t flags) -{ - bool ok = FALSE; - - SCHED_DISABLE(); - if (OBJECT_VALID(task, OBJECT_TASK) && - task->state == STATE_WAIT && (task->sleepflags & flags)) { - task->state = STATE_READY; - task->sleepflags = 0; - task->credits = task->priority; - if (task->credits == -128) - task->credits++; - DLIST_SWAP(&root->tasks_ready, &root->tasks_wait, (node_t *)task, - FALSE); - ok = TRUE; - } - SCHED_ENABLE(); - - return ok; -} - - -void sched_disable(void) -{ - SCHED_DISABLE(); -} - -void sched_enable(void) -{ - SCHED_ENABLE(); -} - - -/* Nestled locking is not permitted with these locks */ -void lock_acquire(_lock_t *lock) -{ - /* Always immediately _yield() unless we can obtain the lock. - * This way we use the less CPU time possible while at the same time - * allowing the locker to eventually release the lock. - */ - for (;;) { - if (_lock_try(lock)) - break; - _yield(NULL); - } -} - -void lock_release(_lock_t *lock) -{ - _lock_release(lock); -} - - -/* A lock type permitting multiple readers but exclusive access for write */ -void rwlock_init(rwlock_t *lock) -{ - _lock_init(&lock->exclusive_lock); - _rlock_init(&lock->recursive_lock); - lock->state = RWLOCK_SLOCKED; -} - -void rwlock_acquire(rwlock_t *lock, bool exclusive) -{ - lock_acquire(&lock->exclusive_lock); - if (exclusive) { - while (!_rlock_try(&lock->recursive_lock)) - _yield(NULL); - lock->state = RWLOCK_XLOCKED; - _rlock_release(&lock->recursive_lock); - } else { - _rlock_acquire(&lock->recursive_lock); - lock->state = RWLOCK_SLOCKED; - _lock_release(&lock->exclusive_lock); - } -} - -void rwlock_release(rwlock_t *lock) -{ - switch (lock->state) { - case RWLOCK_SLOCKED: - _rlock_release(&lock->recursive_lock); - break; - case RWLOCK_XLOCKED: - lock->state = RWLOCK_SLOCKED; - _lock_release(&lock->exclusive_lock); - break; - } -} - -bool rwlock_try(rwlock_t *lock, bool exclusive) -{ - bool ok = FALSE; - - if (_lock_try(&lock->exclusive_lock)) { - if (exclusive) { - if (_rlock_try(&lock->recursive_lock)) { - _rlock_release(&lock->recursive_lock); - _lock_release(&lock->exclusive_lock); - } else { - lock->state = RWLOCK_XLOCKED; - ok = TRUE; - } - } else { - _rlock_acquire(&lock->recursive_lock); - lock->state = RWLOCK_SLOCKED; - _lock_release(&lock->exclusive_lock); - ok = TRUE; - } - } - - return ok; -} - -void rwlock_upgrade(rwlock_t *lock) -{ - if (lock->state == RWLOCK_SLOCKED) { - lock_acquire(&lock->exclusive_lock); - _rlock_release(&lock->recursive_lock); - while (!_rlock_try(&lock->recursive_lock)) - _yield(NULL); - lock->state = RWLOCK_XLOCKED; - _rlock_release(&lock->recursive_lock); - } -} - -void rwlock_downgrade(rwlock_t *lock) -{ - if (lock->state == RWLOCK_XLOCKED) { - _rlock_acquire(&lock->recursive_lock); - lock->state = RWLOCK_SLOCKED; - _lock_release(&lock->exclusive_lock); - } -} diff --git a/Xisop/src/common/kernel/scheduler.h b/Xisop/src/common/kernel/scheduler.h deleted file mode 100644 index 02b95ce..0000000 --- a/Xisop/src/common/kernel/scheduler.h +++ /dev/null @@ -1,90 +0,0 @@ -/* $Id: scheduler.h,v 1.2 2004/01/19 00:03:23 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_SCHEDULER_H -#define KERNEL_SCHEDULER_H - - - -#include -#include -#include - - - -/* Scheduler control without affecting the scheduler interrupt */ -#define SCHED_DISABLE() _rlock_acquire(&root->sched_lock) -#define SCHED_ENABLE() _rlock_release(&root->sched_lock) - -/* Sleep reason flags for task_sleep() and task_wakeup() */ -#define TSF_SIGNAL (1L << 0) -#define TSF_KERNEL (1L << 1) -#define TSF_CUSTOM (1L << 2) - -/* State of an rwlock_t */ -enum _rwlock_states { - RWLOCK_SLOCKED, - RWLOCK_XLOCKED -}; - -struct rwlock { - _lock_t exclusive_lock; - _rlock_t recursive_lock; - enum _rwlock_states state; -}; - - - -void scheduler_init(void); -void schedule(task_t *); -void task_sleep(task_t *, u_int32_t, task_t *); -bool task_wakeup(task_t *, u_int32_t); -void sched_disable(void); -void sched_enable(void); - -void lock_acquire(_lock_t *); -void lock_release(_lock_t *); -void rwlock_init(rwlock_t *); -void rwlock_acquire(rwlock_t *, bool); -void rwlock_release(rwlock_t *); -bool rwlock_try(rwlock_t *, bool); -void rwlock_upgrade(rwlock_t *); -void rwlock_downgrade(rwlock_t *); - - - -#endif diff --git a/Xisop/src/common/kernel/signal.c b/Xisop/src/common/kernel/signal.c deleted file mode 100644 index a882416..0000000 --- a/Xisop/src/common/kernel/signal.c +++ /dev/null @@ -1,195 +0,0 @@ -/* $Id: signal.c,v 1.3 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* Attempts to allocate a general purpose user signal from the current task */ -signum_t signal_alloc(void) -{ - register signum_t signum = -1; - register task_t *task = CURTASK(); - - if (task->sigalloc != 0xFFFFFFFF) { - register sigmask_t sigmask = task->sigalloc; - - for (signum = 0; signum < 32; signum++) { - if ((sigmask & SIGMASK(signum)) == 0) { - sigmask |= SIGMASK(signum); - task->sigalloc = sigmask; - STAT(STAT_SIGNALS_ALLOC, 1); - break; - } - } - if (signum == 32) - signum = -1; - } else { - STAT(STAT_SIGNALS_ALLOC_NOSIG, 1); - DEBUG_PRINTF("- %T signal_alloc() - Out of signals\n"); - } - - return signum; -} - - -void _signal_free(task_t *task, sigmask_t sigmask) -{ - if (OBJECT_VALID(task, OBJECT_TASK)) { - /* Refuse to free reserved signals */ - sigmask &= ~SIGRESMASK; - /* But free all other requested ones */ - task->sigalloc &= ~sigmask; - STAT(STAT_SIGNALS_FREE, 1); - } -} - - -/* Frees back specified allocated signals of the current process, for future - * obtention with signal_alloc() again. - */ -void signal_free(sigmask_t sigmask) -{ - _signal_free(CURTASK(), sigmask); -} - - -/* Suspends the current task until at least one signal in sigmask is received - * by it. The task is moved to the wait queue and sigwait is set, as - * opposition to yield() which does not change the task state and just causes - * a reschedule. - * Obviously, using a sigmask of 0 here woild suspend the task indefinitely, - * and is invalid. If the task needs to be awakened on a timeout event, it - * should allocate a signal for that event and ensure to receive that signal - * when the delay expires. This can be done using a timer.device or another - * task. - * The optional task argument, which may be NULL, specifies a preference to - * which task to run next (as we yield()). - */ -sigmask_t signal_wait(sigmask_t sigmask, task_t *yield) -{ - register sigmask_t recvmask = 0; - - if (sigmask != 0) { - register task_t *t = CURTASK(); - - sigmask |= SIGRESMASK; /* Always awake on those */ - - SCHED_DISABLE(); - /* Set new sigwait mask */ - t->sigwait = sigmask; - SCHED_ENABLE(); - - /* Swap task to waiting queue (we know that we are currently in the - * ready one, in STATE_RUN, otherwise we would not be running), and - * relay control back to scheduler immediately. - */ - task_sleep(t, TSF_SIGNAL, yield); - - /* If we get here, it's because we were swapped back to the ready queue - * as the result of receiving a signal we were waiting for, and - * were awaken by the scheduler, and we are back in STATE_RUN. Clear - * the sigwait mask, but also return it so that the caller knows which - * signal(s) caused our task to wake up again. - */ - SCHED_DISABLE(); - recvmask = t->sigrecv; - t->sigrecv = 0; - SCHED_ENABLE(); - - STAT(STAT_SIGNALS_WAIT_RETURNED_SLEEP, 1); - } else { - STAT(STAT_SIGNALS_WAIT_FAILED, 1); - DEBUG_PRINTF("* %T signal_wait(%b, %p)\n", sigmask, yield); - } - - return recvmask; -} - - -/* Sends a signal to a task. The task is immediately moved to the ready - * queue if it currently was waiting for it. The current task is however - * left executing, but may _yield() if it wants the other end to be able to - * react to the signal as soon as possible. Otherwise the scheduler frequency - * and tasks priorities will decide when the other end can run. - */ -void signal_send(task_t *task, sigmask_t sigmask) -{ - if (OBJECT_VALID(task, OBJECT_TASK) && sigmask != 0) { - bool awake = FALSE; - - SCHED_DISABLE(); - /* Apply signals */ - task->sigrecv |= sigmask; - SCHED_ENABLE(); - - STAT(STAT_SIGNALS_SEND, 1); - - /* If needed, swap task to ready queue */ - if ((task->sigwait & task->sigrecv) != 0) - awake = task_wakeup(task, TSF_SIGNAL); - - /* XXX UGH! Unless we _yield(), synchronization problems quickly occur - * among communicating tasks, they eventually all reside in the wait - * queue, in which case they obviously deadlock. And strangely enough, - * we have to _yield() twice to solve this issue! Why is currently - * still a mystery, but possibly that it has to do with the fact that - * when communicating through message ports, we expect a reply? - * Maybe that the scheduler should be left to evaluate when a task - * should be moved to the waiting queue, and when it needs to be - * brought back on the ready queue because it received an expected - * signal... rather than having tasks do so themselves, which is what - * we currently are doing. - */ - if (awake) { - STAT(STAT_SIGNALS_SEND_WOKE, 1); - _yield(task); - _yield(NULL); - } - } else { - STAT(STAT_SIGNALS_SEND_FAILED, 1); - DEBUG_PRINTF("* %T signal_send(%p, %b)\n", task, sigmask); - } -} diff --git a/Xisop/src/common/kernel/signal.h b/Xisop/src/common/kernel/signal.h deleted file mode 100644 index 50eca01..0000000 --- a/Xisop/src/common/kernel/signal.h +++ /dev/null @@ -1,67 +0,0 @@ -/* $Id: signal.h,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_SIGNAL_H -#define KERNEL_SIGNAL_H - - - -#include -#include - - - -/* Reserved signals */ -#define SIGRESERVED 2 -#define SIGRESMASK 0x00000003L -#define SIGTERM 0 -#define SIGPOLL 1 - - -/* Useful to form a sigmask_t from signum_t */ -#define SIGMASK(n) (sigmask_t )(1L << (n)) - - -signum_t signal_alloc(void); -void signal_free(sigmask_t); -void _signal_free(task_t *, sigmask_t); -sigmask_t signal_wait(sigmask_t, task_t *); -void signal_send(task_t *, sigmask_t); - - - -#endif diff --git a/Xisop/src/common/kernel/statistic.c b/Xisop/src/common/kernel/statistic.c deleted file mode 100644 index 154823b..0000000 --- a/Xisop/src/common/kernel/statistic.c +++ /dev/null @@ -1,168 +0,0 @@ -/* $Id: statistic.c,v 1.3 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include - - - -#ifdef STATISTICS - - - -/* Should match with stat_keys enum of statistic.h */ -const static char *stat_strings[] = { - "mem.mchunks.attach", - "mem.mchunks.attach.failed", - "mem.mchunks.detach", - "mem.mchunks.detach.failed", - "mem.pages.alloc", - "mem.pages.alloc.nomem", - "mem.pages.free", - "mem.pages.free.failed", - "mem.pages.buffered", - "mem.pages.unbuffered", - "mem.pages.reused", - "mem.pools.created", - "mem.pools.created.failed", - "mem.pools.enlarged", - "mem.pools.destroyed", - "mem.pools.destroyed.failed", - "mem.pools.alloc", - "mem.pools,alloc.failed", - "mem.pools.alloc.nomem", - "mem.pools.free", - "mem.pools.free.failed", - "mem.mpools.created", - "mem.mpools.created.failed", - "mem.mpools.destroyed", - "mem.mpools.destroyed.failed", - "mem.mpools.alloc", - "mem.mpools.alloc.failed", - "mem.mpools.alloc.nomem", - "mem.mpools.free", - "mem.mpools.free.failed", - "syscalls.invalid", - "syscalls.invoked", - "hooks.attached", - "hooks.attached.failed", - "hooks.attached.nomem", - "hooks.detached", - "hooks.detached,failed", - "hooks.detached.noexist", - "hooks.expired", - "hooks.executed", - "hooks.skipped", - "facility.disabled", - "facility.disabled.failed", - "facility.enabled", - "facility.enabled.failed", - "facility.executed", - "facility.executed.failed", - "facility.executed.locked", - "sched.preempted", - "tasks.alloc", - "tasks.alloc.failed", - "tasks.alloc.nomem", - "tasks.free", - "tasks.free.failed", - "tasks.started", - "tasks.started.failed", - "tasks.ended", - "tasks.ended.failed", - "ports.created", - "ports.created.exists", - "ports.created.nomem", - "ports.created.nosig", - "ports.destroyed", - "ports.destroyed.failed", - "ports.find.found", - "ports.find.notfound", - "ports.send", - "ports.send.failed", - "ports.send", - "ports.send.failed", - "ports.get", - "ports.get.failed", - "ports.reply", - "ports.reply.failed", - "ports.wait", - "ports.wait.failed", - "ports.wait.sleep", - "ports.wait.returned.immediate", - "ports.wait.returned.sleep", - "ports.wait.returned.nosig", - "ports.flushed", - "ports.flushed.failed", - "signals.alloc", - "signals.alloc.nosig", - "signals.free", - "signals.wait", - "signals.wait.failed", - "signals.wait.returned.sleep", - "signals.send", - "signals.send.failed", - "signals.send.woke", - NULL -}; - - - -void statistic_init(void) -{ - register u_int32_t i; - - for (i = 0; i < (enum stat_keys)STAT_MAX; i++) - root->stats[i] = 0; -} - - -void stat_dump(void) -{ - register u_int32_t i; - - for (i = 0; i < (enum stat_keys)STAT_MAX; i++) - DEBUG_PRINTF("%u\t%s\n", root->stats[i], stat_strings[i]); -} - - - -#endif diff --git a/Xisop/src/common/kernel/statistic.h b/Xisop/src/common/kernel/statistic.h deleted file mode 100644 index 8024431..0000000 --- a/Xisop/src/common/kernel/statistic.h +++ /dev/null @@ -1,163 +0,0 @@ -/* $Id: statistic.h,v 1.2 2004/01/18 17:43:00 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_STATISTIC_H -#define KERNEL_STATISTIC_H - - - -#include - - - -#ifndef STATISTICS - -#define STAT(k, m) - -#else - - - -enum stat_keys { - STAT_MCHUNKS_ATTACH = 0, - STAT_MCHUNKS_ATTACH_FAILED, - STAT_MCHUNKS_DETACH, - STAT_MCHUNKS_DETACH_FAILED, - STAT_PAGES_ALLOC, - STAT_PAGES_ALLOC_NOMEM, - STAT_PAGES_FREE, - STAT_PAGES_FREE_FAILED, - STAT_PAGES_BUFFERED, - STAT_PAGES_UNBUFFERED, - STAT_PAGES_REUSED, - STAT_POOLS_CREATED, - STAT_POOLS_CREATED_FAILED, - STAT_POOLS_ENLARGED, - STAT_POOLS_DESTROYED, - STAT_POOLS_DESTROYED_FAILED, - STAT_POOLS_ALLOC, - STAT_POOLS_ALLOC_FAILED, - STAT_POOLS_ALLOC_NOMEM, - STAT_POOLS_FREE, - STAT_POOLS_FREE_FAILED, - STAT_MPOOLS_CREATED, - STAT_MPOOLS_CREATED_FAILED, - STAT_MPOOLS_DESTROYED, - STAT_MPOOLS_DESTROYED_FAILED, - STAT_MPOOLS_ALLOC, - STAT_MPOOLS_ALLOC_FAILED, - STAT_MPOOLS_ALLOC_NOMEM, - STAT_MPOOLS_FREE, - STAT_MPOOLS_FREE_FAILED, - STAT_SYSCALLS_INVALID, - STAT_SYSCALLS_INVOKED, - STAT_HOOKS_ATTACHED, - STAT_HOOKS_ATTACHED_FAILED, - STAT_HOOKS_ATTACHED_NOMEM, - STAT_HOOKS_DETACHED, - STAT_HOOKS_DETACHED_FAILED, - STAT_HOOKS_DETACHED_NOEXIST, - STAT_HOOKS_EXPIRED, - STAT_HOOKS_EXECUTED, - STAT_HOOKS_SKIPPED, - STAT_FACILITY_DISABLED, - STAT_FACILITY_DISABLED_FAILED, - STAT_FACILITY_ENABLED, - STAT_FACILITY_ENABLED_FAILED, - STAT_FACILITY_EXECUTED, - STAT_FACILITY_EXECUTED_FAILED, - STAT_FACILITY_EXECUTED_LOCKED, - STAT_SCHED_PREEMPTED, - STAT_TASKS_ALLOC, - STAT_TASKS_ALLOC_FAILED, - STAT_TASKS_ALLOC_NOMEM, - STAT_TASKS_FREE, - STAT_TASKS_FREE_FAILED, - STAT_TASKS_STARTED, - STAT_TASKS_STARTED_FAILED, - STAT_TASKS_ENDED, - STAT_TASKS_ENDED_FAILED, - STAT_PORTS_CREATED, - STAT_PORTS_CREATED_EXISTS, - STAT_PORTS_CREATED_NOMEM, - STAT_PORTS_CREATED_NOSIG, - STAT_PORTS_DESTROYED, - STAT_PORTS_DESTROYED_FAILED, - STAT_PORTS_FIND_FOUND, - STAT_PORTS_FIND_NOTFOUND, - STAT_PORTS_SEND, - STAT_PORTS_SEND_FAILED, - STAT_PORTS_GET, - STAT_PORTS_GET_FAILED, - STAT_PORTS_REPLY, - STAT_PORTS_REPLY_FAILED, - STAT_PORTS_WAIT, - STAT_PORTS_WAIT_FAILED, - STAT_PORTS_WAIT_SLEEP, - STAT_PORTS_WAIT_RETURNED_IMMEDIATE, - STAT_PORTS_WAIT_RETURNED_SLEEP, - STAT_PORTS_WAIT_RETURNED_NOSIG, - STAT_PORTS_FLUSHED, - STAT_PORTS_FLUSHED_FAILED, - STAT_SIGNALS_ALLOC, - STAT_SIGNALS_ALLOC_NOSIG, - STAT_SIGNALS_FREE, - STAT_SIGNALS_WAIT, - STAT_SIGNALS_WAIT_FAILED, - STAT_SIGNALS_WAIT_RETURNED_SLEEP, - STAT_SIGNALS_SEND, - STAT_SIGNALS_SEND_FAILED, - STAT_SIGNALS_SEND_WOKE, - STAT_MAX -}; - - - -#define STAT(k, n) root->stats[(enum stat_keys)(k)] += (n) - - - -void statistic_init(void); -void statistic_dump(void); - - - -#endif - - - -#endif diff --git a/Xisop/src/common/kernel/syscall.c b/Xisop/src/common/kernel/syscall.c deleted file mode 100644 index 9df06e8..0000000 --- a/Xisop/src/common/kernel/syscall.c +++ /dev/null @@ -1,204 +0,0 @@ -/* $Id: syscall.c,v 1.2 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* It also would be possible to simply use a structure with all the - * function pointers of the various types... And have the user functions - * refer those with the structure as well, just like for Xisop libraries... - * However, this system is a little more secure for the kernel stack, - * which state is always controled. It also allows to export an ID which - * we can validate. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* XXX */ - - - -static void _sys_getroot(void *, void *); -static void _sys_int_disable(void *, void *); -static void _sys_int_enable(void *, void *); -static void _sys_idle(void *, void *); -static void _sys_custom(void *, void *); - - - -/* Should match with enum in syscall.h */ -static void (*_syscalls[])(void *, void *) = { - _sys_getroot, - _sys_int_disable, - _sys_int_enable, - _sys_idle, - _sys_custom -}; - - - -/* Called by port-specific code before initializing interrupt facilities */ -void syscall_init(void) -{ - root->syscalls = _syscalls; -} - - -/* The following consist of the kernel-side functions which execute in - * supervisor mode. - */ - -/* Syscall trap handler */ -void _scatch(u_int32_t func, void *res, void *args) -{ - if (func < (enum syscalls)SYS_MAX && root->syscalls[func]) - root->syscalls[func](res, args); - else { - STAT(STAT_SYSCALLS_INVALID, 1); - DEBUG_PRINTF("* %T _scatch(%u, %p, %p) - Invalid syscall number\n", - func, res, args); - } - STAT(STAT_SYSCALLS_INVOKED, 1); -} - - -static void _sys_getroot(void *res, void *args) -{ - struct _sres { - struct xisop_root *root; - } *sres = res; - - sres->root = root; -} - - -/* ARGSUSED */ -static void _sys_int_disable(void *res, void *args) -{ - _splhigh(); -} - -/* ARGSUSED */ -static void _sys_int_enable(void *res, void *args) -{ - _spl0(); -} - -/* ARGSUSED */ -static void _sys_idle(void *res, void *args) -{ - _idle(); -} - - -static void _sys_custom(void *res, void *args) -{ - struct _sargs { - void (*func)(void *, void *); - void *args; - } *sargs = args; - - sargs->func(res, sargs->args); -} - - - -/* And here are the functions which are called from userspace to trigger - * system calls. - */ - -/* Returns the Xisop system pointer. This obviously should be used with care */ -struct xisop_root *sys_getroot(void) -{ - struct _sres { - struct xisop_root *root; - } sres; - - _syscall(SYS_GETROOT, &sres, NULL); - - return sres.root; -} - - -/* And these allow to disable all interrupts, which of course also causes - * the scheduler to be disabled. Should however not generally be used as a - * substitute to sched_disable(). - */ -void sys_int_disable(void) -{ - _syscall(SYS_INT_DISABLE, NULL, NULL); -} - -void sys_int_enable(void) -{ - _syscall(SYS_INT_ENABLE, NULL, NULL); -} - -/* Causes the CPU to sleep until the next interrupt occurs */ -void sys_idle(void) -{ - _syscall(SYS_IDLE, NULL, NULL); -} - - -/* Since Xisop does not use MMU, and in now way claims to be secure against - * it's own tasks, other than providing clean facilities, a very useful - * syscall to execute arbitrary code in supervisor mode. If one needs - * unix security, they should be running NetBSD :) - * This allows userspace tasks to extend system calls. The user provided - * function uses the same semantics as Xisop syscall ones. An int value - * can be returned, which will then be returned by sys_custom(), and - * arbitrary data may be written into the supplied results pointer if wanted - * (the first void * argument, which is set to the supplied res pointer). - * The user function can obtain it's arguments from the second void *, - * which is supplied using args. This way possibilities are endless. - */ -void sys_custom(void *res, void (*func)(void *, void *), void *args) -{ - struct _sargs { - void (*func)(void *, void *); - void *args; - } sargs = { - func, - args - }; - - _syscall(SYS_CUSTOM, res, &sargs); -} diff --git a/Xisop/src/common/kernel/syscall.h b/Xisop/src/common/kernel/syscall.h deleted file mode 100644 index 639a0c5..0000000 --- a/Xisop/src/common/kernel/syscall.h +++ /dev/null @@ -1,76 +0,0 @@ -/* $Id: syscall.h,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERN_SYSCALL_H -#define KERN_SYSCALL_H - - - -#include -#include -#include - - - -/* Currently available syscalls */ -enum syscalls { - SYS_GETROOT = 0, - SYS_INT_DISABLE, - SYS_INT_ENABLE, - SYS_IDLE, - SYS_CUSTOM, - SYS_MAX -}; - - - -void syscall_init(void); -void _scatch(u_int32_t, void *, void *); - -struct xisop_root *sys_getroot(void); -void sys_int_disable(void); -void sys_int_enable(void); -void sys_idle(void); -void sys_custom(void *, void (*)(void *, void *), void *); - - - -extern void (*_syscalls[])(void *, void *); - - - -#endif diff --git a/Xisop/src/common/kernel/task.c b/Xisop/src/common/kernel/task.c deleted file mode 100644 index 0234078..0000000 --- a/Xisop/src/common/kernel/task.c +++ /dev/null @@ -1,432 +0,0 @@ -/* $Id: task.c,v 1.8 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -static void task_startend_code(void); - -static int task_reaper(void *, void *); - - - -task_t *task_alloc(int (*start)(void *, void *), void *res, void *args, - priority_t priority, size_t stacksize, u_int8_t flags) -{ - if (start != NULL && stacksize != 0) { - register page_t *stack = NULL; - register u_int32_t pages; - - pages = stacksize / _PAGE_SIZE; - if (stacksize % _PAGE_SIZE) - pages++; - if ((stack = pages_alloc(0, pages, FALSE)) != NULL) { - register task_t *task = NULL; - - if ((task = (task_t *)spool_alloc(POOL_TASK)) != NULL) { - if ((flags & TF_SHARED) != 0) { - register mpool_t *mpool = CURTASK()->mpool; - - if (OBJECT_VALID(mpool, OBJECT_MPOOL)) { - /* This task will share mpool_t with parent */ - lock_acquire(&mpool->lock); - mpool->shared = TRUE; - mpool->usecount++; - task->mpool = mpool; - _lock_release(&mpool->lock); - } - } else { - /* This task needs it's own unique mpool_t */ - if ((task->mpool = (mpool_t *)spool_alloc(POOL_MPOOL)) - != NULL) { - if (!mpool_init(task->mpool)) - task->mpool = (mpool_t *)spool_free(POOL_MPOOL, - (pnode_t *)task->mpool); - } - } - if (task->mpool != NULL) { - /* Validate task_t object */ - OBJECT_VALIDATE(task, OBJECT_TASK); - /* Initialize other task_t fields */ - task->sleepflags = 0; - task->flags = flags; - task->state = STATE_START; - task->priority = priority; - task->sigalloc = task->sigwait = task->sigrecv = 0; - task->start = start; - task->res = res; - task->args = args; - task->rescode = 0; - task->stack = stack; - task->stacksize = pages * _PAGE_SIZE; - _ctx_init(&task->ctx, (u_int32_t *)stack->address, - task->stacksize, (void *)task_startend_code); - /* Resources */ - DLIST_INIT(&task->resources.ports); - DLIST_INIT(&task->resources.devices); - task->resources.device = NULL; - STAT(STAT_TASKS_ALLOC, 1); - - return task; - } else { - STAT(STAT_TASKS_ALLOC_NOMEM, 1); - DEBUG_PRINTF( - "* %T task_alloc(%p. %p, %p, %d, %u, %x) - mpool_init()\n", - start, res, args, (int32_t)priority, stacksize, - (u_int32_t)flags); - } - spool_free(POOL_TASK, (pnode_t *)task); - } else { - STAT(STAT_TASKS_ALLOC_NOMEM, 1); - DEBUG_PRINTF( - "* %T task_alloc(%p, %p, %p, %d, %u, %x) - Out of memory\n", - start, res, args, (int32_t)priority, stacksize, - (u_int32_t)flags); - } - pages_free(stack); - } else { - STAT(STAT_TASKS_ALLOC_NOMEM, 1); - DEBUG_PRINTF( - "* %T task_alloc(%p, %p, %p, %d, %u, %x) - Out of memory\n", - start, res, args, (int32_t)priority, stacksize, - (u_int32_t)flags); - } - } else { - STAT(STAT_TASKS_ALLOC_FAILED, 1); - DEBUG_PRINTF("* %T task_alloc(%p, %p, %p, %d, %u, %x)\n", - start, res, args, (int32_t)priority, stacksize, - (u_int32_t)flags); - } - - return NULL; -} - - -/* Free a task_t. Also unlinks the task from the system lists. The task - * must first have been processed by task_end() and thus moved into the - * dead queue. - */ -task_t *task_free(task_t *task) -{ - if (OBJECT_VALID(task, OBJECT_TASK) && - (task->state == STATE_DEAD || task->state == STATE_START)) { - SCHED_DISABLE(); - if (task->state == STATE_DEAD) - DLIST_UNLINK(&root->tasks_dead, (node_t *)task); - SCHED_ENABLE(); - if (task->stack != NULL) - pages_free(task->stack); - /* Free task resources */ - /* All ports the task created. Linked via port_t->tasknode. */ - { - register port_t *port, *next; - - for (port = DLIST_TOP(&(task->resources.ports)); port != NULL; - port = next) { - next = DLIST_NEXT(&port->tasknode); - port_destroy((port_t *)&(((hashnode_t *)port)[-1])); - } - } - /* Devices we opened. Linked via device_t->tasknode. */ - { - register node_t *node, *next; - - for (node = DLIST_TOP(&(task->resources.devices)); node != NULL; - node = next) { - next = DLIST_NEXT(node); - device_close((device_t *)&(((pnode_t *)node)[-1])); - } - } - /* If we are a device */ - if (task->resources.device) - device_detach(task->resources.device); - /* XXX other future resources handling, like opened libraries, etc */ - /* Invalidate task */ - OBJECT_INVALIDATE(task); - /* All memory the task allocated using malloc(). If mpool_destroy() - * fails with FALSE, either a problem occured or the mpool_t is still - * in use by another task sharing it, in which case we do not free it. - */ - if (mpool_destroy(task->mpool)) - spool_free(POOL_MPOOL, (pnode_t *)task->mpool); - /* And finally the task node itself. */ - spool_free(POOL_TASK, (pnode_t *)task); - STAT(STAT_TASKS_FREE, 1); - } else { - STAT(STAT_TASKS_FREE_FAILED, 1); - DEBUG_PRINTF("* %T task_free(%p)\n", task); - } - - return NULL; -} - - -/* Allows to start a new task */ -bool task_start(task_t *task) -{ - bool ok = FALSE; - - if (OBJECT_VALID(task, OBJECT_TASK) && task->state == STATE_START) { - /* This task was just allocated, start it */ - task->state = STATE_READY; - if ((task->credits = task->priority) == -128) - task->credits++; - SCHED_DISABLE(); - DLIST_APPEND(&root->tasks_ready, (node_t *)task); - SCHED_ENABLE(); - ok = TRUE; - STAT(STAT_TASKS_STARTED, 1); - } else { - STAT(STAT_TASKS_STARTED_FAILED, 1); - DEBUG_PRINTF("* %T task_start(%p)\n", task); - } - - return ok; -} - - -bool task_end(task_t *task) -{ - bool ok = FALSE, current = FALSE; - - if (OBJECT_VALID(task, OBJECT_TASK) && task->state != STATE_DEAD) { - ok = TRUE; - SCHED_DISABLE(); - switch (task->state) { - case STATE_RUN: - /* FALLTHROUGH */ - case STATE_READY: - DLIST_SWAP(&root->tasks_dead, &root->tasks_ready, (node_t *)task, - FALSE); - break; - case STATE_WAIT: - DLIST_SWAP(&root->tasks_dead, &root->tasks_wait, (node_t *)task, - FALSE); - break; - default: - ok = FALSE; - break; - } - if (ok) { - STAT(STAT_TASKS_ENDED, 1); - task->state = STATE_DEAD; - /* Wakeup reaper as there's at least one task on the dead queue */ - task_wakeup(root->task_reaper, TSF_KERNEL); - /* If it's the current task, ensure to yield now. */ - if (task == root->curtask) - current = TRUE; - } - SCHED_ENABLE(); - } - - if (current) { - /* We also probably could go to sleep indefinitely instead, - * but as we are in the dead queue, we are certain that we will not - * be given another chance to run until we get freed. - */ - for (;;) - _yield(NULL); - } - if (!ok) { - STAT(STAT_TASKS_ENDED_FAILED, 1); - DEBUG_PRINTF("* %T task_end(%p)\n", task); - } - - return ok; -} - - -priority_t task_getpriority(task_t *task) -{ - register priority_t p = 0; - - if (OBJECT_VALID(task, OBJECT_TASK)) - p = task->priority; - - return p; -} - - -priority_t task_setpriority(task_t *task, priority_t new) -{ - register priority_t p = 0; - - if (OBJECT_VALID(task, OBJECT_TASK)) { - SCHED_DISABLE(); - p = task->priority; - task->priority = new; - if ((task->credits = new) == -128) - task->credits++; - SCHED_ENABLE(); - } - - return p; -} - - -/* This is the code which each new task automatically starts executing, which - * performs some initializations and then executes the task-specific code. - * It also takes control again when the task ends and returns. - */ -static void task_startend_code(void) -{ - register task_t *task = CURTASK(); - - /* XXX Setup our reserved signals and port */ - - /* Call the supplied entry point function */ - task->rescode = task->start(task->res, task->args); - - /* Adios amigo! Translation: KTHXBYE!111 */ - task_end(task); - /* NOTREACHED */ -} - - - -/* System tasks - * ============ - */ - -/* This consists of Xisop init task. It's purpose is to launch the system - * tasks as well as all tasks which the port-specific code defined which should - * be launched. We also link in system and port-defined shared libraries. - * Resident devices and handlers actually consist of tasks and are given - * no special treatment. - */ -/* ARGSUSED */ -int task_init(void *res, void *args) -{ - /* Register ourself */ - root->task_init = CURTASK(); - - /* Attach system shared libraries */ - { - /* XXX */ - } - - /* Launch system tasks, which auto-register themselves by storeing their - * address in the Xisop root structure. - */ - { - register task_t *task; - - /* Task reaper */ - if ((task = task_alloc(task_reaper, NULL, NULL, 0, 4096, - TF_KERNEL | TF_SHARED)) != NULL) - task_start(task); - } - - /* Attach port-specified shared libraries and launch port-specific tasks */ - _port_init(); - - /* And perform our init task shores, which are neverending. */ - { - port_t *pubport; - - if ((pubport = port_create("INIT")) != NULL) { - port_t *ports[] = { - pubport - }; - register message_t *msg; - - /* Currently just reply to any message we get and do nothing */ - for (;;) { - if ((port_wait(ports, 1, NULL)) == pubport) { - while ((msg = port_get(pubport)) != NULL) - port_reply(msg); - } - } - } - } - - /* XXX We actually could safely die here for now, but don't want to. - * Eventually we will make sure that the tasks remain running, and - * restart tasks which are marked to be persistant if they ever die. - */ - /* NOTREACHED */ - return 0; -} - - -/* This consists of the reaper task, which is started by Xisop init task. - * Our duty consists of sleeping, but to free the tasks which are on the - * dead queue, if any, when wakeing up. The only event which awakes us up - * consists of the task_end() function. As tasks may have alot of resources - * to free back to the system, it is a good idea to have this task dedicating - * it's own CPU time to do it, it releives all other tasks, as well as the - * kernel from having to. - */ -/* ARGSUSED */ -static int task_reaper(void *res, void *args) -{ - /* Register ourselves for task_end() */ - root->task_reaper = CURTASK(); - - for (;;) { - task_sleep(CURTASK(), TSF_KERNEL, NULL); - /* We were awaken by task_end() */ - for (;;) { - register task_t *task; - - SCHED_DISABLE(); - task = DLIST_TOP(&root->tasks_dead); - SCHED_ENABLE(); - if (task != NULL) { - /* Free this task and let some CPU time to others */ - task_free(task); - _yield(NULL); - } else - break; - } - } - - /* NOTREACHED */ - return 0; -} diff --git a/Xisop/src/common/kernel/task.h b/Xisop/src/common/kernel/task.h deleted file mode 100644 index ea9f069..0000000 --- a/Xisop/src/common/kernel/task.h +++ /dev/null @@ -1,164 +0,0 @@ -/* $Id: task.h,v 1.2 2004/01/19 18:07:11 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_TASK_H -#define KERNEL_TASK_H - - - -#include -#include -#include -#include -#include -#include -#include -#include -/*#include XXX I must be able to include this!*/ - - - -/* Useful macro to be used in kernel code */ -#define CURTASK() (root->curtask) - - - -/* task.state */ -#define STATE_START 0 -#define STATE_READY 1 -#define STATE_WAIT 2 -#define STATE_DEAD 3 /* To be removed */ -#define STATE_RUN 4 - -/* task.flags and tn_message.event */ -#define TF_KERNEL (1 << 0) /* Kernelspace task */ -#define TF_SYSTEM (1 << 1) /* A system task */ -#define TF_DEVICE (1 << 2) /* Task is a device */ -#define TF_HANDLER (1 << 3) /* Task is a handler */ -#define TF_OS (1 << 4) /* OS resident task */ -#define TF_SHARED (1 << 5) /* Shares mpool_t w/ parent */ - -/* some defined values for task.priority */ -#define PRI_MAX 127 /* highest priority */ -#define PRI_DEFAULT 0 /* default priority for normal tasks */ -#define PRI_MIN -127 /* lowest priority */ - - - -/* Task's allocated resources */ -struct resources { - list_t ports; /* Linked via port_t->tasknode */ - list_t devices; /* Linked via device_t->tasknode */ - devicenode_t *device; /* If we are a device */ - /*handlernode_t *handler;*/ /* If we are a handler */ -}; - -/* XXX Don't know if this will be useful/required yet */ -/* These, similarly to the task's memory pool, will only be freed once the - * parent task is freed, in case it has threads. - * XXX hmm I think that the message ports cannot be shared among threads, since - * they require a signal bit, allocated on the specific task! - * now would signal shareing be wanted? several tasks would then be awaken - * by the same signal. I doubt we want this on xisop. - */ -/* -struct procstate { - lock *currentdir; - lock *in; - lock *out; - lock *err; - struct handlerpacket pkt; - struct msgport *pktrp; -}; -*/ - -/* This is a task node, as the kernel sees it. */ -struct task { - /* Tasks use the primary node for swapping */ - pnode_t node; - /* User multipurpose node */ - node_t usernode; - - /* Validity sceal */ - u_int32_t object_magic; - - /* Info */ - u_int32_t sleepflags; - u_int8_t flags; - u_int8_t state; - - /* Credits are given according to priority by the scheduler */ - priority_t priority, credits; - - /* Signal */ - sigmask_t sigalloc, sigwait, sigrecv; - /* XXX sigfunc sighandlers[32]; */ - - /* Entry point and parameters/results */ - int (*start)(void *, void *); - void *res, *args; - int rescode; - - /* Context */ - page_t *stack; - size_t stacksize; - _ctx_t ctx; - - /* Memory pool, which can be shared or unique */ - mpool_t *mpool; - - /* Resources we have opened which need special handling other than - * freeing the memory they allocated. - */ - struct resources resources; -}; - - - -task_t *task_alloc(int (*)(void *, void *), void *, void *, priority_t, - size_t, u_int8_t); -task_t *task_free(task_t *); -bool task_start(task_t *); -bool task_end(task_t *); -priority_t task_getpriority(task_t *); -priority_t task_setpriority(task_t *, priority_t); - -int task_init(void *, void *); - - - -#endif diff --git a/Xisop/src/common/kernlib/clean.sh b/Xisop/src/common/kernlib/clean.sh deleted file mode 100755 index c8bd473..0000000 --- a/Xisop/src/common/kernlib/clean.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../generic_makedefs.sh - -cleanlib . -cleanlib string -show $L_RM ar/*.a diff --git a/Xisop/src/common/kernlib/fifo.h b/Xisop/src/common/kernlib/fifo.h deleted file mode 100644 index 3e4cc71..0000000 --- a/Xisop/src/common/kernlib/fifo.h +++ /dev/null @@ -1,165 +0,0 @@ -/* $Id: fifo.h,v 1.2 2004/06/04 19:03:36 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_FIFO_H -#define KERNLIB_FIFO_H - - - -#include - - - -/* Allows to create a new fifo_t type structure, to fit any data type */ -#define FIFO_DEFINE(n, o) typedef struct n { \ - o *top, *bottom, *head, *tail; \ - u_int32_t size; \ -} n - -FIFO_DEFINE(fifo8_t, u_int8_t); -FIFO_DEFINE(fifo16_t, u_int16_t); -FIFO_DEFINE(fifo32_t, u_int32_t); -FIFO_DEFINE(fifo64_t, u_int64_t); - - - -/* Initializes a FIFO */ -#define FIFO_INIT(f, b, s) do { \ - (f)->top = (f)->head = (f)->tail = (b); \ - (f)->bottom = &((b)[(s)]); \ - (f)->size = (s) - 1; \ -} while (/* CONSTCOND */0) - -/* Used to compute the next location of a tail or head pointer, accounting - * for the necessary occasional rotation. - */ -#define FIFO_NEXT(f, p) (&((p)[1]) == (f)->bottom ? (f)->top : &((p)[1])) - -/* Returns TRUE if the FIFO is full, that is, cannot hold more elements */ -#define FIFO_FULL(f) (FIFO_NEXT((f), (f)->head) == (f)->tail) - -/* Returns TRUE if the FIFO is empty */ -#define FIFO_EMPTY(f) ((f)->head == (f)->tail) - -/* Returns the number of currently held elements into a FIFO */ -#define FIFO_STAT(f) (FIFO_EMPTY(f) ? 0 : \ - (f)->head - (f)->tail > 0 ? \ - ((f)->head - (f)->tail) / sizeof(*(f)->head): \ - ((f)->size - ((f)->tail - (f)->head)) / sizeof(*(f)->head)) - -#define FIFO_AVAIL(f) ((f)->size - FIFO_STAT(f)) - -#define FIFO_FLUSH(f) ((f)->tail = (f)->head) - -/* If no available room the oldest element is lost. The caller may verify - * with FIFO_FULL() first if needed. - */ -#define FIFO_PUT(f, e) do { \ - *(f)->head = *(e); \ - (f)->head = FIFO_NEXT((f), (f)->head); \ - if (FIFO_EMPTY(f)) \ - (f)->tail = FIFO_NEXT((f), (f)->tail); \ -} while (/* CONSTCOND */0) - -/* Has no action if the buffer has no more elements, but does not return any - * result to say so. The caller may use FIFO_EMPTY() to check if needed. - */ -#define FIFO_GET(f, e) do { \ - if (!FIFO_EMPTY(f)) { \ - *(e) = *(f)->tail; \ - (f)->tail = FIFO_NEXT((f), (f)->tail); \ - } \ -} while (/* CONSTCOND */0) - -#define FIFO_FIND(f, p, e) do { \ - register typeof(*(e)) *r; \ - \ - *(p) = NULL; \ - for (r = (f)->tail; r != (f)->head; r = FIFO_NEXT(f, r)) \ - if (*r == *(e)) { \ - *(p) = r; \ - break; \ - } \ -} while (/* CONSTCOND */0) - -/* XXX Those are bugged for now */ -#define FIFO_ALLOC(f, p, a, s) do { \ - register int r; \ - \ - if ((r = (f)->tail - (f)->head) != 0) { \ - if (r < 1) \ - r = (f)->bottom - (f)->head; \ - if ((r /= sizeof(*(f)->head)) > (int)(s)) \ - r = (int)(s); \ - *(p) = (f)->head; \ - (f)->head = (&((f)->head[r]) == (f)->bottom ? (f)->top : \ - &((f)->head[r])); \ - } \ - *(a) = (size_t)r; \ -} while (/* CONSTCOND */0) - -#define FIFO_FREE(f, p, a, s) do { \ - register int r; \ - \ - if ((r = (f)->head - (f)->tail) != 0) { \ - if (r < 1) \ - r = (f)->bottom - (f)->tail; \ - if ((r /= sizeof(*(f)->tail)) > (int)(s)) \ - r = (int)(s); \ - *(p) = (f)->tail; \ - (f)->tail = (&((f)->tail[r]) == (f)->bottom ? (f)->top : \ - &((f)->tail[r])); \ - } \ - *(a) = (size_t)r; \ -} while (/* CONSTCOND */0) - -#define FIFO_WRITE(f, p, a, s) do { \ - /* XXX */ \ -} while (/* CONSTCOND */0) - -#define FIFO_READ(f, p, a, s) do { \ - /* XXX */ \ -} while (/* CONSTCOND */0) - - - -size_t getnfifo8(u_int8_t *, fifo8_t *, size_t); -size_t putnfifo8(fifo8_t *, u_int8_t *, size_t); - - - -#endif diff --git a/Xisop/src/common/kernlib/hash.c b/Xisop/src/common/kernlib/hash.c deleted file mode 100644 index c652405..0000000 --- a/Xisop/src/common/kernlib/hash.c +++ /dev/null @@ -1,381 +0,0 @@ -/* $Id: hash.c,v 1.6 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software written by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include - - - -/* This system is safe to use 32-bit hashes internally, despite the possibility - * for collisions. We maintain an array or buckets, within which the entries - * are distributed. A 32-bit hash collision entry will end up on the same - * bucket. We however also make sure to not allow to store exact duplicate - * keys. The number if buckets will increase and decrease whenever the system - * detects that it becomes necessary for efficiency. The larger the number of - * buckets, the less nodes are likely to coexist in each bucket. The bucket - * index to use is evaluated using a modulo to convert the 32-bit hash to - * fit into the current number of buckets in the table. Of course, when - * the number of buckets is to be updated (which ideally happens rarely), - * the entries are rehashed to be properly indexed within the new capacity. - * - * The number of buckets is automatically doubled when the table fills up - * at a factor of 1. This way, we avoid having to calculate a fill factor - * using floating point arithmetic. Commonly used value for the initial hash - * table bucket capacity is 16, which are set HT_DEFAULT_CAPACITY represents. - * - * Searching for a key by pattern, which requires iterating through the - * nodes, rather than through it's absolute key can actually be a little - * slower than running through a simple linked list of absolute hash values, - * since all buckets must be scanned. However, we ensure to stop running - * through buckets when the total number of mappings have been scanned already. - * Lookups using the absolute key of the node will be much faster in the case - * where the hash table grows considerably, however. - */ - - - -#define HASH_INDEX(h, s) ((h) % (s)) - - - -static void hashtable_rehash(hashtable_t *, unsigned int); - - - -bool hashtable_init(hashtable_t *t, const char *label, - unsigned int initialcapacity, void *(*allocfunc)(size_t), - void (*freefunc)(void *), - int (*keycomp)(const void *, const void *, size_t), - u_int32_t (*keyhash)(const void *, size_t), bool dynamic) -{ - if (!OBJECT_VALID(t, OBJECT_HASHTABLE)) { - if ((t->array = allocfunc(sizeof(list_t) * initialcapacity)) != NULL) { - unsigned int i; - - OBJECT_VALIDATE(t, OBJECT_HASHTABLE); - t->label = label; - t->malloc = allocfunc; - t->free = freefunc; - t->keycomp = keycomp; - t->keyhash = keyhash; - t->nodes = 0; - t->initial = t->capacity = initialcapacity; - t->avgtotal = t->avgcnt = initialcapacity; - t->dynamic = dynamic; - t->iterating = FALSE; - for (i = 0; i < initialcapacity; i++) - DLIST_INIT(&(t->array[i])); - - return TRUE; - } else - DEBUG_PRINTF("* %T hashtable_init(%p = %s) - malloc(%d)\n", - label, t, (int)sizeof(list_t) * initialcapacity); - } else - DEBUG_PRINTF( - "* %T hashtable_init(%p = %s) - Table already initialized", - label, t); - - return FALSE; -} - - -void hashtable_destroy(hashtable_t *t, bool freeall) -{ - if (OBJECT_VALID(t, OBJECT_HASHTABLE)) { - if (t->array != NULL) { - if (freeall) { - register unsigned int i, done; - register list_t *l; - register hashnode_t *k, *kt; - - for (i = done = 0; done < t->nodes && i < t->capacity; i++) { - l = &(t->array[i]); - if (DLIST_NODES(l) > 0) { - for (k = DLIST_TOP(l); k != NULL; k = kt) { - kt = DLIST_NEXT(k); - pool_free((pnode_t *)k); - done++; - } - } - } - } - t->free(t->array); - } - OBJECT_INVALIDATE(t); - } else - DEBUG_PRINTF( - "* %T hashtable_destroy(%p) - Invalid hashtable_t pointer", - t); -} - - -hashnode_t *hashtable_lookup(hashtable_t *t, const void *key, size_t keysize) -{ - register u_int32_t hash; - register unsigned int i; - register list_t *l; - register hashnode_t *k = NULL; - - if (OBJECT_VALID(t, OBJECT_HASHTABLE)) { - hash = t->keyhash(key, keysize); - i = HASH_INDEX(hash, t->capacity); - l = &(t->array[i]); - if (DLIST_NODES(l) > 0) { - DLIST_FOREACH(l, k) { - if (k->hash == hash && k->keysize == keysize && - t->keycomp(k->key, key, keysize) == 0) - break; - } - } - } else - DEBUG_PRINTF( - "* %T hashtable_lookup(%p) - Invalid hashtable_t pointer", - t); - - return k; -} - - -bool hashtable_link(hashtable_t *t, hashnode_t *k, const void *key, - size_t keysize, bool check) -{ - register u_int32_t hash; - register unsigned int i; - register list_t *l; - bool ok = TRUE; - - if (!OBJECT_VALID(t, OBJECT_HASHTABLE)) { - DEBUG_PRINTF("* %T hashtable_link(%p) - Invalid hashtable_t pointer", - t); - return FALSE; - } - if (k == NULL) { - DEBUG_PRINTF( - "* %T hashtable_link(NULL) - Table (%p = %s) Invalid " - "hashnode_t pointer", - t, t->label); - return FALSE; - } - - hash = t->keyhash(key, keysize); - i = HASH_INDEX(hash, t->capacity); - l = &(t->array[i]); - if (check) { - /* We do not allow exact duplicates, so verify first. Duplicate - * hashes are fine, however, as long as the key data is not identical. - */ - if (DLIST_NODES(l) > 0) { - register hashnode_t *tk; - - DLIST_FOREACH(l, tk) { - if (tk == k || (tk->hash == hash && tk->keysize == keysize && - t->keycomp(tk->key, key, keysize) == 0)) { - DEBUG_PRINTF( - "* %T hashtable_link(%p = %s, %p) - Duplicate key " - "insert attempt", t, t->label, k); - ok = FALSE; - break; - } - } - } - } - if (ok) { - OBJECT_VALIDATE(k, OBJECT_HASHNODE); - k->hash = hash; - k->list = l; - k->key = key; - k->keysize = keysize; - DLIST_INSERT(l, (node_t *)k); - /* Grow capacity if necessary */ - t->nodes++; - if (t->dynamic && !t->iterating) { - if (t->dynamic && !t->iterating) - hashtable_rehash(t, t->capacity * 2); - } - } - - return ok; -} - - -void hashtable_unlink(hashtable_t *t, hashnode_t *k) -{ - if (OBJECT_VALID(t, OBJECT_HASHTABLE)) { - if (OBJECT_VALID(k, OBJECT_HASHNODE)) { - unsigned int exceeding; - - OBJECT_INVALIDATE(k); - DLIST_UNLINK(k->list, (node_t *)k); - k->list = NULL; - t->nodes--; - - /* Verify if the capacity should be reduced, using statistics */ - t->avgtotal += t->capacity; - t->avgcnt++; - if (t->avgcnt > t->capacity / (t->initial * 3)) { - t->avgcnt = 1; - t->avgtotal = t->capacity; - } - /* Rehash with a smaller capacity if necessary */ - if (t->dynamic && !t->iterating) { - if ((exceeding = t->capacity - (t->avgtotal / t->avgcnt)) > 0) - hashtable_rehash(t, t->capacity - exceeding); - } - } else - DEBUG_PRINTF( - "* %T hashtable_unlink(%p) - Table (%p = %s) Invalid " - "hashnode_t pointer", - k, t, t->label); - } else - DEBUG_PRINTF( - "* %T hashtable_unlink(%p) - Invalid hashtable_t pointer", - t); -} - - -/* Note that as the user generally has a pool_t dedicated to the hashnode_t - * elements for a particular table, it may be more efficient to not use - * the option and to pool_free() which does not need to iterate - * through nodes. This function has to however, because it obviously cannot - * assume that the caller wishes to free all nodes of the origin pool_t, or - * that all entries origin from the same pool_t. - */ -void hashtable_empty(hashtable_t *t, bool freeall) -{ - register unsigned int i; - register list_t *l; - register hashnode_t *k, *kt; - - if (OBJECT_VALID(t, OBJECT_HASHTABLE)) { - if (freeall) { - for (i = 0; i < t->capacity; i++) { - l = &(t->array[i]); - if (DLIST_NODES(l) > 0) { - for (k = DLIST_TOP(l); k != NULL; k = kt) { - kt = DLIST_NEXT(k); - pool_free((pnode_t *)k); - } - } - } - } else { - for (i = 0; i < t->capacity; i++) - DLIST_INIT(&(t->array[i])); - } - if (t->dynamic && !t->iterating) - hashtable_rehash(t, t->initial); - } else - DEBUG_PRINTF( - "* %T hashtable_empty(%p) - Invalid hashtable_t pointer", - t); -} - - -void hashtable_iterate(hashtable_t *t, - bool (*func)(hashnode_t *, void *), void *udata) -{ - register unsigned int i; - register list_t *l; - register hashnode_t *k, *kt; - - if (OBJECT_VALID(t, OBJECT_HASHTABLE)) { - if (t->nodes > 0) { - t->iterating = TRUE; - for (i = 0; i < t->capacity; i++) { - l = &(t->array[i]); - if (DLIST_NODES(l) > 0) { - /* Note that we use a temporary variable to hold the next - * key, in case the user function alters the key node - * (i.e. unlinks it) - */ - for (k = DLIST_TOP(l); k != NULL; k = kt) { - kt = DLIST_NEXT(k); - if (!func(k, udata)) { - t->iterating = FALSE; - return; - } - } - } - } - t->iterating = FALSE; - } - } else - DEBUG_PRINTF( - "* %T hashtable_iterate(%p) - Invalid hashtable_t pointer", - t); -} - - -/* Rehashes the whole hashtable so that the capacity may be changed to the - * specified one. The memory area is also automatically changed. Ideally, - * this only occurs rarely. If it fails because of a lack of memory, the - * hash table will simply not be affected, but lookups will become slower. - */ -static void hashtable_rehash(hashtable_t *t, unsigned int newcapacity) -{ - list_t *newarray; - - if ((newarray = t->malloc(sizeof(list_t) * newcapacity)) != NULL) { - register unsigned int i, done; - - for (i = 0; i < newcapacity; i++) - DLIST_INIT(&newarray[i]); - - for (i = done = 0; done < t->nodes && i < t->capacity; i++) { - register hashnode_t *k, *kt; - register list_t *l, *newl; - - l = &(t->array[i]); - if (DLIST_NODES(l) > 0) { - for (k = DLIST_TOP(l); k != NULL; k = kt) { - kt = DLIST_NEXT(k); - newl = &newarray[HASH_INDEX(k->hash, newcapacity)]; - DLIST_SWAP(newl, l, (node_t *)k, TRUE); - k->list = newl; - done++; - } - } - } - - t->capacity = newcapacity; - t->free(t->array); - t->array = newarray; - } -} diff --git a/Xisop/src/common/kernlib/hash.h b/Xisop/src/common/kernlib/hash.h deleted file mode 100644 index ed04553..0000000 --- a/Xisop/src/common/kernlib/hash.h +++ /dev/null @@ -1,96 +0,0 @@ -/* $Id: hash.h,v 1.5 2004/06/04 02:15:47 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_HASH_H -#define KERNLIB_HASH_H - - - -#include -#include -#include - - - -struct hashnode { - pnode_t node; - u_int32_t object_magic, hash; - list_t *list; - const void *key; - size_t keysize; - /* Custom user data will follow, uncluding the key element to which the - * previous key pointer is expected to point. - */ -}; - -struct hashtable { - pnode_t node; /* In case we want a pool_t of hashtable_t */ - u_int32_t object_magic; - unsigned int initial, capacity, nodes; - const char *label; - list_t *array; - void *(*malloc)(size_t); - void (*free)(void *); - int (*keycomp)(const void *, const void *, size_t); - u_int32_t (*keyhash)(const void *, size_t); - unsigned int avgtotal, avgcnt; - bool dynamic, iterating; -}; - - - -#define HT_DEFAULT_CAPACITY 16 - -#define HASHTABLE_NODES(t) ((t)->nodes) - - - -bool hashtable_init(hashtable_t *, const char *, unsigned int, - void *(*)(size_t), void (*)(void *), - int (*)(const void *, const void *, size_t), - u_int32_t (*)(const void *, size_t), bool); -void hashtable_destroy(hashtable_t *, bool); -hashnode_t *hashtable_lookup(hashtable_t *, const void *, size_t); -bool hashtable_link(hashtable_t *, hashnode_t *, const void *, size_t, bool); -void hashtable_unlink(hashtable_t *, hashnode_t *); -void hashtable_empty(hashtable_t *, bool); -void hashtable_iterate(hashtable_t *, bool (*)(hashnode_t *, void *), - void *); - - - -#endif diff --git a/Xisop/src/common/kernlib/lifo.h b/Xisop/src/common/kernlib/lifo.h deleted file mode 100644 index ae9e260..0000000 --- a/Xisop/src/common/kernlib/lifo.h +++ /dev/null @@ -1,107 +0,0 @@ -/* $Id: lifo.h,v 1.3 2004/06/04 19:14:07 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_LIFO_H -#define KERNLIB_LIFO_H - - - -#include - - - -/* LIFO_DEFINE(lifotypename, objecttype); */ -#define LIFO_DEFINE(n, o) typedef struct n { \ - u_int32_t size, elements; \ - o *buffer, *endbuffer, *head; \ -} n - -/* Because of the way this is implemented using macros, it would also be - * possible to provide lifo types to hold structures. - */ -LIFO_DEFINE(lifo8_t, u_int8_t); -LIFO_DEFINE(lifo16_t, u_int16_t); -LIFO_DEFINE(lifo32_t, u_int32_t); -LIFO_DEFINE(lifo64_t, u_int64_t); - - - -/* XXX Although it's great to use macros for these operations, it also - * prevents assembly functions to be provided to replace them. - */ -/* void LIFO_INIT(lifo*_t *, u_int*_t *, u_int32_t); */ -#define LIFO_INIT(f, b, s) do { \ - (f)->size = (s); \ - (f)->elements = 0; \ - (f)->buffer = (f)->endbuffer = (f)->head = (b); \ -} while (/* CONSTCOND */0) - -/* bool LIFO_FULL(lifo*_t *); */ -#define LIFO_FULL(f) ((f)->elements == (f)->size) - -/* u_int32_t LIFO_STAT(lifo*_t *); */ -#define LIFO_STAT(f) ((f)->elements) - -/* void LIFO_FLUSH(lifo*_t *); */ -#define LIFO_FLUSH(f) do { \ - (f)->head = (f)->buffer; \ - (f)->elements = 0; \ -} while (/* CONSTCOND */0) - -/* void LIFO_PUT(lifo*_t *, u_int*_t *); */ -#define LIFO_PUT(s, e) do { \ - if ((s)->elements < (s)->size) { \ - *((s)->head++) = *(e); \ - (s)->elements++; \ - } \ -} while (/* CONSTCOND */0) - -/* void LIFO_GET(lifo*_t *, u_int*_t *); */ -#define LIFO_GET(s, e) do { \ - if ((s)->elements > 0) { \ - *(e) = *(--(s)->head); \ - (s)->elements--; \ - } \ -} while (/* CONSTCOND */0) - -/* LIFO_ALLOC(lifo*_t *, u_int*_t **, size_t *); */ - -/* LIFO_FREE(lifo*_t, u_int*_t **, size_t *); */ - - - -#endif diff --git a/Xisop/src/common/kernlib/list.h b/Xisop/src/common/kernlib/list.h deleted file mode 100644 index ebb8bd1..0000000 --- a/Xisop/src/common/kernlib/list.h +++ /dev/null @@ -1,178 +0,0 @@ -/* $Id: list.h,v 1.5 2004/06/04 19:14:07 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNEL_LIST_H -#define KERNEL_LIST_H - - - -#include - - - -typedef struct list list_t; -typedef struct node node_t; - - - -struct node { - node_t *prev, *next; -}; - -struct list { - node_t *top, *bottom; - u_int32_t nodes; -}; - - - -/* Some macros to optimize operations on doubly linked lists */ -#define DLIST_INITIALIZER {NULL, NULL, 0} - -#define DLIST_INIT(lst) do { \ - (lst)->top = (lst)->bottom = NULL; \ - (lst)->nodes = 0; \ -} while (/* CONSTCOND */0) - -#define DLIST_UNLINK(lst, nod) do { \ - register node_t *prev = (nod)->prev, *next = (nod)->next; \ - \ - if (prev != NULL) \ - prev->next = next; \ - else \ - (lst)->top = next; \ - if (next != NULL) \ - next->prev = prev; \ - else \ - (lst)->bottom = prev; \ - (lst)->nodes--; \ -} while (/* CONSTCOND */0) - -#define DLIST_APPEND(lst, nod) do { \ - register node_t *tmp = (lst)->bottom; \ - \ - if (tmp != NULL) { \ - tmp->next = (nod); \ - (nod)->prev = tmp; \ - (nod)->next = NULL; \ - (lst)->bottom = (nod); \ - } else { \ - (lst)->bottom = (lst)->top = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_INSERT(lst, nod) do { \ - register node_t *tmp = (lst)->top; \ - \ - if (tmp != NULL) { \ - tmp->prev = (nod); \ - (nod)->prev = NULL; \ - (nod)->next = tmp; \ - (lst)->top = (nod); \ - } else { \ - (lst)->top = (lst)->bottom = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_INSERTAT(lst, atnode, nod) do { \ - register node_t *prev = (atnode)->prev, *next = (atnode); \ - \ - (nod)->next = next; \ - next->prev = (nod); \ - if (prev != NULL) { \ - prev->next = (nod); \ - (nod)->prev = prev; \ - } else { \ - (lst)->top = (nod); \ - (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_SWAP(dst, src, nod, ins) do { \ - register node_t *prev = (nod)->prev, *next = (nod)->next; \ - \ - if (prev != NULL) \ - prev->next = next; \ - else \ - (src)->top = next; \ - if (next != NULL) \ - next->prev = prev; \ - else \ - (src)->bottom = prev; \ - (src)->nodes--; \ - if ((ins)) { \ - if ((prev = (dst)->top) != NULL) { \ - prev->prev = (nod); \ - (nod)->prev = NULL; \ - (nod)->next = prev; \ - (dst)->top = (nod); \ - } else { \ - (dst)->top = (dst)->bottom = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - } else { \ - if ((prev = (dst)->bottom) != NULL) { \ - prev->next = (nod); \ - (nod)->prev = prev; \ - (nod)->next = NULL; \ - (dst)->bottom = (nod); \ - } else { \ - (dst)->bottom = (dst)->top = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - } \ - (dst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_TOP(lst) ((void *)((list_t *)(lst))->top) -#define DLIST_BOTTOM(lst) ((void *)((list_t *)(lst))->bottom) -#define DLIST_NEXT(var) ((void *)((node_t *)(var))->next) -#define DLIST_PREV(var) ((void *)((node_t *)(var))->prev) - -#define DLIST_FOREACH(lst, var) \ - for ((var) = DLIST_TOP((lst)); (var) != NULL; (var) = DLIST_NEXT((var))) - -#define DLIST_NODES(lst) (((list_t *)(lst))->nodes) - - - -#endif diff --git a/Xisop/src/common/kernlib/make.sh b/Xisop/src/common/kernlib/make.sh deleted file mode 100755 index 0bf7318..0000000 --- a/Xisop/src/common/kernlib/make.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../makedefs.sh - -buildlib string -show $C_AR ar/string.a string/*.o -show $C_RANLIB ar/string.a - -buildlib . -show $C_AR ar/kernlib.a *.o -show $C_RANLIB ar/kernlib.a diff --git a/Xisop/src/common/kernlib/rand.c b/Xisop/src/common/kernlib/rand.c deleted file mode 100644 index f2071fe..0000000 --- a/Xisop/src/common/kernlib/rand.c +++ /dev/null @@ -1,108 +0,0 @@ -/* $Id: rand.c,v 1.2 2004/01/29 04:56:50 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software written by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Algorithm was borrowed from: - * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1). - * "Random number generators: good ones are hard to find", - * Park and Miller, Communications of the ACM, vol. 31, no. 10, - * October 1988, p. 1195. - * - * The 10,000nth invokation with default initial seed of 1 should result - * in 1043618065. Of course, this is a highly predictable algorithm, but - * it is rather well distributed, while also being quite fast, and is thus - * suitable in the implementation of ANSI/C89 rand(3)/srand(3) functions. - * Do NOT use for cryptography related work. - * Matt - */ - - - -#include -#include - - - -static unsigned int global_seed = 1; - - - -int rand(void) -{ - /* - register int a, b; - - a = b = (signed int)global_seed; - a /= 127773; - b %= 127773; - - b *= 16807; - a *= 2836; - b -= a; - if (b <= 0) - b += 0x7fffffff; - - global_seed = b; - - return b; - */ - - int v; - - if ((v = (global_seed % 127773 * 16807) - - (global_seed / 127773 * 2836)) < 1) - v += 0x7fffffff; - global_seed = v; - - return v; -} - - -void srand(unsigned int seed) -{ - global_seed = seed; -} - - -/* This is the POSIX reentrant variant where caller supplies seed */ -int rand_r(unsigned int *seed) -{ - int v; - - if ((v = (*seed % 127773 * 16807) - (*seed / 127773 * 2836)) < 1) - v += 0x7fffffff; - *seed = v; - - return v; -} diff --git a/Xisop/src/common/kernlib/rand.h b/Xisop/src/common/kernlib/rand.h deleted file mode 100644 index 29ed498..0000000 --- a/Xisop/src/common/kernlib/rand.h +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id: rand.h,v 1.1 2004/01/29 04:55:06 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software written by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_RAND_H -#define KERNLIB_RAND_H - - - -#include - - - -int rand(void); -void srand(unsigned int); -int rand_r(unsigned int *); - - - -#endif diff --git a/Xisop/src/common/kernlib/setjmp.h b/Xisop/src/common/kernlib/setjmp.h deleted file mode 100644 index e19e520..0000000 --- a/Xisop/src/common/kernlib/setjmp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* $Id: setjmp.h,v 1.1 2004/01/30 07:01:24 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_SETJMP_H -#define KERNLIB_SETJMP_H - - - -/* These functions, as well as _ctx_t are defined by the processor-specific - * support headerfile, . These are the C89/ANSI - * setjmp()/longjmp(). - */ - - - -#include -#include - - - -typedef _ctx_t jmp_buf[1]; - - - -int setjmp(jmp_buf); -void longjmp(jmp_buf, int); - - - -#endif diff --git a/Xisop/src/common/kernlib/string.h b/Xisop/src/common/kernlib/string.h deleted file mode 100644 index cba5365..0000000 --- a/Xisop/src/common/kernlib/string.h +++ /dev/null @@ -1,106 +0,0 @@ -/* $Id: string.h,v 1.3 2004/06/03 05:40:46 mmondor Exp $ */ - -/* - * Copyright (C) 1989-2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef KERNLIB_STRING_H -#define KERNLIB_STRING_H - - - -#include -#include - - - -/* This is used for some kernel strings, such as public message port names */ -typedef struct bstr { - size_t size, len; /* Maximum and current lengths */ - u_int8_t data[1]; /* Actual buffer follows */ -} bstr_t; - - -bstr_t *bstr_alloc(size_t); -bstr_t *bstr_new(const char *, size_t, bool); -bstr_t *bstr_free(bstr_t *); - - - -/* More conventional string functions */ -size_t strlen(const char *); -size_t strnlen(const char *, size_t); - -char *_strcpy(char *, const char *); -size_t _strncpy(char *, const char *, size_t); - -char *_strcat(char *, const char *); -char *_strncat(char *, const char *, size_t); - -int strcmp(const char *, const char *); -int strncmp(const char *, const char *, size_t); - -char *strchr(const char *, int); -char *strnchr(const char *, int, size_t); -char *strrchr(const char *, int); -char *strnrchr(const char *, int, size_t); - -char *_strdup(const char *); -char *_strndup(const char *, size_t); - -int straspl(char **, char *, int); -int strspl(char **, char *, int, char); - -int strcasecmp(const char *, const char *); -int strncasecmp(const char *, const char *, size_t); -void _strlower(char *); -void _strupper(char *); -u_int32_t _strpack32(const char *, size_t); -u_int32_t _memcasehash32(const void *, size_t); -int _memcasecmp(const void *, const void *, size_t); - -u_int32_t htol(const char *); -void _strrev(char *); -u_int32_t memhash32(const void *, size_t); - -#define memclr(a, l) memset((a), 0, (l)) -int memcmp(const void *, const void *, size_t); -void *memcpy(void *, const void *, size_t); -void *memmove(void *, const void *, size_t); -void *memset(void *, int, size_t); -void pageclr(void *, u_int32_t); - - - -#endif diff --git a/Xisop/src/common/kernlib/string/_strcat.c b/Xisop/src/common/kernlib/string/_strcat.c deleted file mode 100644 index f431a05..0000000 --- a/Xisop/src/common/kernlib/string/_strcat.c +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id: _strcat.c,v 1.1 2004/06/03 05:40:02 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* XXX Unlike ANSI, returns pointer at end of destination rather to beginning - * to allow special optimizations in loops. - */ -char *_strcat(char *dest, const char *src) -{ - for (; *dest != '\0'; dest++) ; - for (; (*dest = *src++) != '\0'; dest++) ; - - return (dest); -} diff --git a/Xisop/src/common/kernlib/string/_strcpy.c b/Xisop/src/common/kernlib/string/_strcpy.c deleted file mode 100644 index affc726..0000000 --- a/Xisop/src/common/kernlib/string/_strcpy.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id: _strcpy.c,v 1.1 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* XXX Unlike standard strcpy(), returns pointer to end of copied string in - * destination, rather than to beginning, more useful to optimize some loops. - * This variant should never be called strcpy() (i.e., could be called - * _strcpy() however). - */ -char *_strcpy(char *dest, const char *src) -{ - for (; (*dest = *src++) != '\0'; dest++) ; - - return (dest); -} diff --git a/Xisop/src/common/kernlib/string/_strdup.c b/Xisop/src/common/kernlib/string/_strdup.c deleted file mode 100644 index 76a78c9..0000000 --- a/Xisop/src/common/kernlib/string/_strdup.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id: _strdup.c,v 1.3 2004/06/03 05:54:44 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include - - - -/* Uses kernel memory pool, should only be used by kernel code */ -char *_strdup(const char *str) -{ - char *new; - register const char *ptr; - register size_t len; - - for (new = NULL, ptr = str; *ptr != '\0'; ptr++) ; - - len = (size_t)(ptr - str) + 1; - if ((new = MALLOC(len)) != NULL) - (void) memcpy(new, str, len); - - return new; -} diff --git a/Xisop/src/common/kernlib/string/_strncat.c b/Xisop/src/common/kernlib/string/_strncat.c deleted file mode 100644 index 61115b2..0000000 --- a/Xisop/src/common/kernlib/string/_strncat.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id: _strncat.c,v 1.1 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* XXX Unlike ANSI, returns pointer at end of destination rather to beginning - * to allow special optimizations in loops. - */ -char *_strncat(char *dest, const char *src, size_t max) -{ - if (max != 0) { - register const char *toptr; - - for (toptr = dest, toptr += max; dest < toptr && *dest != '\0'; - dest++) ; - for (; dest < toptr && (*dest = *src++) != '\0'; dest++) ; - if (dest < toptr) - *dest = '\0'; - } - - return dest; -} diff --git a/Xisop/src/common/kernlib/string/_strncpy.c b/Xisop/src/common/kernlib/string/_strncpy.c deleted file mode 100644 index d9132eb..0000000 --- a/Xisop/src/common/kernlib/string/_strncpy.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id: _strncpy.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Unlike the useless return code of the standard ANSI one, - * this function returns the number of bytes successfully copied. - */ -size_t _strncpy(char *dest, const char *src, size_t max) -{ - if (max > 0) { - register const char *sptr; - register char *toptr; - - for (sptr = src, toptr = dest, toptr += max; - dest < toptr && (*dest = *sptr) != '\0'; sptr++, dest++) ; - if (dest == toptr) - *dest = '\0'; - - return ((size_t)(sptr - src)); - } - - *dest = '\0'; - return 0; -} diff --git a/Xisop/src/common/kernlib/string/_strndup.c b/Xisop/src/common/kernlib/string/_strndup.c deleted file mode 100644 index 007d15e..0000000 --- a/Xisop/src/common/kernlib/string/_strndup.c +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id: _strndup.c,v 1.3 2004/06/03 05:54:44 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include - - - -/* Uses kernel memory. */ -char *_strndup(const char *str, size_t max) -{ - char *new; - register const char *ptr, *toptr; - size_t len; - - for (toptr = ptr = str, toptr += max, new = NULL; - ptr < toptr && *ptr != '\0'; ptr++) ; - len = (size_t)(ptr - str); - if ((new = MALLOC(len + 1)) != NULL) { - (void) memcpy(new, str, len); - new[len] = '\0'; - } - - return new; -} diff --git a/Xisop/src/common/kernlib/string/_strrev.c b/Xisop/src/common/kernlib/string/_strrev.c deleted file mode 100644 index 3019ad2..0000000 --- a/Xisop/src/common/kernlib/string/_strrev.c +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id: _strrev.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Iteratively reverses the supplied string */ -void _strrev(char *str) -{ - register char *p1, *p2, t; - - for (p1 = p2 = str; *p2; p2++) ; - if (p2 > p1) - p2--; - - for (;p1 < p2; p1++, p2--) { - t = *p1; - *p1 = *p2; - *p2 = t; - } -} diff --git a/Xisop/src/common/kernlib/string/bstr_alloc.c b/Xisop/src/common/kernlib/string/bstr_alloc.c deleted file mode 100644 index 34b63c6..0000000 --- a/Xisop/src/common/kernlib/string/bstr_alloc.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id: bstr_alloc.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include - - - -/* This is always allocated using kernel memory, and is for use by kernel - * functions. - */ -bstr_t *bstr_alloc(size_t size) -{ - bstr_t *bstr = NULL; - - if ((bstr = MALLOC(sizeof(bstr_t) + size + 1)) != NULL) { - bstr->size = size; - bstr->len = 0; - *bstr->data = 0; - } - - return bstr; -} diff --git a/Xisop/src/common/kernlib/string/bstr_free.c b/Xisop/src/common/kernlib/string/bstr_free.c deleted file mode 100644 index ba7b837..0000000 --- a/Xisop/src/common/kernlib/string/bstr_free.c +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id: bstr_free.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include - - - -bstr_t *bstr_free(bstr_t *bstr) -{ - if (bstr != NULL) - FREE(bstr); - - return NULL; -} diff --git a/Xisop/src/common/kernlib/string/bstr_new.c b/Xisop/src/common/kernlib/string/bstr_new.c deleted file mode 100644 index 04eca59..0000000 --- a/Xisop/src/common/kernlib/string/bstr_new.c +++ /dev/null @@ -1,67 +0,0 @@ -/* $Id: bstr_new.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include - - - -/* This is always allocated using kernel memory, and is for use by kernel - * functions. - */ -bstr_t *bstr_new(const char *string, size_t max, bool fixed) -{ - register bstr_t *bstr = NULL; - register size_t len = strnlen(string, max); - register size_t size; - - if (fixed) - size = max; - else - size = len; - - if ((bstr = MALLOC(sizeof(bstr_t) + size + 1)) != NULL) { - bstr->size = size; - bstr->len = len; - memcpy(bstr->data, string, len); - bstr->data[len] = 0; - } - - return bstr; -} diff --git a/Xisop/src/common/kernlib/string/case.c b/Xisop/src/common/kernlib/string/case.c deleted file mode 100644 index 4835110..0000000 --- a/Xisop/src/common/kernlib/string/case.c +++ /dev/null @@ -1,241 +0,0 @@ -/* $Id: case.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -static const unsigned char toupper_table[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, - 0x1E, 0x1F, ' ', '!', '"', '#', '$', '%', '&', 0x27, - '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', - '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', - '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', - 'Z', '[', 0x5C, ']', '^', '_', '`', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '{', '|', '}', '~', 0x7F, 0x80, 0x81, - 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, - 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, - 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, - 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, - 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, - 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, - 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, - 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - -static const unsigned char tolower_table[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, - 0x1E, 0x1F, ' ', '!', '"', '#', '$', '%', '&', 0x27, - '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', - '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', - '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', - 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z', '[', 0x5C, ']', '^', '_', '`', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, 0x80, 0x81, - 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, - 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, - 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, - 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, - 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, - 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, - 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, - 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - - - -int strcasecmp(const char *s1, const char *s2) -{ - register const unsigned char *us1, *us2; - register unsigned char cs1, cs2; - - for (us1 = (const unsigned char *)s1, us2 = (const unsigned char *)s2, - cs1 = tolower_table[(int)*us1], cs2 = tolower_table[(int)*us2]; - cs1 != '\0' && cs2 != '\0' && - (cs1 = tolower_table[(int)*us1]) == - (cs2 = tolower_table[(int)*us2]); - us1++, us2++) ; - - return ((int)(cs1 - cs2)); -} - - -int strncasecmp(const char *s1, const char *s2, size_t max) -{ - register const unsigned char *us1, *us2, *toptr; - register unsigned char cs1, cs2; - - if (max == 0) - return 0; - - for (us1 = (const unsigned char *)s1, us2 = (const unsigned char *)s2, - cs1 = tolower_table[(int)*us1], cs2 = tolower_table[(int)*us2], - toptr = us1, toptr += max; - us1 < toptr && cs1 != '\0' && cs2 != '\0' && - (cs1 = tolower_table[(int)*us1]) == - (cs2 = tolower_table[(int)*us2]); - us1++, us2++) ; - - return (us1 < toptr ? ((int)(cs1 - cs2)) : 0); -} - - -void _strlower(char *str) -{ - register unsigned char *ustr; - - for (ustr = (unsigned char *)str; *ustr != '\0'; ustr++) - *ustr = tolower_table[(int)*ustr]; -} - - -void _strupper(char *str) -{ - register unsigned char *ustr; - - for (ustr = (unsigned char *)str; *ustr != '\0'; ustr++) - *ustr = toupper_table[(int)*ustr]; -} - - -/* This function generates a 32-bit hash using the supplied string which - * is suitable for fast lookup for command comparision. It simply converts - * characters to uppercase and stores them in the value. It of course can - * only perform this for 4 bytes. It will stop at either end of string '\0' - * or space ' '. If the string has more than 4 characters -1 is returned. - */ -u_int32_t _strpack32(const char *str, size_t min) -{ - register unsigned const char *ustr; - register u_int32_t hash = 0; - size_t i; - - for (ustr = (unsigned const char *)str, i = 0; *ustr > 32 && i < 5; i++) { - hash <<= 8; - hash |= toupper_table[(int)*ustr++]; - } - if (i < min || i > 4) - hash = 0; - - return hash; -} - - -/* These functions are useful to use in conjunction with hash tables if - * case-insensitive processing of data is required while case-sensitivity of - * records storage must be preserved. - */ - -u_int32_t _memcasehash32(const void *mem, size_t size) -{ - register u_int32_t hash; - register const unsigned char *curmem, *tomem; - - hash = 0; - curmem = tomem = mem; - tomem += size; - -#if !defined(_ARCH_LOWCACHE) - while (curmem < tomem - 4) { -#if !defined(_ARCH_USEINDEXING) - hash = toupper_table[(int)*curmem++] + (31 * hash); - hash = toupper_table[(int)*curmem++] + (31 * hash); - hash = toupper_table[(int)*curmem++] + (31 * hash); - hash = toupper_table[(int)*curmem++] + (31 * hash); -#else /* !defined(_ARCH_USEINDEXING) */ - hash = toupper_table[(int)curmem[0]] + (31 * hash); - hash = toupper_table[(int)curmem[1]] + (31 * hash); - hash = toupper_table[(int)curmem[2]] + (31 * hash); - hash = toupper_table[(int)curmem[3]] + (31 * hash); - curmem += 4; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (curmem < tomem) - hash = toupper_table[(int)*curmem++] + (31 * hash); - - return hash; -} - -int _memcasecmp(const void *s1, const void *s2, size_t size) -{ - register const unsigned char *ptr1, *ptr2, *toptr; - -#define CMP() toupper_table[(int)*ptr1++] != toupper_table[(int)*ptr2++] -#define RET() return (int)(toupper_table[(int)*(--ptr1)] - \ - toupper_table[(int)*(--ptr2)]) - - ptr1 = toptr = s1; - toptr += size; - ptr2 = s2; - -#if !defined(_ARCH_LOWCACHE) - while (ptr1 < toptr - 4) - if (CMP() || CMP() || CMP() || CMP()) - RET(); -#endif - while (ptr1 < toptr) - if (CMP()) - RET(); - -#undef CMP -#undef RET - - return 0; -} diff --git a/Xisop/src/common/kernlib/string/htol.c b/Xisop/src/common/kernlib/string/htol.c deleted file mode 100644 index 79ef88d..0000000 --- a/Xisop/src/common/kernlib/string/htol.c +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id: htol.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Converts an hexadecimal string to u_int32_t */ -u_int32_t htol(const char *s) -{ - register u_int32_t v = 0; - - while (*s) { - if (*s >= '0' && *s <= '9') { - if (v <= (u_int16_t)-1) - v = (u_int16_t)v * 16; - else - v = v * 16; - v += *s++ - '0'; - } else if (*s >= 'a' && *s <= 'f') { - if (v <= (u_int16_t)-1) - v = (u_int16_t)v * 16; - else - v = v * 16; - v += *s++ - 87; - } else if (*s >= 'A' && *s <= 'F') { - if (v <= (u_int16_t)-1) - v = (u_int16_t)v * 16; - else - v = v * 16; - v += *s++ - 55; - } else break; - } - - return v; -} diff --git a/Xisop/src/common/kernlib/string/memcmp.c b/Xisop/src/common/kernlib/string/memcmp.c deleted file mode 100644 index 6b3b0f9..0000000 --- a/Xisop/src/common/kernlib/string/memcmp.c +++ /dev/null @@ -1,120 +0,0 @@ -/* $Id: memcmp.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -int memcmp(const void *dest, const void *src, size_t len) -{ - register const unsigned char *ptr, *toptr, *dptr; - - ptr = toptr = src; - toptr += len; - dptr = dest; - -#define RET(a, b) return (int)(*(--(a)) - *(--(b))) - -#if _ARCH_INT_BITS == 8 - -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) - if (*ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ || - *ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ || - *ptr++ != *dptr++ || *ptr++ != *dptr++) - RET(dptr, ptr); -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - if (*ptr++ != *dptr++) - RET(dptr, ptr); - -#else /* _ARCH_INT_BITS != 8 */ - - if (len < 32 || ((int)ptr % sizeof(int)) != ((int)dptr % sizeof(int))) { -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) - if (*ptr++ != *dptr++ || *ptr++ != *dptr++ || *ptr++ != *dptr++ || - *ptr++ != *dptr++ || *ptr++ != *dptr++ || - *ptr++ != *dptr++ || *ptr++ != *dptr++ || - *ptr++ != *dptr++) - RET(dptr, ptr); -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - if (*ptr++ != *dptr++) - RET(dptr, ptr); - } else { - register const unsigned int *lptr, *ltoptr, *ldptr, *ldtoptr; - register const unsigned char *dtoptr; - - dtoptr = dptr; - dtoptr += len; - lptr = (const unsigned int *)OALIGN_CEIL(ptr, int); - ltoptr = (const unsigned int *)OALIGN_FLOOR(toptr, int); - ldptr = (const unsigned int *)OALIGN_CEIL(dptr, int); - ldtoptr = (const unsigned int *)OALIGN_FLOOR(dtoptr, int); - if (ldtoptr - ldptr < ltoptr - lptr) - ltoptr--; - - while (ptr < (const unsigned char *)lptr) - if (*ptr++ != *dptr++) - RET(dptr, ptr); -#if !defined(_ARCH_LOWCACHE) - while (lptr < ltoptr - (sizeof(int) * 8)) { - if (*lptr++ != *ldptr++ || *lptr++ != *ldptr++ || - *lptr++ != *ldptr++ || *lptr++ != *ldptr++ || - *lptr++ != *ldptr++ || *lptr++ != *ldptr++ || - *lptr++ != *ldptr++ || *lptr++ != *ldptr++) - RET(ldptr, lptr); - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr < ltoptr) - if (*lptr++ != *ldptr++) - RET(ldptr, lptr); - ptr = (const unsigned char *)lptr; - dptr = (const unsigned char *)ldptr; - while (ptr < toptr) - if (*ptr++ != *dptr++) - RET(dptr, ptr); - } - -#endif /* _ARCH_INT_BITS == 8 */ - -#undef RET - - return 0; -} diff --git a/Xisop/src/common/kernlib/string/memcpy.c b/Xisop/src/common/kernlib/string/memcpy.c deleted file mode 100644 index 398d91e..0000000 --- a/Xisop/src/common/kernlib/string/memcpy.c +++ /dev/null @@ -1,164 +0,0 @@ -/* $Id: memcpy.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -void *memcpy(void *dest, const void *src, size_t len) -{ - register const unsigned char *ptr, *toptr; - register unsigned char *dptr; - - ptr = toptr = src; - toptr += len; - dptr = dest; - -#if _ARCH_INT_BITS == 8 - -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[1] = ptr[1]; - dptr[2] = ptr[2]; - dptr[3] = ptr[3]; - dptr[4] = ptr[4]; - dptr[5] = ptr[5]; - dptr[6] = ptr[6]; - dptr[7] = ptr[7]; - dptr += 8; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *dptr++ = *ptr++; - -#else /* _ARCH_INT_BITS != 8 */ - - if (len < 32 || ((int)ptr % sizeof(int)) != ((int)dptr % sizeof(int))) { -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[1] = ptr[1]; - dptr[2] = ptr[2]; - dptr[3] = ptr[3]; - dptr[4] = ptr[4]; - dptr[5] = ptr[5]; - dptr[6] = ptr[6]; - dptr[7] = ptr[7]; - dptr += 8; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *dptr++ = *ptr++; - } else { - register const unsigned int *lptr, *ltoptr; - register unsigned int *ldptr, *ldtoptr; - register unsigned char *dtoptr; - - dtoptr = dptr; - dtoptr += len; - lptr = (const unsigned int *)OALIGN_CEIL(ptr, int); - ltoptr = (const unsigned int *)OALIGN_FLOOR(toptr, int); - ldptr = (unsigned int *)OALIGN_CEIL(dptr, int); - ldtoptr = (unsigned int *)OALIGN_FLOOR(dtoptr, int); - if (ldtoptr - ldptr < ltoptr - lptr) - ltoptr--; - - while (ptr < (const unsigned char *)lptr) - *dptr++ = *ptr++; -#if !defined(_ARCH_LOWCACHE) - while (lptr < ltoptr - (sizeof(int) * 8)) { -#if !defined(_ARCH_USEINDEXING) - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - ldptr[0] = lptr[0]; - ldptr[1] = lptr[1]; - ldptr[2] = lptr[2]; - ldptr[3] = lptr[3]; - ldptr[4] = lptr[4]; - ldptr[5] = lptr[5]; - ldptr[6] = lptr[6]; - ldptr[7] = lptr[7]; - ldptr = &ldptr[8]; - lptr = &lptr[8]; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr < ltoptr) - *ldptr++ = *lptr++; - ptr = (unsigned const char *)lptr; - dptr = (unsigned char *)ldptr; - while (ptr < toptr) - *dptr++ = *ptr++; - } - -#endif /* _ARCH_INT_BITS == 8 */ - - return dest; -} diff --git a/Xisop/src/common/kernlib/string/memhash32.c b/Xisop/src/common/kernlib/string/memhash32.c deleted file mode 100644 index 9184827..0000000 --- a/Xisop/src/common/kernlib/string/memhash32.c +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id: memhash32.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -u_int32_t memhash32(const void *mem, size_t size) -{ - register u_int32_t hash; - register const unsigned char *curmem, *tomem; - - hash = 0; - curmem = tomem = mem; - tomem += size; - -#if !defined(_ARCH_LOWCACHE) - while (curmem < tomem - 4) { -#if !defined(_ARCH_USEINDEXING) - hash = *curmem++ + (31 * hash); - hash = *curmem++ + (31 * hash); - hash = *curmem++ + (31 * hash); - hash = *curmem++ + (31 * hash); -#else /* !defined(_ARCH_USEINDEXING) */ - hash = curmem[0] + (31 * hash); - hash = curmem[1] + (31 * hash); - hash = curmem[2] + (31 * hash); - hash = curmem[3] + (31 * hash); - curmem += 4; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (curmem < tomem) - hash = *curmem++ + (31 * hash); - - return hash; -} diff --git a/Xisop/src/common/kernlib/string/memmove.c b/Xisop/src/common/kernlib/string/memmove.c deleted file mode 100644 index cd0db28..0000000 --- a/Xisop/src/common/kernlib/string/memmove.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $Id: memmove.c,v 1.1 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Can work with overlapping areas */ -void *memmove(void *dest, const void *src, size_t len) -{ - register const unsigned char *ptr = NULL, *toptr = NULL; - register unsigned char *dptr = NULL; - size_t d; - - if (dest < src) - d = (const unsigned char *)src - (unsigned char *)dest; - else - d = (unsigned char *)dest - (const unsigned char *)src; - -#if _ARCH_INT_BITS == 8 - - if (dest < src) { - /* Copy in increasing order */ - ptr = toptr = (const unsigned char *)src; - toptr += len; - dptr = dest; -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[1] = ptr[1]; - dptr[2] = ptr[2]; - dptr[3] = ptr[3]; - dptr[4] = ptr[4]; - dptr[5] = ptr[5]; - dptr[6] = ptr[6]; - dptr[7] = ptr[7]; - dptr += 8; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *dptr++ = *ptr++; - } else if (dest > src) { - /* Copy in reverse order */ - ptr = toptr = (const unsigned char *)src; - ptr += len; - dptr = dest; - dptr += len; -#if !defined(_ARCH_LOWCACHE) - while (ptr >= toptr + 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[-1] = ptr[-1]; - dptr[-2] = ptr[-2]; - dptr[-3] = ptr[-3]; - dptr[-4] = ptr[-4]; - dptr[-5] = ptr[-5]; - dptr[-6] = ptr[-6]; - dptr[-7] = ptr[-7]; - dptr -= 8; - ptr -= 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr >= toptr) - *dptr-- = *ptr--; - } - -#else /* _ARCH_INT_BITS != 8 */ - - if (len < 32 || d < sizeof(int) || - ((int)ptr % sizeof(int)) != ((int)dptr % sizeof(int))) { - if (dest < src) { - /* Copy in increasing order */ - ptr = toptr = (const unsigned char *)src; - toptr += len; - dptr = dest; -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; - *dptr++ = *ptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[1] = ptr[1]; - dptr[2] = ptr[2]; - dptr[3] = ptr[3]; - dptr[4] = ptr[4]; - dptr[5] = ptr[5]; - dptr[6] = ptr[6]; - dptr[7] = ptr[7]; - dptr += 8; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *dptr++ = *ptr++; - } else if (dest > src) { - /* Copy in reverse order */ - ptr = toptr = (const unsigned char *)src; - ptr += len; - dptr = dest; - dptr += len; -#if !defined(_ARCH_LOWCACHE) - while (ptr >= toptr + 8) { -#if !defined(_ARCH_USEINDEXING) - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; - *dptr-- = *ptr--; -#else /* !defined(_ARCH_USEINDEXING) */ - dptr[0] = ptr[0]; - dptr[-1] = ptr[-1]; - dptr[-2] = ptr[-2]; - dptr[-3] = ptr[-3]; - dptr[-4] = ptr[-4]; - dptr[-5] = ptr[-5]; - dptr[-6] = ptr[-6]; - dptr[-7] = ptr[-7]; - dptr -= 8; - ptr -= 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr >= toptr) - *dptr-- = *ptr--; - } - } else { - if (dest < src) { - /* Increasing order */ - register const unsigned int *lptr, *ltoptr; - register unsigned int *ldptr, *ldtoptr; - register unsigned char *dtoptr; - - ptr = toptr = (const unsigned char *)src; - toptr += len; - dptr = dest; - - dtoptr = dptr; - dtoptr += len; - lptr = (const unsigned int *)OALIGN_CEIL(ptr, int); - ltoptr = (const unsigned int *)OALIGN_FLOOR(toptr, int); - ldptr = (unsigned int *)OALIGN_CEIL(dptr, int); - ldtoptr = (unsigned int *)OALIGN_FLOOR(dtoptr, int); - if (ldtoptr - ldptr < ltoptr - lptr) - ltoptr--; - - while (ptr < (const unsigned char *)lptr) - *dptr++ = *ptr++; -#if !defined(_ARCH_LOWCACHE) - while (lptr < ltoptr - (sizeof(int) * 8)) { -#if !defined(_ARCH_USEINDEXING) - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; - *ldptr++ = *lptr++; -#else /* !defined(_ARCH_USEINDEXING) */ - ldptr[0] = lptr[0]; - ldptr[1] = lptr[1]; - ldptr[2] = lptr[2]; - ldptr[3] = lptr[3]; - ldptr[4] = lptr[4]; - ldptr[5] = lptr[5]; - ldptr[6] = lptr[6]; - ldptr[7] = lptr[7]; - ldptr = &ldptr[8]; - lptr = &lptr[8]; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr < ltoptr) - *ldptr++ = *lptr++; - ptr = (const unsigned char *)lptr; - dptr = (unsigned char *)ldptr; - while (ptr < toptr) - *dptr++ = *ptr++; - } else if (dest > src) { - /* Reverse order */ - register const int *lptr, *ltoptr; - register int *ldptr, *ldtoptr; - register char *dtoptr; - - ptr = toptr = (const unsigned char *)src; - ptr += len; - dptr = dest; - dptr += len; - - dtoptr = dest; - lptr = (const unsigned int *)OALIGN_FLOOR(ptr, int); - ldptr = (unsigned int *)OALIGN_FLOOR(dptr, int); - ltoptr = (const unsigned int *)OALIGN_CEIL(toptr, int); - ldtoptr = (unsigned int *)OALIGN_CEIL(dtoptr, int); - if (ldptr - ldtoptr < lptr - ltoptr) - ltoptr++; - - while (ptr >= (const unsigned char *)lptr) - *dptr-- = *ptr--; -#if !defined(_ARCH_LOWCACHE) - while (lptr >= ltoptr + (sizeof(int) * 8)) { -#if !defined(_ARCH_USEINDEXING) - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; - *ldptr-- = *lptr--; -#else /* !defined(_ARCH_USEINDEXING) */ - ldptr[0] = lptr[0]; - ldptr[-1] = lptr[-1]; - ldptr[-2] = lptr[-2]; - ldptr[-3] = lptr[-3]; - ldptr[-4] = lptr[-4]; - ldptr[-5] = lptr[-5]; - ldptr[-6] = lptr[-6]; - ldptr[-7] = lptr[-7]; - ldptr = &ldptr[-8]; - lptr = &lptr[-8]; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr >= ltoptr) - *ldptr-- = *lptr--; - ptr = (const unsigned char *)lptr; - dptr = (unsigned char *)ldptr; - while (ptr >= toptr) - *dptr-- = *ptr--; - } - } - -#endif /* _ARCH_INT_BITS == 8 */ - - return dest; -} diff --git a/Xisop/src/common/kernlib/string/memset.c b/Xisop/src/common/kernlib/string/memset.c deleted file mode 100644 index 65f0cdd..0000000 --- a/Xisop/src/common/kernlib/string/memset.c +++ /dev/null @@ -1,179 +0,0 @@ -/* $Id: memset.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -void *memset(void *mem, int fill, size_t len) -{ - register unsigned char *ptr, *toptr; - u_int8_t byte = (u_int8_t)fill; - - ptr = toptr = mem; - toptr += len; - -#if _ARCH_INT_BITS == 8 - -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; -#else /* !defined(_ARCH_USEINDEXING) */ - ptr[0] = byte; - ptr[1] = byte; - ptr[2] = byte; - ptr[3] = byte; - ptr[4] = byte; - ptr[5] = byte; - ptr[6] = byte; - ptr[7] = byte; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *ptr++ = byte; - -#else /* _ARCH_INT_BITS != 8 */ - - if (len < 32) { -#if !defined(_ARCH_LOWCACHE) - while (ptr < toptr - 8) { -#if !defined(_ARCH_USEINDEXING) - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; - *ptr++ = byte; -#else /* !defined(_ARCH_USEDARRAYS) */ - ptr[0] = byte; - ptr[1] = byte; - ptr[2] = byte; - ptr[3] = byte; - ptr[4] = byte; - ptr[5] = byte; - ptr[6] = byte; - ptr[7] = byte; - ptr += 8; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (ptr < toptr) - *ptr++ = byte; - } else { - register unsigned int *lptr, *ltoptr, lword = 0; - - if (byte != 0) { -#if _ARCH_INT_BITS == 16 - lword = ((byte << 8) & 0xff00) | (byte & 0x00ff); -#elif _ARCH_INT_BITS == 32 - /* Creating a 16-bit word from the 8-bit one, then the 32-bit word - * from the 16-bit one require less instructions. - */ - register u_int16_t tmp; - - tmp = ((byte << 8) & 0xff00) | (byte & 0x00ff); - lword = ((tmp << 16) & 0xffff0000) | (tmp & 0x0000ffff); -#elif _ARCH_INT_BITS == 64 - /* Unlikely, since long is usually 64-bit on 64-bit archs, leaving - * 32-bit ints. - * Creating a 16-bit word from the 8-bit one, a 32-bit word from - * the 16-bit one and a 64-bit word from the 32-bit one require - * less instructions. - */ - register u_int32_t tmp2; - register u_int16_t tmp; - - tmp = ((byte << 8) & 0xff00) | (byte & 0x00ff); - tmp2 = ((tmp << 16) & 0xffff0000) | (tmp & 0x0000ffff); - lword = ((tmp2 << 32) & 0xffffffff00000000ULL) | - (tmp2 & 0x00000000ffffffffULL); -#endif - } - - lptr = (unsigned int *)OALIGN_CEIL(ptr, int); - ltoptr = (unsigned int *)OALIGN_FLOOR(toptr, int); - - while (ptr < (unsigned char *)lptr) - *ptr++ = byte; -#if !defined(_ARCH_LOWCACHE) - while (lptr < ltoptr - (sizeof(int) * 8)) { -#if !defined(_ARCH_USEINDEXING) - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; -#else /* !defined(_ARCH_USEINDEXING) */ - lptr[0] = lword; - lptr[1] = lword; - lptr[2] = lword; - lptr[3] = lword; - lptr[4] = lword; - lptr[5] = lword; - lptr[6] = lword; - lptr[7] = lword; - lptr = &lptr[8]; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr < ltoptr) - *lptr++ = lword; - ptr = (unsigned char *)lptr; - while (ptr < toptr) - *ptr++ = byte; - } - -#endif /* _ARCH_INT_BITS == 8 */ - - return mem; -} diff --git a/Xisop/src/common/kernlib/string/pageclr.c b/Xisop/src/common/kernlib/string/pageclr.c deleted file mode 100644 index cb74b59..0000000 --- a/Xisop/src/common/kernlib/string/pageclr.c +++ /dev/null @@ -1,96 +0,0 @@ -/* $Id: pageclr.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include - - - -/* Faster than memset(), but assumes that be aligned and that _PAGE_SIZE - * is a multiple of sizeof(int). - */ -void pageclr(void *mem, u_int32_t many) -{ - register int *lptr, *ltoptr, lword = 0; - - lptr = (int *)mem; - ltoptr = (int *)(((u_int8_t *)mem + (_PAGE_SIZE * many))); - -#if !defined(_ARCH_LOWCACHE) - while (lptr < ltoptr - (sizeof(int) * 16)) { -#if !defined(_ARCH_USEINDEXING) - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; - *lptr++ = lword; -#else /* !defined(_ARCH_USEINDEXING) */ - lptr[0] = lword; - lptr[1] = lword; - lptr[2] = lword; - lptr[3] = lword; - lptr[4] = lword; - lptr[5] = lword; - lptr[6] = lword; - lptr[7] = lword; - lptr[8] = lword; - lptr[9] = lword; - lptr[10] = lword; - lptr[11] = lword; - lptr[12] = lword; - lptr[13] = lword; - lptr[14] = lword; - lptr[15] = lword; - lptr = &lptr[16]; -#endif /* !defined(_ARCH_USEINDEXING) */ - } -#endif /* !defined(_ARCH_LOWCACHE) */ - while (lptr < ltoptr) - *lptr++ = lword; -} diff --git a/Xisop/src/common/kernlib/string/straspl.c b/Xisop/src/common/kernlib/string/straspl.c deleted file mode 100644 index 7f15a91..0000000 --- a/Xisop/src/common/kernlib/string/straspl.c +++ /dev/null @@ -1,68 +0,0 @@ -/* $Id: straspl.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Splits columns of a string delimited by spaces and/or tabs, and fills - * char **argv with pointers to each column. Returns the number of columns - * that could be filled in. The supplied string IS modified. - */ -int straspl(char **argv, char *str, int maxcols) -{ - register char *ptr, *ptr2; - int col; - - for (ptr = str, col = 0; *ptr != '\0' && col < maxcols; ) { - for (; *ptr == ' ' || *ptr == '\t'; ptr++) ; - if (*ptr != '\0') { - for (ptr2 = ptr; *ptr != '\0' && *ptr != ' ' && *ptr != '\t'; - ptr++) ; - if (ptr != ptr2) { - if (*ptr != '\0') - *ptr++ = '\0'; - argv[col++] = ptr2; - } else - break; - } else - break; - } - - return col; -} diff --git a/Xisop/src/common/kernlib/string/strchr.c b/Xisop/src/common/kernlib/string/strchr.c deleted file mode 100644 index fd4c51d..0000000 --- a/Xisop/src/common/kernlib/string/strchr.c +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id: strchr.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -char *strchr(const char *str, int c) -{ - for (; *str != '\0' && *str != c; str++) ; - - return (*str != '\0' ? (char *)str : NULL); -} diff --git a/Xisop/src/common/kernlib/string/strcmp.c b/Xisop/src/common/kernlib/string/strcmp.c deleted file mode 100644 index 3d5c931..0000000 --- a/Xisop/src/common/kernlib/string/strcmp.c +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id: strcmp.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -int strcmp(const char *s1, const char *s2) -{ - for (; *s1 != '\0' && *s2 != '\0' && *s1 == *s2; s1++, s2++) ; - - return ((int)((const unsigned char)*s1 - (const unsigned char)*s2)); -} diff --git a/Xisop/src/common/kernlib/string/strlen.c b/Xisop/src/common/kernlib/string/strlen.c deleted file mode 100644 index 3bcca1b..0000000 --- a/Xisop/src/common/kernlib/string/strlen.c +++ /dev/null @@ -1,56 +0,0 @@ -/* $Id: strlen.c,v 1.2 2004/06/03 05:40:03 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -size_t strlen(const char *str) -{ - register const char *ptr = str; - - /* Although this causes ptr to be increased even when 0 is reached, - * compilers generally generate better code. - * i.e. GCC2-m68k: tstb %a0@+ vs tstb %a0@ and addql #1, %a0 - * Matt - */ - while (*ptr++ != '\0') ; - - /* Don't forget to substract 1 */ - return ((size_t)((ptr - 1) - str)); -} diff --git a/Xisop/src/common/kernlib/string/strnchr.c b/Xisop/src/common/kernlib/string/strnchr.c deleted file mode 100644 index a7ba5b8..0000000 --- a/Xisop/src/common/kernlib/string/strnchr.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $Id: strnchr.c,v 1.2 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -char *strnchr(const char *str, int c, size_t max) -{ - if (max > 0) { - register const char *toptr; - - for (toptr = str, toptr += max; - str < toptr && *str != '\0' && (int)*str != c; str++) ; - - if (str == toptr || *str == '\0') - return NULL; - - return (char *)str; - } - - return NULL; -} diff --git a/Xisop/src/common/kernlib/string/strncmp.c b/Xisop/src/common/kernlib/string/strncmp.c deleted file mode 100644 index de97198..0000000 --- a/Xisop/src/common/kernlib/string/strncmp.c +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id: strncmp.c,v 1.3 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -int strncmp(const char *s1, const char *s2, size_t max) -{ - if (max > 0) { - register const char *toptr; - - for (toptr = s1, toptr += max; s1 < toptr && *s1 != '\0' && - *s2 != '\0' && *s1 == *s2; s1++, s2++) ; - - return (s1 < toptr ? - ((int)((const unsigned char)*s1 - (const unsigned char)*s2)) : - 0); - } - - return 0; -} diff --git a/Xisop/src/common/kernlib/string/strnlen.c b/Xisop/src/common/kernlib/string/strnlen.c deleted file mode 100644 index 231521e..0000000 --- a/Xisop/src/common/kernlib/string/strnlen.c +++ /dev/null @@ -1,51 +0,0 @@ -/* $Id: strnlen.c,v 1.2 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -size_t strnlen(const char *str, size_t max) -{ - register const char *fptr, *tptr; - - for (fptr = tptr = str, tptr += max; fptr < tptr && *fptr != '\0'; fptr++) - ; - - return ((size_t)(fptr - str)); -} diff --git a/Xisop/src/common/kernlib/string/strnrchr.c b/Xisop/src/common/kernlib/string/strnrchr.c deleted file mode 100644 index a156119..0000000 --- a/Xisop/src/common/kernlib/string/strnrchr.c +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: strnrchr.c,v 1.2 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -char *strnrchr(const char *str, int c, size_t max) -{ - register const char *toptr, *found; - - for (found = NULL, toptr = str, toptr += max; - str < toptr && *str != '\0'; str++) { - if (*str == c) - found = str; - } - - return (char *)found; -} diff --git a/Xisop/src/common/kernlib/string/strrchr.c b/Xisop/src/common/kernlib/string/strrchr.c deleted file mode 100644 index d871c0e..0000000 --- a/Xisop/src/common/kernlib/string/strrchr.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id: strrchr.c,v 1.2 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -char *strrchr(const char *str, int c) -{ - register const char *found; - - for (found = NULL; *str != '\0'; str++) { - if (*str == c) - found = str; - } - - return (char *)found; -} diff --git a/Xisop/src/common/kernlib/string/strspl.c b/Xisop/src/common/kernlib/string/strspl.c deleted file mode 100644 index 0dac4a9..0000000 --- a/Xisop/src/common/kernlib/string/strspl.c +++ /dev/null @@ -1,65 +0,0 @@ -/* $Id: strspl.c,v 1.2 2004/06/03 05:40:04 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include - - - -/* Splits columns of a string delimited by sep, and fills - * char **argv with pointers to each column. Returns the number of columns - * that could be filled in. The supplied string IS modified. Note that two - * contiguous separators cause empty entries to be filled in. An exception - * consists of the last separator, which is ignored if nothing is found after - * it. - */ -int strspl(char **argv, char *str, int maxcols, char sep) -{ - register char *ptr, *ptr2; - int col; - - for (col = 0, ptr = str; *ptr != '\0' && col < maxcols; ) { - for (ptr2 = ptr; *ptr != '\0' && *ptr != sep; ptr++) ; - if (*ptr != '\0') - *ptr++ = '\0'; - argv[col++] = ptr2; - } - - return col; -} - - diff --git a/Xisop/src/common/make.sh b/Xisop/src/common/make.sh deleted file mode 100755 index 962d2c7..0000000 --- a/Xisop/src/common/make.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../makedefs.sh - -# Build kernlib -show cd kernlib -./make.sh -show cd .. - -# Build kernel -show cd kernel -./make.sh -show cd .. diff --git a/Xisop/src/common/types.h b/Xisop/src/common/types.h deleted file mode 100644 index c46da28..0000000 --- a/Xisop/src/common/types.h +++ /dev/null @@ -1,133 +0,0 @@ -/* $Id: types.h,v 1.6 2004/06/03 05:54:44 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef COMMON_TYPES_H -#define COMMON_TYPES_H - - - -typedef unsigned char u_int8_t; -typedef signed char int8_t; -typedef unsigned short u_int16_t; -typedef signed short int16_t; -typedef unsigned long u_int32_t; -typedef signed long int32_t; -typedef unsigned long long u_int64_t; -typedef signed long long int64_t; -typedef int bool; -typedef u_int32_t size_t; -typedef int32_t ssize_t; -#define NULL ((void *)0) -#define TRUE /* CONSTCOND */(1) -#define FALSE /* CONSTCOND */(0) - -/* For code-embedded copyright and CVS/RCS ID strings */ -#define COPYRIGHT(x) static const char _copyright[] = x -#define RCSID(x) static const char _rcsid[] = x - - -/* Useful to o-align a value relative to v (sizes and pointers) */ -#define OALIGN_CEIL(v, o) \ - ((((size_t)(v)) + (sizeof(o)) - 1) / (sizeof(o)) * (sizeof(o))) -#define OALIGN_FLOOR(v, o) ((size_t)(v) - (((size_t)(v) % sizeof(o)))) - -/* Useful to byte align a value with supplied size */ -#define BALIGN_CEIL(v, s) ((((size_t)(v)) + (s) - 1) / (s) * (s)) -#define BALIGN_FLOOR(v, s) ((size_t)(v) - (((size_t)(v) % (s)))) - -/* Import necessary processor-specific optimization macros */ -#include -/* For network and host byte order of 16-bit and 32-bit types */ -#if defined(_ARCH_LITTLE_ENDIAN) -#define BYTEORDER_NETWORK16 _bswap16 -#define BYTEORDER_HOST16 _bswap16 -#define BYTEORDER_NETWORK32 _bswap32 -#define BYTEORDER_HOST32 _bswap32 -#elif defined(_ARCH_BIG_ENDIAN) -#define BYTEORDER_NETWORK16(w) (w) -#define BYTEORDER_HOST16(w) (w) -#define BYTEORDER_NETWORK32(w) (w) -#define BYTEORDER_HOST32(w) (w) -#else -error "Endian not specified (_ARCH_LITTLE_ENDIAN | _ARCH_BIG_ENDIAN)"; -#endif -/* Ensure that _ARCH_INT_BITS was defined */ -#ifndef _ARCH_INT_BITS -error "Bits in an int (_ARCH_INT_BITS) not specified (8, 16, 32, 64)"; -#endif - -/* common/kernel/device.h */ -typedef struct devicenode devicenode_t; -typedef struct devicehandle device_t; -typedef struct iorequest iorequest_t; - -/* common/kernel/exception.h */ -typedef u_int32_t hookid_t; -typedef struct _int_hook hook_t; -typedef struct _int_facility facility_t; - -/* common/kernel/memory.h */ -typedef struct page page_t; -typedef struct mchunk mchunk_t; -typedef struct pool pool_t; -typedef struct ppool ppool_t; -typedef struct pnode pnode_t; -typedef struct mpool mpool_t; -typedef struct mnode mnode_t; - -/* common/kernel/port.h */ -typedef struct port port_t; -typedef struct message message_t; -typedef struct mmessage mmessage_t; - -/* common/kernel/scheduler.h */ -typedef struct rwlock rwlock_t; - -/* common/kernel/signal.h */ -typedef int signum_t; -typedef u_int32_t sigmask_t; - -/* common/kernel/task.h */ -typedef struct task task_t; -typedef int8_t priority_t; - -/* common/kernlib/hash.h */ -typedef struct hashtable hashtable_t; -typedef struct hashnode hashnode_t; - - -#endif diff --git a/Xisop/src/config.h b/Xisop/src/config.h deleted file mode 100644 index 08cc233..0000000 --- a/Xisop/src/config.h +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id: config.h,v 1.5 2004/01/29 05:02:02 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef CONFIG_H -#define CONFIG_H - - - -/* Flags which are possible to uncomment to compile in the kernel */ - -#define DEBUG 4096 -#define STATISTICS - - - -#endif diff --git a/Xisop/src/generic_makedefs.sh b/Xisop/src/generic_makedefs.sh deleted file mode 100644 index a3bf722..0000000 --- a/Xisop/src/generic_makedefs.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -# $Id: generic_makedefs.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -# These are various defaults which are used for the building process. -# Change as required, and don't forget to create the ./port and ./processor -# symbolic links to their respective directory. - -# Local non-cross building tools -L_AR='ar qS' -L_AS='as' -L_CC='gcc' -L_LD='ld' -L_NM='nm' -L_OBJDUMP='objdump' -L_RANLIB='ranlib' -L_STRIP='strip' -L_CAT='cat' -L_DD='dd' - -# Other general purpose tools -L_RM='rm -f' -L_LN='ln -s' -L_SED='sed' -L_ECHO='echo' -L_LS='ls' - -show() -{ - # Only output to stderr, not stdout - $L_ECHO "$@" >&2 - $@ -} - -# Deletes all .o files in a directory -# $1 = directory -cleanlib() -{ - show $L_RM $1/*.o -} diff --git a/Xisop/src/make.sh b/Xisop/src/make.sh deleted file mode 100755 index 3ae7f99..0000000 --- a/Xisop/src/make.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ./generic_makedefs.sh - -usage() -{ - $L_ECHO - $L_ECHO 'Usage: ./make.sh -t ' - $L_ECHO - $L_ECHO 'Available targets:' - $L_ECHO '- amiga' - $L_ECHO -} - -while getopts t: f; do - case $f in - t) - case $OPTARG in - amiga) - PROCESSOR='processors/m68k' - PORT='ports/amiga' - ;; - *) - $L_ECHO "Unknown target $OPTARG" - ;; - esac - ;; - *) - usage - exit 0 - ;; - esac -done -if [ -z $PORT ] || [ -z $PROCESSOR ]; then - usage - exit 0 -fi - -./clean.sh -show $L_LN $PROCESSOR processor -show $L_LN $PORT port -show $L_LN $PORT/makedefs.sh makedefs.sh -show export SRCDIR=`pwd` - -# XXX Is this a bug? As port/ symbolic link goes down two levels, I have to -# cd back two levels? - -# Build processor-specific support code to processor/ar/*.a -show cd processor -show ./make.sh - -# Build port-specific support code to port/ar/*.a -show cd ../../port -show ./make.sh - -# Build the portable common code to common/kernel/ar/*.a, -# common/kernlib/ar/*.a and XXX ??? -# and link to global ELF relocatable kernel object xisop.o -show cd ../../common -show ./make.sh - -# Let the port-specific boot code create the kernel image -show cd ../port/boot -show ./make.sh - -show cd .. diff --git a/Xisop/src/ports/amiga/boot/DOTuaerc b/Xisop/src/ports/amiga/boot/DOTuaerc deleted file mode 100644 index b78e08c..0000000 --- a/Xisop/src/ports/amiga/boot/DOTuaerc +++ /dev/null @@ -1,27 +0,0 @@ -config_description=UAE -x11.rom_path=./ -x11.floppy_path=./ -x11.hardfile_path=./ -x11.low_bandwidth=false -x11.use_mitshm=false -x11.hide_cursor=true -32bit_blits=true -use_gui=nowait -use_debugger=false -kickstart_rom_file=/home/mmondor/kick.rom -floppy0=/home/mmondor/src/work/Xisop/src/ports/amiga/boot/xisop.adf -floppy1= -floppy2= -floppy3= -sound_output=none -joyport0=mouse -joyport1=kbd1 -kbd_lang=us -immediate_blits=yes -cpu_speed=max -cpu_type=68000 -chipmem_size=2 -fastmem_size=4 -#filesystem=rw,System3.1:/data2/amiga/System3.1 -#filesystem=rw,Work:/data2/amiga/Work -#filesystem=rw,ASM:/data2/amiga/asm diff --git a/Xisop/src/ports/amiga/boot/README b/Xisop/src/ports/amiga/boot/README deleted file mode 100644 index a088fde..0000000 --- a/Xisop/src/ports/amiga/boot/README +++ /dev/null @@ -1,12 +0,0 @@ -DOTuaerc ~/.uaerc used for testing and developping with UAE - Amiga emulator - -xisop.adf Actual Amiga bootable Xisop floppy image - -image.bin Consists of the actual compiled kernel binary image -image.o Useful for debugging, objdump -drw image.o -bootf/bootf.bin Compiled floppy boot sector image -bootf/kernel.bin Compiled floppy boot sector image + Xisop image - -config.h File to modify depending on your Amiga model and - kernel size, stack size, etc. diff --git a/Xisop/src/ports/amiga/boot/bootf/bootf_c.c b/Xisop/src/ports/amiga/boot/bootf/bootf_c.c deleted file mode 100644 index 7088e55..0000000 --- a/Xisop/src/ports/amiga/boot/bootf/bootf_c.c +++ /dev/null @@ -1,139 +0,0 @@ -/* $Id: bootf_c.c,v 1.2 2004/01/20 20:56:20 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This used to be done by assembly code, it's however best to have a C - * loader which could eventually perform fancy stuff, and relocation as well. - * If the loader eventually gets too large to fit into the default boot block - * size, this boot block can then simply serve to load another loader and - * launch it. - */ - - - -#include - -#include "../config.h" - - -COPYRIGHT("\0\nXisop bootloader Copyright 2001-2003, Matthew Mondor, \ -All rights reserved.\n"); - - - -/* CONFIGURATION */ -#define KERNSTART 1024 /* Start of kernel image on disk */ -#define READSIZE 4096 /* Block size for read/relocation (512 min) */ - - - -#define MEMF_CHIP 0x0001 -#define MEMF_FAST 0x0002 -#define CMD_READ 2 -#define ALRT_NOMEM 0x00010001 -#define ALRT_RERR 0x14000001 - - -struct iostdreq { - u_int8_t pad[28]; - u_int16_t command; - u_int8_t flags; - int8_t error; - u_int32_t actual, length; - void *data; - u_int32_t offset; -}; - - -void *AllocMem(long, long); -void *AllocAbs(long, void *); -void FreeMem(void *, long); -long DoIO(struct iostdreq *); -void Alert(long, void *); - -void load(struct iostdreq *); - - - -void load(struct iostdreq *ioreq) -{ - void *buf = NULL, *readbuf = NULL; - bool ok = FALSE; - - /* Allocate CHIP memory buffer to load disk blocks into */ - if ((readbuf = AllocMem(READSIZE, MEMF_CHIP)) != NULL) { - - if ((buf = AllocAbs(KERNSIZE + STACKSIZE, (void *)KERNADDR)) - == (void *)KERNADDR) { - register u_int32_t offset, *addr, *toaddr; - - /* Read image from disk starting at KERNSTART, upto - * KERNSTART + KERNSIZE, in blocks of READSIZE bytes, which we - * relocate to our kernel buffer on the fly in KERNADDR. - */ - for (offset = KERNSTART, addr = buf, toaddr = buf + KERNSIZE; - addr < toaddr; offset += READSIZE) { - register u_int32_t *raddr, *taddr; - - /* Read a block */ - ioreq->command = CMD_READ; - ioreq->length = READSIZE; - ioreq->data = readbuf; - ioreq->offset = offset; - if ((DoIO(ioreq)) != 0) { - Alert(ALRT_RERR, load); - for (;;) ; - /* NOTREACHED */ - } - - /* Relocate block */ - for (raddr = readbuf, taddr = readbuf + READSIZE; - raddr < taddr; *addr++ = *raddr++) ; - } - ok = TRUE; - } - FreeMem(readbuf, READSIZE); - if (ok) { - void (*code)(u_int32_t *, size_t); - - /* Jump to relocated code, passing it the supervisor stack */ - code = (void *)KERNADDR; - code((u_int32_t *)STACKADDR, STACKSIZE); - } - } - - Alert(ALRT_NOMEM, load); - for (;;) ; - /* NOTREACHED */ -} diff --git a/Xisop/src/ports/amiga/boot/bootf/bootf_s.s b/Xisop/src/ports/amiga/boot/bootf/bootf_s.s deleted file mode 100644 index 2937275..0000000 --- a/Xisop/src/ports/amiga/boot/bootf/bootf_s.s +++ /dev/null @@ -1,118 +0,0 @@ -/* $Id: bootf_s.s,v 1.2 2004/01/20 20:56:20 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -ExecBase = 0x0004 - - -.globl _start, AllocMem, AllocAbs, FreeMem, DoIO, Alert - - -.text - -| AmigaOS boot header (checksum should be calculated after assembling) -| This is actually loaded at 0x0020b660, the ROM jumps at 0x0020b66c. - .long 0x444f5300, 0x00000000, 0x00000000 - -_start: - -| Loader code (startup leaves us with a6 to exec.lib and a1 to IOreq pointer) -| Call our C load() function! -| - movel %a1, %sp@- - bsrl load -| NOTREACHED - addql #4, %sp - rts - - -| Amiga library of required function stubs for load() C function - -| [d0]void * = [-198]AllocMem([d0]long bytes, [d1]long reqs) -| -AllocMem: - moveml %a6/%d1-%d0, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d0 - movel %sp@(20), %d1 - jsr %a6@(-198) - moveal %d0, %a0 - moveml %sp@+, %d0-%d1/%a6 - rts - -| [d0]void * = [-204]AllocAbs([d0]long bytes, [a1]void *addr) -| -AllocAbs: - moveml %a1/%a6/%d0, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d0 - moveal %sp@(20), %a1 - jsr %a6@(-204) - moveal %d0, %a0 - moveml %sp@+, %d0/%a6/%a1 - rts - -| void [-210]FreeMem([a1]memptr, [d0]bytesize) -| -FreeMem: - moveml %a1/%a6/%d0, %sp@- - moveal ExecBase:w, %a6 - moveal %sp@(16), %a1 - movel %sp@(20), %d0 - jsr %a6@(-210) - moveml %sp@+, %d0/%a6/%a1 - rts - -| [d0] = [-456]DoIO([a1]struct IORequest *) -| -DoIO: - moveml %a1/%a6, %sp@- - moveal ExecBase:w, %a6 - moveal %sp@(12), %a1 - jsr %a6@(-456) - moveml %sp@+, %a6/%a1 - rts - -| void [-108]Alert([d7]long alertNum,[a5]char *flags) -| -Alert: - moveml %d7/%a5-%a6, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d7 - moveal %sp@(20), %a5 - jsr %a6@(-108) - moveml %sp@+, %a6-%a5/%d7 - rts diff --git a/Xisop/src/ports/amiga/boot/bootf/bootf_script.ld b/Xisop/src/ports/amiga/boot/bootf/bootf_script.ld deleted file mode 100644 index b422db9..0000000 --- a/Xisop/src/ports/amiga/boot/bootf/bootf_script.ld +++ /dev/null @@ -1,14 +0,0 @@ -OUTPUT_FORMAT("binary", "binary", "binary") -OUTPUT_ARCH(m68k) - -ENTRY(_start) - -SECTIONS { - . = 0x0020b660; - .text : { - *(.text) - *(.rodata) - *(.data) - *(.bss) - } -} diff --git a/Xisop/src/ports/amiga/boot/clean.sh b/Xisop/src/ports/amiga/boot/clean.sh deleted file mode 100755 index 79f30ca..0000000 --- a/Xisop/src/ports/amiga/boot/clean.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.2 2004/01/20 20:56:20 mmondor Exp $ - -. ../../../generic_makedefs.sh - -show $L_RM image.bin image.o init.o -show $L_RM tools/aosbblock tools/dumpkern tools/config -show $L_RM bootf/bootf_s.o bootf/bootf_c.o bootf/bootf.o bootf/bootf.bin -show $L_RM bootf/kern.bin xisop.adf diff --git a/Xisop/src/ports/amiga/boot/config.h b/Xisop/src/ports/amiga/boot/config.h deleted file mode 100644 index 537e947..0000000 --- a/Xisop/src/ports/amiga/boot/config.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id: config.h,v 1.1 2004/01/20 20:56:20 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Until proper memory auto-detection is made, this file contains the general - * information needed to setup the supervisor stack and kernel image location, - * as well as the available RAM. - * This currently assumes that 4 megs of FAST RAM are located from - * 0x00200000 to 0x005fffff (Card 1, Zorro II), and that 2 megs of CHIP RAM - * are found from 0x00001000 to 0x001fffff. - * All these numbers should be a multiple of 4096 bytes. - */ - - - -/* CONFIGURATION */ - -/* Size of kernel image to read from disk, in bytes */ -#define KERNSIZE 65536 - -/* Size of kernel supervisor stack, in bytes */ -#define STACKSIZE 8192 - -/* Boundaries of FAST RAM */ -#define FMEM_START 0x00200000 -#define FMEM_END 0x00600000 - -/* Boundaries of CHIP RAM */ -#define CMEM_START 0x00001000 -#define CMEM_END 0x00200000 - - -/* These are useful results, used by boot/bootf/bootf_c.c, boot/init.c - * and boot/tools/config.c - */ -#define STACKADDR (FMEM_END - STACKSIZE) -#define KERNADDR (STACKADDR - KERNSIZE) -#define FPOOLADDR (FMEM_START) -#define FPOOLSIZE (KERNADDR - FMEM_START - 1) -#define CPOOLADDR (CMEM_START) -#define CPOOLSIZE (CMEM_END - CMEM_START - 1) diff --git a/Xisop/src/ports/amiga/boot/image_script.ld b/Xisop/src/ports/amiga/boot/image_script.ld deleted file mode 100644 index 8ee2279..0000000 --- a/Xisop/src/ports/amiga/boot/image_script.ld +++ /dev/null @@ -1,13 +0,0 @@ -OUTPUT_FORMAT("binary", "binary", "binary") -OUTPUT_ARCH(m68k) - -ENTRY(_start) - -SECTIONS { - .text : { - *(.text) - *(.rodata) - *(.data) - *(.bss) - } -} diff --git a/Xisop/src/ports/amiga/boot/init.c b/Xisop/src/ports/amiga/boot/init.c deleted file mode 100644 index 1e59866..0000000 --- a/Xisop/src/ports/amiga/boot/init.c +++ /dev/null @@ -1,590 +0,0 @@ -/* $Id: init.c,v 1.7 2004/01/20 21:26:48 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This code entry point consist of _start() which is called by the boot - * loader. We setup the supervisor stack pointer and then jump to _init(), - * which sets up the various port-specifics for Xisop, and finally launches - * Xisop itself calling main(). See the Xisop documentation for more - * information on what port-specific code has to provide in it's - * initialization and support.h. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - - - -/* Entry point */ -void _start(u_int32_t *, size_t); - -/* Our initialization functions */ -static void _init(void); -static void _disable_interrupts(void); -static void _stop_floppy_motor(void); -static void _init_memory(void); -static void _init_syscalls(void); -static void _enable_keyboard_interrupt(void); -static void _enable_vblank_interrupt(void); -static void _init_scheduler(void); -static void _init_screen(void); - -/* C exception handlers */ -void _icatch1(u_int16_t); -void _icatch2(u_int16_t); -void _icatch3(u_int16_t); -void _icatch4(u_int16_t); -void _icatch5(u_int16_t); -void _tcatch(int); -void _ecatch(int); - - -/* Port-specific port-initialization, to attach our port-specific shared - * libraries and launch our port-specific tasks - */ -struct initmsg { - message_t node; - u_int16_t color; -}; - -struct taskarg { - u_int16_t color; - u_int32_t rounds; -}; - -static int _task_color_server(void *, void *); -static int _task_color_client(void *, void *); -static void _keyboard_hook(hookid_t, int, void *); -void _panic(u_int16_t); - - - -/* Used to ensure that only the first exception occurs */ -static _rlock_t elock; - - - -/* The role of this function is to go in supervisor mode, set the supervisor - * stack, then call init(). - */ -void _start(u_int32_t *ssp, size_t sz) { - _supervisor(ssp, sz, _init); - /* NOTREACHED */ -} - - -/* Main port-specific initialization */ -static void _init(void) -{ - /* So that ecatch() cannot recurse */ - _rlock_init(&elock); - - _disable_interrupts(); - _stop_floppy_motor(); - - memory_init(); /* MI function */ - _init_memory(); - - facilities_init(); - - _init_exceptions(); - - _init_syscalls(); - - _enable_keyboard_interrupt(); - _enable_vblank_interrupt(); - _init_scheduler(); - _init_screen(); - - /* It is necessary to call this other MI function now, which internally - * will enable interrupts when safe to do so, which should have been - * disabled all along initialization. - */ - xisop_init(); - - /* We finally can switch to usermode and jump to MI main(). - * _usermode() m68k-specific function uses 1024 bytes on the - * current supervisor stack to create a user stack, and jumps to - * the specified function in user mode using that small stack. - */ - _usermode(main); - - /* NOTREACHED */ -} - - -static void _disable_interrupts(void) -{ - /* Turn off scheduling, interrupts and DMA channels */ - Forbid(); - /* Disable interrupts */ - _splhigh(); - CUSTOM->INTENA = INTENA_CLRALL; - CUSTOM->INTREQ = INTREQ_CLRALL; - /* Disable DMA */ - CUSTOM->DMACON = DMACON_CLRALL; - /* Disable CIA interrupt generation */ - CIA_A->ICR = CIA_ICR_CLRALL; - CIA_B->ICR = CIA_ICR_CLRALL; -} - - -static void _stop_floppy_motor(void) -{ - /* Stop floppy0 drive motor */ - CIA_B->PRB &= ~CIAB_PRB_FLOP0; /* Select */ - CIA_B->PRB |= CIAB_PRB_FMOTOR; /* Command */ -} - - -static void _init_memory(void) -{ - mchunk_t *mchunk; - - /* Initialize memory system, facilities_init() needs this to be done. - * XXX Some effort should be made to better detect the available memory, - * but at least it's easy to fix for each system type right now. - * The file to modify consists of ../config.h - */ - mchunk = mchunk_init((void *)FPOOLADDR, FPOOLSIZE); - mchunk_attach(_MEM_FAST, mchunk); - mchunk = mchunk_init((void *)CPOOLADDR, CPOOLSIZE); - mchunk_attach(_MEM_CHIP, mchunk); -} - - -static void _init_syscalls(void) -{ - CUSTOM->INTENA = INT_SETCLR | INT_SOFT; -} - - -static void _enable_keyboard_interrupt(void) -{ - /* Enable keyboard interrupts */ - CIA_A->CRA = CIA_CRA_START | CIA_CRA_INMODE; - CIA_A->ICR = CIA_ICR_SETCLR | CIA_ICR_SERDONE; - CUSTOM->INTENA = INT_SETCLR | INT_CIAA; -} - - -static void _enable_vblank_interrupt(void) -{ - /* Enable vertical blank interrupt */ - CUSTOM->INTENA = INT_SETCLR | INT_VBLANK; -} - - -/* Enable CIA-B TimerA interrupt for scheduler, which has high priority */ -static void _init_scheduler(void) -{ - u_int8_t *p; - u_int16_t v; - - /* Evaluate latch value to use for scheduler frequency */ - v = (u_int16_t)(CIA_COUNTSPEED / SCHEDTIMER_HZ); - p = (u_int8_t *)&v; - /* Stop timer and set latch */ - CIA_B->CRA = 0x00; - CIA_B->TAHI = p[0]; - CIA_B->TALO = p[1]; - /* Start and order to load latch value, in contiguous mode */ - CIA_B->CRA = CIA_CRA_START | CIA_CRA_LOAD; - CIA_B->ICR = CIA_ICR_SETCLR | CIA_ICR_TIMA0; - /* Enable CIA-B interrupts */ - CUSTOM->INTENA = INT_SETCLR | INT_CIAB; -} - - -/* Setup our Amiga Xisop console screen */ -/* XXX I have two choices here. I could use a 16 color screen and emulate - * ANSI-BBS colors, or just use a two color one and use my very small fonts. - * in the second case, I could still support a few control codes. - */ -static void _init_screen(void) -{ - u_int16_t s; - - /* I need to allocate/initialize a bitmap/bitplane, as well as - * chip memory for the copper list. - */ - s = asplvblank(); - /* Screen size and position configuration */ - CUSTOM->DDFSTRT = 0x3C; - CUSTOM->DDFSTOP = 0xD4; - CUSTOM->DIWSTRT = 0x2C81; - CUSTOM->DIWSTOP = 0xF4C1; - CUSTOM->CLXCON = 0x0000; - /* Enable bitplane and copper DMA */ - CUSTOM->DMACON = DMACON_SETCLR | DMACON_BLITTER /*| DMACON_COPPER*/; - asplx(s); -} - - -/* These consist of the various interrupt handlers corresponding to each - * of the 6 maskable hardware interrupt levels. Using _spl*() one can set the - * current task level which may not be interrupted by every lower level. - * may be used to evaluate the cause of the interrupt. - */ - -/* ARGSUSED */ -void _icatch1(u_int16_t intreq) -{ - _ipl_t x; - - x = _spl1(); - if (intreq & INT_SOFT) { - /* Software interrupt */ - } - if (intreq & INT_FLOPBLCK) { - /* Floppy disk block done interrupt */ - facility_exechooks(_FACILITY_FLOPPYBLOCK, 0); - } - if (intreq & INT_SERTBE) { - /* Serial RS-232 trasmit buffer empty interrupt */ - facility_exechooks(_FACILITY_SERIALTBE, 0); - } - _splx(x); -} - -void _icatch2(u_int16_t intreq) -{ - _ipl_t x; - - x = _spl2(); - if (intreq & INT_CIAA) { - /* CIA-A or expansion bus pin 19 interrupt */ - u_int8_t icrmask = CIA_A->ICR; - - /* CIA-A TimerA available. - * CIA-A TimerB used for keyboard. - * CIA-A TOD counter available. - */ - if (icrmask & CIA_ICR_TIMB0) { - /* CIA-A TimerB reached 0. If used in continuous we only need - * to react, otherwise we also should reload a latch value back. - * This counts at a rate of 715909/second for NTSC and - * 709379/second for PAL. - */ - facility_exechooks(_FACILITY_CIATIMB0, 0); - } - if (icrmask & CIA_ICR_SERDONE) { - /* Keyboard intput interrupt */ - u_int8_t c; - - c = CIA_A->SDR; - facility_exechooks(_FACILITY_KEYBOARD, (int)c); - } - } - _splx(x); -} - -void _icatch3(u_int16_t intreq) -{ - _ipl_t x; - - x = _spl3(); - if (intreq & INT_COPPER) { - /* Copper processor generated interrupt */ - facility_exechooks(_FACILITY_COPPER, 0); - } - if (intreq & INT_VBLANK) { - /* Vertical blank (raster) interrupt */ - facility_exechooks(_FACILITY_VBLANK, 0); - } - if (intreq & INT_BLITRDY) { - /* Blitter done/ready interrupt */ - facility_exechooks(_FACILITY_BLITTERREADY, 0); - } - _splx(x); -} - -/* ARGSUSED */ -void _icatch4(u_int16_t intreq) -{ - _ipl_t x; - - x = _spl4(); - if (intreq & INT_AUDIO0) { - /* DMA done for audio channel 0 interrupt */ - facility_exechooks(_FACILITY_AUDIO, 0); - } - if (intreq & INT_AUDIO1) { - /* DMA done for audio channel 1 interrupt */ - facility_exechooks(_FACILITY_AUDIO, 1); - } - if (intreq & INT_AUDIO2) { - /* DMA done for audio channel 2 interrupt */ - facility_exechooks(_FACILITY_AUDIO, 2); - } - if (intreq & INT_AUDIO3) { - /* DMA done for audio channel 3 interrupt */ - facility_exechooks(_FACILITY_AUDIO, 3); - } - _splx(x); -} - -/* ARGSUSED */ -void _icatch5(u_int16_t intreq) -{ - _ipl_t x; - - x = _spl5(); - if (intreq & INT_SERRBF) { - /* Serial RS-232 read buffer full interrupt */ - facility_exechooks(_FACILITY_SERIALRBF, 0); - } - if (intreq & INT_FLOPSYNC) { - /* Floppy disk sync pattern found interrupt */ - facility_exechooks(_FACILITY_FLOPPYSYNC, 0); - } - _splx(x); -} - -/* Level 6 handled by assembly code */ - - -/* And generic C trap handler to catch remaining trap vectors (0 and 1 are - * used by the system calls and _yield(), respectively. - */ -void _tcatch(int vector) -{ - _ipl_t x; - - x = _splhigh(); /* XXX */ - facility_exechooks(_FACILITY_TRAP, vector); - _splx(x); -} - - -/* A hack to display the exception vector number using raster lines */ -void _ecatch(int vector) -{ - static u_int16_t ecolors[2] = {0x0F00, 0x0A00}; - register bool col = FALSE; - - if (_rlock_try(&elock)) { - _splhigh(); - for (;;) { - register int i; - - for (i = 0; i < vector; i++) { - CUSTOM->COLOR[0] = ecolors[col]; - ldelay(2); - CUSTOM->COLOR[0] = 0x0000; - ldelay(2); - } - ldelay(8); - col = !col; - } - } - for (;;) - _idle(); -} - - - -/* Function we supply to Xisop which calls it to allow us to initialize - * our port-specific shared libraries and tasks. - */ -void _port_init(void) -{ - register task_t *task; - - if ((task = task_alloc(_task_color_server, NULL, NULL, 0, 4096, TF_KERNEL)) - != NULL) - task_start(task); - else - _panic(0x0F00); /* Red */ -} - - - -/* These are our port-specific tasks */ - -/* ARGSUSED */ -static int _task_color_server(void *res, void *args) -{ - port_t *port; - - /* Create our public port */ - if ((port = port_create("COLOR")) != NULL) { - struct taskarg targ[3]; - task_t *task; - hookid_t kbdhook; - - /* Setup an interrupt handler (only for fun) */ - kbdhook = hook_attach(_FACILITY_KEYBOARD, 10, 0, _keyboard_hook, NULL); - - /* Start our tasks. As these require our port to communicate through, - * note that we created it first. - */ - targ[0].color = 0x00F0; - targ[0].rounds = 6000; - if ((task = task_alloc(_task_color_client, NULL, &targ[0], 0, 4096, - TF_SHARED)) != NULL) - task_start(task); - targ[1].color = 0x00C0; - targ[1].rounds = 4000; - if ((task = task_alloc(_task_color_client, NULL, &targ[1], 0, 4096, - TF_SHARED)) != NULL) - task_start(task); - targ[2].color = 0x0090; - targ[2].rounds = 2000; - if ((task = task_alloc(_task_color_client, NULL, &targ[2], 0, 4096, - TF_SHARED)) != NULL) - task_start(task); - - /* Main loop. All we do is listen for requests via our port, in the - * form of messages. When we get one, display the requested color, - * and reply. This task should be in STATE_WAIT most of the time, - * and only awakens to answer requests then goes back to sleep. - */ - for (;;) { - port_t *ports[] = { - port - }; - register struct initmsg *msg = NULL; - - /* Black to show that we are sleeping */ - CUSTOM->COLOR[0] = 0x0000; - ldelay(1); - if ((port_wait(ports, 1, NULL)) == port) { - /* We could use while () here instead of if (), however this - * gives a better demonstration. When the screen eventually - * gets purple, all tasks are sleeping (init, reaper and - * this task, since our three children have died already). - * If we use while (), we never go in sleep mode, since there - * are several feeders and they are of equal priority than - * us. - */ - if ((msg = (struct initmsg *)port_get(port)) != NULL) { - CUSTOM->COLOR[0] = msg->color; - if (!port_reply((message_t *)msg)) - _panic(0x0F00); /* Red */ - } - } else - _panic(0x0FF0); /* Yellow */ - } - - port = port_destroy(port); - } - - _panic(0x0FFF); /* White */ - /* NOTREACHED */ - return 0; -} - - -/* ARGSUSED */ -static int _task_color_client(void *res, void *args) -{ - port_t *rport; - - /* Create our reply port */ - if ((rport = port_create(NULL)) != NULL) { - port_t *sport; - - /* Locate task_init()'s public port */ - if ((sport = port_find("COLOR")) != NULL) { - struct initmsg msg; - port_t *ports[] = { - rport - }; - struct taskarg *targ = args; - register u_int32_t rounds = targ->rounds; - - msg.color = targ->color; - /* Send coloring requests via the public COLOR port. - * For each request we wait for a reply, and then continue. - * This task runs most of the time, only sleeping when waiting - * for a result from the slave task. - */ - for (;rounds > 0; rounds--) { - if (port_send(sport, rport, (message_t *)&msg)) { - if ((port_wait(ports, 1, NULL)) == rport) { - /* Just get rid of messages since we don't need to - * verify a result code. - */ - port_flush(rport); - } else - _panic(0x0FF0); /* Yellow */ - } else - _panic(0x0F00); /* Red */ - } - } - - rport = port_destroy(rport); - } - - return 0; -} - - -/* Used in the case of a fatal error we catch */ -void _panic(u_int16_t color) -{ - sched_disable(); - sys_int_disable(); - for (;;) { - CUSTOM->COLOR[0] = color; - ldelay(2); - CUSTOM->COLOR[0] = 0x0000; - ldelay(2); - } - /* NOTREACHED */ -} - - -/* Mainly used as a test for now */ -/* ARGSUSED */ -static void _keyboard_hook(hookid_t hookid, int reason, void *udata) -{ - register u_int16_t col = 0; - - /* Just display a color corresponding to the keyboard code */ - col |= reason; col <<= 8; col |= reason; - CUSTOM->COLOR[0] = col; -} diff --git a/Xisop/src/ports/amiga/boot/make.sh b/Xisop/src/ports/amiga/boot/make.sh deleted file mode 100755 index 820e10d..0000000 --- a/Xisop/src/ports/amiga/boot/make.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.2 2004/01/20 20:56:20 mmondor Exp $ - -. ../../../makedefs.sh - -# Create tools -show $L_CC -Wall -o tools/aosbblock tools/aosbblock.c -show $L_CC -Wall -o tools/dumpkern tools/dumpkern.c -show $L_CC -Wall -o tools/config tools/config.c -KERNADDR=$(tools/config) - -# Create kernel image -show $C_COMPC -I$SRCDIR init.c -A=`$L_LS ../../../common/kernel/ar/*.a ../ar/*.a ../../../processor/ar/*.a ../../../common/kernlib/ar/*.a` -show $C_LD -nostdlib -e _start -Ttext $KERNADDR -o image.o init.o $A -show $C_LD -T image_script.ld -Ttext $KERNADDR -nostdlib -o image.bin init.o $A - -# Create bootblock loader -show $C_COMPS -I$SRCDIR -o bootf/bootf_s.o bootf/bootf_s.s -show $C_COMPC -I$SRCDIR -o bootf/bootf_c.o bootf/bootf_c.c -show $C_LD -nostdlib -r -Ttext 0x0020b660 -o bootf/bootf.o bootf/bootf_s.o bootf/bootf_c.o -show $C_LD -T bootf/bootf_script.ld -nostdlib -o bootf/bootf.bin bootf/bootf.o -show tools/aosbblock bootf/bootf.bin - -# Create bootable floppy image -show $L_CAT bootf/bootf.bin image.bin >bootf/kern.bin -show $L_DD if=/dev/zero of=xisop.adf bs=901120 count=1 -show tools/dumpkern xisop.adf bootf/kern.bin - -$L_ECHO === -$L_ECHO The floppy image should be $SRCDIR/ports/amiga/boot/xisop.adf -$L_ECHO === diff --git a/Xisop/src/ports/amiga/boot/tools/aosbblock.c b/Xisop/src/ports/amiga/boot/tools/aosbblock.c deleted file mode 100644 index 95cbeae..0000000 --- a/Xisop/src/ports/amiga/boot/tools/aosbblock.c +++ /dev/null @@ -1,107 +0,0 @@ -/* $Id: aosbblock.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Fixes a bootblock to be 1024 bytes in size, and sets it's AmigaOS checksum - */ - - - -#include -#include - - - -int main(int, char **); -u_int32_t checksum(u_int32_t *, int); - - - -int main(int argc, char **argv) -{ - FILE *fh; - u_int32_t lblock[256]; - int i; - char *block = (char *)lblock; - - if (argc == 2) { - - if ((fh = fopen(argv[1], "rb"))) { - /* First make sure to 0 pad block, then load block */ - for (i = 0; i < 256; i++) - lblock[i] = 0; - fread(block, 1, 1024, fh); - fclose(fh); - } else { - printf("could not open file \"%s\" for reading\n", argv[1]); - exit(-1); - } - - /* Calculate block checksum and fix it */ - lblock[1] = 0; - lblock[1] = htonl(0xFFFFFFFF - checksum(lblock, 256)); - - /* Write back file over old one */ - if ((fh = fopen(argv[1], "wb"))) { - fwrite(block, 1, 1024, fh); - fclose(fh); - } else { - printf("could not open file \"%s\" for writing\n", argv[1]); - exit(-1); - } - - } else { - printf("usage: aosbblock \n"); - exit(-1); - } - - exit(0); -} - - -u_int32_t checksum(u_int32_t *block, int size) -{ - u_int32_t sum, lastsum; - int i; - - for (sum = 0, i = 0; i < size; i++) { - lastsum = sum; - sum += ntohl(block[i]); - if (sum < lastsum) - ++sum; - } - - return sum; -} diff --git a/Xisop/src/ports/amiga/boot/tools/config.c b/Xisop/src/ports/amiga/boot/tools/config.c deleted file mode 100644 index 116feca..0000000 --- a/Xisop/src/ports/amiga/boot/tools/config.c +++ /dev/null @@ -1,64 +0,0 @@ -/* $Id: config.c,v 1.1 2004/01/20 20:56:20 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This program is useful to know the proper address to use in image_script.ld - * and make.sh for building the kernel image. - */ - - - -#include -#include "../config.h" - - - -int main(void); - - - -int main(void) -{ - printf("0x%08x\n", KERNADDR); - /* - printf("Supervisor stack location (0x%08x bytes): 0x%08x\n", - STACKSIZE, STACKADDR); - printf("Kernel image location (0x%08x bytes): 0x%08x\n", - KERNSIZE, KERNADDR); - printf("Usable multipurpose RAM: (0x%08x bytes) 0x%08x\n", - POOLSIZE, POOLADDR); - */ - - return 0; -} diff --git a/Xisop/src/ports/amiga/boot/tools/dumpkern.c b/Xisop/src/ports/amiga/boot/tools/dumpkern.c deleted file mode 100644 index b39abe0..0000000 --- a/Xisop/src/ports/amiga/boot/tools/dumpkern.c +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id: dumpkern.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Simple program to allow to dump a kernel image over an existing file - * (ususally to serve as a virtual floppy for bochs or to create - * floppy image files), without changing the size of the file. - */ - - - -#include -#include -#include -#include - - - -#define BUFSIZE 4096 - - - -int main(int, char **); - - - -int main(int argc, char **argv) -{ - if (argc == 3) { - int ffd, kfd; - - if ((ffd = open(argv[1], O_RDWR)) != -1) { - if ((kfd = open(argv[2], O_RDONLY)) != -1) { - char buf[BUFSIZE]; - size_t len; - - while ((len = read(kfd, buf, BUFSIZE)) > 0) - if ((write(ffd, buf, len)) != len) { - fprintf(stderr, "Error writing\n"); - break; - } - close(kfd); - } else fprintf(stderr, "Cannot open kernel file '%s'\n", argv[2]); - close(ffd); - } else fprintf(stderr, "Cannot open disk file '%s'\n", argv[1]); - } else fprintf(stderr, "Usage: dumpkern \n"); - - exit(0); -} diff --git a/Xisop/src/ports/amiga/clean.sh b/Xisop/src/ports/amiga/clean.sh deleted file mode 100755 index 7058be2..0000000 --- a/Xisop/src/ports/amiga/clean.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../generic_makedefs.sh - -show $L_RM support_s.o support_c.o ar/*.a diff --git a/Xisop/src/ports/amiga/make.sh b/Xisop/src/ports/amiga/make.sh deleted file mode 100755 index 9d58b03..0000000 --- a/Xisop/src/ports/amiga/make.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../makedefs.sh - -show $C_COMPS -I$SRCDIR support_s.s -show $C_COMPC -I$SRCDIR support_c.c -show $C_AR ar/support.a support_s.o support_c.o -show $C_RANLIB ar/support.a diff --git a/Xisop/src/ports/amiga/makedefs.sh b/Xisop/src/ports/amiga/makedefs.sh deleted file mode 100644 index b1eef0c..0000000 --- a/Xisop/src/ports/amiga/makedefs.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh - -# $Id: makedefs.sh,v 1.2 2003/12/27 00:01:55 mmondor Exp $ - -# These are various defaults which are used for the building process. -# Change as required, and don't forget to create the ./port and ./processor -# symbolic links to their respective directory. - -# Local non-cross building tools -L_AR='ar qS' -L_AS='as' -L_CC='gcc' -L_LD='ld' -L_NM='nm' -L_OBJDUMP='objdump' -L_RANLIB='ranlib' -L_STRIP='strip' -L_CAT='cat' -L_DD='dd' - -# Cross building tools (set to same values as L_* if wanted) -C_PREFIX='/usr/src/tools/bin' -C_AR="$C_PREFIX/m68k--netbsdelf-ar qS" -C_AS="$C_PREFIX/m68k--netbsdelf-as" -C_CC="$C_PREFIX/m68k--netbsdelf-gcc" -C_LD="$C_PREFIX/m68k--netbsdelf-ld" -C_NM="$C_PREFIX/m68k--netbsdelf-nm" -C_OBJDUMP="$C_PREFIX/m68k--netbsdelf-objdump" -C_RANLIB="$C_PREFIX/m68k--netbsdelf-ranlib" -C_STRIP="$C_PREFIX/m68k--netbsdelf-strip" - -# Other general purpose tools -L_RM='rm -f' -L_LN='ln -s' -L_SED='sed' -L_ECHO='echo' -L_LS='ls' - -# Command to compile a C module using the cross-compiler -#C_COMPC="$C_CC -Wall -ffreestanding -nostdinc -m68000 -O2 -fno-function-cse -fomit-frame-pointer -c" -C_COMPC="$C_CC -Wall -ffreestanding -nostdinc -m68000 -O2 -fno-function-cse -fomit-frame-pointer -c" -# And to compile an assembly module using the cross-assembler -C_COMPS="$C_CC -Wall -ffreestanding -nostdinc -m68000 -c" - -show() -{ - # Only output to stderr, not stdout - $L_ECHO "$@" >&2 - $@ -} - -# Useful to compile all .c and .s files in a directory to .o modules -# $1 = directory -buildlib() -{ - for i in `$L_LS $1/*.s 2>/dev/null`; do - DEST=`$L_ECHO $i | $L_SED 's/\.s/\.o/'` - show $C_COMPS -I$SRCDIR -o $DEST $i - done - for i in `$L_LS $1/*.c 2>/dev/null`; do - DEST=`$L_ECHO $i | $L_SED 's/\.c/\.o/'` - show $C_COMPC -I$SRCDIR -o $DEST $i - done -} - -# Deletes all .o files in a directory -# $1 = directory -cleanlib() -{ - show $L_RM $1/*.o -} diff --git a/Xisop/src/ports/amiga/support.h b/Xisop/src/ports/amiga/support.h deleted file mode 100644 index bdd609b..0000000 --- a/Xisop/src/ports/amiga/support.h +++ /dev/null @@ -1,467 +0,0 @@ -/* $Id: support.h,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This code was not derived from original AmigaOS headerfiles, but rather - * made comparing informations from various books I already had at home, - * such as "Mapping the Amiga", "La Bible de l'Amiga", and "Amiga Intern". - * - * Matt - */ - - - -#ifndef AMIGA_SUPPORT_H -#define AMIGA_SUPPORT_H - - - -#include - - - -/* Adapt this as required for NTSC or PAL Amigas */ - -/* CIA TimerA and TimerB count this amount of ticks per second */ -/* NTSC */ -/*#define CIA_COUNTSPEED 715909*/ -/* PAL */ -#define CIA_COUNTSPEED 709379 - - - -/* The Amiga has two CIA chips, each CIA supports two 8-bit parallel ports - * and one serial port. Each CIA chip also has two timers. Amiga also has - * various custom chips (Agnus, Denise, Paula, Ramsey, the copper parallel - * coprocessor)... - * - * The use of the CIA timers and counters is as follows: - * - CIA-A TOD counter available - * - CIA-A TimerA used for keyboard timing - * - CIA-A TimerB available - * - CIA-B TOD counter available - * - CIA-B TimerA available, we use it for the Xisop scheduler interrupt. - * - CIA-B TimerB available - * - * Xisop kernel itself may not need to use all those registers, however - * devices may, and will be able to use this same headerfile. - */ - -#define CIA_A ((volatile CIA *)0x00BFE001) -#define CIA_B ((volatile CIA *)0x00BFD000) -#define CUSTOM ((volatile CUST *)0x00DFF000) - - -/* Each of the two CIAs have this structure (8520 chip as mapped in Amiga) */ -typedef struct CIA { - volatile u_int8_t PRA; /* Parallel port register A */ - u_int8_t pad1[255]; - volatile u_int8_t PRB; /* Parallel port register B */ - u_int8_t pad2[255]; - volatile u_int8_t DDRA; /* Parallel port A data direction register */ - u_int8_t pad3[255]; - volatile u_int8_t DDRB; /* Parallel port B data direction register */ - u_int8_t pad4[255]; - volatile u_int8_t TALO; /* Timer A lower 8 bits */ - u_int8_t pad5[255]; - volatile u_int8_t TAHI; /* Timer A upper 8 bits */ - u_int8_t pad6[255]; - volatile u_int8_t TBLO; /* Timer B lower 8 bits */ - u_int8_t pad7[255]; - volatile u_int8_t TBHI; /* Timer B upper 8 bits */ - u_int8_t pad8[255]; - volatile u_int8_t E_LSB; /* Event counter bits 0-7 */ - u_int8_t pad9[255]; - volatile u_int8_t E_MID; /* Event counter bits 8-15 */ - u_int8_t pad10[255]; - volatile u_int8_t E_MSB; /* Event counter bits 16-23 */ - u_int8_t pad11[255 + 256]; - volatile u_int8_t SDR; /* Serial port data register */ - u_int8_t pad12[255]; - volatile u_int8_t ICR; /* Interrupt control register */ - u_int8_t pad13[255]; - volatile u_int8_t CRA; /* Control register A */ - u_int8_t pad14[255]; - volatile u_int8_t CRB; /* Control register B */ - u_int8_t pad15[255]; -} CIA; - -/* Here are defined common CIA register bits for code clarity */ -#define CIA_ICR_TIMA0 (1 << 0) -#define CIA_ICR_TIMB0 (1 << 1) -#define CIA_ICR_TODALRM (1 << 2) -#define CIA_ICR_SERDONE (1 << 3) -#define CIA_ICR_SIGFLAG (1 << 4) -#define CIA_ICR_CIAINT (1 << 7) -#define CIA_ICR_SETCLR (1 << 7) -#define CIA_ICR_CLRALL 0x7F - -#define CIA_CRA_START (1 << 0) -#define CIA_CRA_PBON (1 << 1) -#define CIA_CRA_OUTMODE (1 << 2) -#define CIA_CRA_RUNMODE (1 << 3) -#define CIA_CRA_LOAD (1 << 4) -#define CIA_CRA_INMODE (1 << 5) -#define CIA_CRA_SPMODE (1 << 6) - -#define CIA_CRB_START (1 << 0) -#define CIA_CRB_PBON (1 << 1) -#define CIA_CRB_OUTMODE (1 << 2) -#define CIA_CRB_RUNMODE (1 << 3) -#define CIA_CRB_LOAD (1 << 4) -#define CIA_CRB_INMODE (1 << 5 | 1 << 6) -#define CIA_CRB_ALARM (1 << 7) - -/* These are Amiga-specific and are different for each of the two CIAs */ -#define CIAA_PRA_MOVL (1 << 0) /* Memory overlay bit */ -#define CIAA_PRA_LED (1 << 1) /* Pwr LED & aud low pass filt stat */ -#define CIAA_PRA_FCHNG (1 << 2) /* Floppy disk change */ -#define CIAA_PRA_FRONLY (1 << 3) /* Floppy read-only */ -#define CIAA_PRA_FTRK0 (1 << 4) /* Floppy disk track 0 */ -#define CIAA_PRA_FRDY (1 << 5) /* Floppy disk ready for commands */ -#define CIAA_PRA_FIRE0 (1 << 6) /* Button 1 Port 1 pressed */ -#define CIAA_PRA_FIRE1 (1 << 7) /* Button 1 port 2 pressed */ - -#define CIAA_PRB_CDATA 0xFF /* Centronics data pins/bits */ - -#define CIAB_PRA_PBUSY (1 << 0) /* Centronics BUSY */ -#define CIAB_PRA_POUT (1 << 1) /* Centronics paper out */ -#define CIAB_PRA_PSEL (1 << 2) /* Centronics select */ -#define CIAB_PRA_SDSR (1 << 3) /* RS-232 Data Set Ready */ -#define CIAB_PRA_SCTS (1 << 4) /* RS-232 Clear To Send */ -#define CIAB_PRA_SDCD (1 << 5) /* RS-232 Carrier Detect */ -#define CIAB_PRA_SRTS (1 << 6) /* RS-232 Request To Send */ -#define CIAB_PRA_SDTR (1 << 7) /* RS-232 Data Terminal Ready */ - -#define CIAB_PRB_FHSTEP (1 << 0) /* Floppy head step */ -#define CIAB_PRB_FHDIR (1 << 1) /* Floppy head direction */ -#define CIAB_PRB_FSIDE (1 << 2) /* Floppy side */ -#define CIAB_PRB_FLOP0 (1 << 3) /* Select Floppy drive 0 */ -#define CIAB_PRB_FLOP1 (1 << 4) /* Select Floppy drive 1 */ -#define CIAB_PRB_FLOP2 (1 << 5) /* Select Floppy drive 2 */ -#define CIAB_PRB_FLOP3 (1 << 6) /* Select Floppy drive 3 */ -#define CIAB_PRB_FMOTOR (1 << 7) /* Floppy motor status */ - - -/* Useful union to represent 32-bit address split into two 16-bit registers */ -typedef union AADDR { - struct { - void *addr; /* Always 32-bit on m68k */ - } full; - struct { - u_int16_t addr_h; /* Bits 16-31 */ - u_int16_t addr_l; /* Bits 0-15 */ - } parial; -} AADDR; - -/* Each of the 4 native 8-bit Amiga channels are controled with this */ -typedef struct AUDCHAN { - AADDR AUDLC; /* Address of audio data */ - u_int16_t AUDLEN; /* Length of audio data */ - u_int16_t AUDPER; /* Period duration */ - u_int16_t AUDVOL; /* Channel volume */ - u_int16_t AUDDAT; /* Audio data (to D/A converter) */ - u_int16_t pad1[2]; /* Unused */ -} AUDCHAN; - -/* Sprite information */ -typedef struct SPR { - u_int16_t SPRPOS; /* Sprite start position (vert. and horiz.) */ - u_int16_t SPRCTL; /* Control register and vertical stop */ - u_int16_t SPRDATA; /* Data register A (to RGB output) */ - u_int16_t SPRDATB; /* Data register B (to RGB output) */ -} SPR; - - -/* And, the Amiga custom chips registers. */ -typedef struct CUST { - u_int16_t BLTDDAT; /* Blitter output data (Blitter to RAM) */ - u_int16_t DMACONR; /* Read DMA control register */ - u_int16_t VPOSR; /* MSB of vertical position */ - u_int16_t VHPOSR; /* Vertical and horizontal beam position */ - u_int16_t DSKDATR; /* Dist read data (disk to RAM) */ - u_int16_t JOY0DAT; /* Joystick/Mouse position game port 0 */ - u_int16_t JOY1DAT; /* Joystick/Mouse position game port 1 */ - u_int16_t CLXDAT; /* Collision register */ - u_int16_t ADKCONR; /* Read audio/disk control register */ - u_int16_t POT0DAT; /* Read potentiometer game port 0 */ - u_int16_t POT1DAT; /* Read potentiometer game port 1 */ - u_int16_t POTGOR; /* Read potentiometer port data */ - u_int16_t SERDATR; /* Read serial port and status */ - u_int16_t DSKBYTR; /* Read disk data byte and status */ - u_int16_t INTENAR; /* Read interrupt enable */ - u_int16_t INTREQR; /* Read interrupt request */ - AADDR DSKPTR; /* Disk DMA address */ - u_int16_t DSKLEN; /* Disk DMA block length */ - u_int16_t DSKDAT; /* Disk write data (RAM to disk) */ - u_int16_t REFPTR; /* Refresh counter */ - u_int16_t VPOSW; /* Write MSB of vertical beam position */ - u_int16_t VHPOSW; /* Write vertical and horizontal beam position */ - u_int16_t COPCON; /* Copper control register */ - u_int16_t SERDAT; /* Write serial data and stop bits */ - u_int16_t SERPER; /* Serial port control register and baud rate */ - u_int16_t POTGO; /* Write potentiometer port data and start bit */ - u_int16_t JOYTEST; /* Write in both mouse counters */ - u_int16_t STREQU; /* Horizontal sync with VBlank and equal frame */ - u_int16_t STRVBL; /* Horizontal sync wuth vertical blank */ - u_int16_t STRHOR; /* Horizontal synchronization signal */ - u_int16_t STRLONG; /* Long horizontal line marker */ - /* Following can also be accessed by the copper processor if COPCON=1 */ - u_int16_t BLTCON0; /* Blitter control register 0 */ - u_int16_t BLTCON1; /* Blitter control register 1 */ - u_int16_t BLTAFWM; /* Mask for first data word from A */ - u_int16_t BLTALWM; /* Mask for last data word from A */ - AADDR BLTCPTR; /* Address of source data C */ - AADDR BLTBPTR; /* Address of source data B */ - AADDR BLTAPTR; /* Address of source data A */ - AADDR BLTDPTR; /* Address of destination data D */ - u_int16_t BLTSIZE; /* Start bit and size of blitter window */ - u_int16_t BLTCON0L; /* Like BLTCON0, bits 0-7 */ - u_int16_t BLTSIZEV; /* Windth of blitter window */ - u_int16_t BLTSIZEH; /* Height of blitter window */ - u_int16_t BLTCMOD; /* Blitter modulo for source data C */ - u_int16_t BLTBMOD; /* Blitter modulo for source data B */ - u_int16_t BLTAMOD; /* Blitter modulo for source data A */ - u_int16_t BLTDMOD; /* Blitter modulo for destination data D */ - u_int16_t pad1[4]; /* Unused */ - u_int16_t BLTCDAT; /* Blitter source data register C */ - u_int16_t BLTBDAT; /* Blitter source data register B */ - u_int16_t BLTADAT; /* Blitter source data register A */ - u_int16_t pad2[3]; /* Unused */ - u_int16_t DENISEID; /* Chip identification from Denise */ - u_int16_t DSKSYNC; /* Disk sync pattern */ - /* The following registers can always be written to by the Copper */ - AADDR COP1LPTR; /* Address of first copper list */ - AADDR COP2LPTR; /* Address of second copper list */ - u_int16_t COPJMP1; /* Jump to start of first copper list */ - u_int16_t COPJMP2; /* Jump to start of second copper list */ - u_int16_t COPINS; /* Copper command register */ - u_int16_t DIWSTRT; /* Upper left corner of display window */ - u_int16_t DIWSTOP; /* Lower right corner of display window */ - u_int16_t DDFSTRT; /* Start of bitplane DMA (horiz. pos.) */ - u_int16_t DDFSTOP; /* End of bitplane DMA (horiz. pos.) */ - u_int16_t DMACON; /* Write DMA control register */ - u_int16_t CLXCON; /* Write collision control register */ - u_int16_t INTENA; /* Write interrupt enable */ - u_int16_t INTREQ; /* Write interrupt request */ - u_int16_t ADKCON; /* Audio, disk abd UART control register */ - AUDCHAN AUDCH[4]; /* Four digital audio channels */ - AADDR BPLPTR[6]; /* Six bitplane addresses */ - u_int16_t pad3[4]; /* Unused */ - u_int16_t BPLCON0; /* Bitplane control register 0 */ - u_int16_t BPLCON1; /* Bitplane control register 1 (scroll values) */ - u_int16_t BPLCON2; /* Bitplane control register 2 (priority control) */ - u_int16_t BPLCON3; /* Bitplane control register 3 */ - u_int16_t BPL1MOD; /* Bitplane modulo for uneven planes */ - u_int16_t BPL2MOD; /* Bitplane modulo for even planes */ - u_int16_t pad4[2]; /* Unused */ - u_int16_t BPLDAT[6];/* Bitplane data (to RGB output) */ - u_int16_t pad5[2]; /* Unused */ - AADDR SPRDATPTR[8]; /* Sprite data registers */ - SPR SPR[8]; /* Sprite control registers */ - u_int16_t COLOR[32];/* Color pallete registers (color table) */ - u_int16_t HTOTAL; /* Clock count per line (VARBEAM=1) */ - u_int16_t HSSTOP; /* H-sync stop position */ - u_int16_t HBSTRT; /* H-blank start position */ - u_int16_t HBSTOP; /* H-blank stop position */ - u_int16_t VTOTAL; /* Number of lines per picture */ - u_int16_t VSSTOP; /* V-sync stop line */ - u_int16_t VBSTRT; /* V-blank start line */ - u_int16_t VBSTOP; /* V-blank stop line */ - u_int16_t SPRHSTRT; /* UHRES sprite start line */ - u_int16_t SPRHSTOP; /* UHRES sprite stop line */ - u_int16_t BPLHSTRT; /* UHRES bitplane start line */ - u_int16_t BPLHSTOP; /* UHRES bitplane stop line */ - u_int16_t HHPOSW; /* Write DUAL-mode column counter */ - u_int16_t HHPOSR; /* Read DUAL-mode column counter */ - u_int16_t BEAMCON0; /* Raster beam control register */ - u_int16_t HSSTRT; /* H-sync start position */ - u_int16_t VSSTRT; /* V-sync start position */ - u_int16_t HCENTER; /* H-pos. of V-sync in interlace mode */ - u_int16_t DIWHIGH; /* Screen window, upper bits for start/stop */ - u_int16_t BPLHMOD; /* UHRES bitplane modulo */ - AADDR SPRHPTR; /* UHRES sprite pointer */ - AADDR BPLHPTR; /* UHRES bitplane pointer */ - u_int16_t pad6[7]; /* Unused */ -} CUST; - -/* And again some bits definitions for code clarity */ -#define DMACON_AUDIO0 (1 << 0) -#define DMACON_AUDIO1 (1 << 1) -#define DMACON_AUDIO2 (1 << 2) -#define DMACON_AUDIO3 (1 << 3) -#define DMACON_AUDIO (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3) -#define DMACON_FLOPPY (1 << 4) -#define DMACON_SPRITE (1 << 5) -#define DMACON_BLITTER (1 << 6) -#define DMACON_COPPER (1 << 7) -#define DMACON_BITPLANE (1 << 8) -#define DMACON_MASTER (1 << 9) -#define DMACON_PRIORITY (1 << 10) -#define DMACON_ZEROS (1 << 13) -#define DMACON_BLITTING (1 << 14) -#define DMACON_SETCLR (1 << 15) -#define DMACON_CLRALL 0x07FF - -#define ADKCON_0MODVOL1 (1 << 0) -#define ADKCON_1MODVOL2 (1 << 1) -#define ADKCON_2MODVOL3 (1 << 2) -#define ADKCON_3OFF (1 << 3) -#define ADKCON_0MODPER1 (1 << 4) -#define ADKCON_1MODPER2 (1 << 5) -#define ADKCON_2MODPER3 (1 << 6) -#define ADKCON_3OFF2 (1 << 7) -#define ADKCON_FLOP_GCR (1 << 8) -#define ADKCON_GCR_SYNC (1 << 9) -#define ADKCON_SYNC (1 << 10) -#define ADKCON_UARTBRK (1 << 11) -#define ADKCON_FLOP_MFM (1 << 12) -#define ADKCON_SETCLR (1 << 15) - -/* Most of these are shared by INTREQ, INTREQR, INTENA, INTENAR */ -#define INT_SERTBE (1 << 0) -#define INT_FLOPBLCK (1 << 1) -#define INT_SOFT (1 << 2) -#define INT_CIAA (1 << 3) -#define INT_COPPER (1 << 4) -#define INT_VBLANK (1 << 5) -#define INT_BLITRDY (1 << 6) -#define INT_AUDIO0 (1 << 7) -#define INT_AUDIO1 (1 << 8) -#define INT_AUDIO2 (1 << 9) -#define INT_AUDIO3 (1 << 10) -#define INT_AUDIO (1 << 7 | 1 << 8 | 1 << 9 | 1 << 10) -#define INT_SERRBF (1 << 11) -#define INT_FLOPSYNC (1 << 12) -#define INT_CIAB (1 << 13) -#define INT_LEVEL6 (1 << 14) /* INTREQR */ -#define INT_MASTER (1 << 14) /* INTENA */ -#define INT_SETCLR (1 << 15) /* INTENA & INTREQ */ -#define INTENA_CLRALL 0x3FFF -#define INTREQ_CLRALL 0x7FFF - - - - -/* Stuff we need to initialize before calling Xisop's main() */ - -/* -#define MEMF_CHIP 0x0001 -#define MEMF_FAST 0x0002 - -void *OpenLibrary(char *, long); -void CloseLibrary(void *); -long AvailMem(long); -void *AllocMem(long, long); -void *AllocAbs(long, void *); -void FreeMem(void *, long); -void Permit(void); -void Enable(void); -void *SuperState(void); -void UserState(void *); - -void jdelay(u_int32_t); -u_int32_t atime(void); -*/ -void ldelay(u_int32_t); - -void Alert(long, void *); -void Forbid(void); -void Disable(void); -void _supervisor(u_int32_t *, size_t, void (*)(void)); - -/* Set priority level */ -u_int16_t asplvblank(void); -u_int16_t asplsched(void); -/* Set priority level exit */ -void asplx(u_int16_t); - - - -/* Things we export for Xisop - * -------------------------- - */ - - -/* Memory management */ - -/* Our preferred page size. As Xisop does not support MMU, any size which is - * resonable and a multiple of 16 can be used. - */ -#define _PAGE_SIZE 4096 - -/* Definitions we need for mpool_t */ -#define _MPOOLS 7 -#define _MPOOLSTART 16 -#define _MPOOLSTEP 1 - -/* Memory types we setup */ -enum _memtypes { - _MEM_FAST = 0, - _MEM_CHIP, - _MEM_MAX -}; - -/* Scheduler timer rate */ -#define SCHEDTIMER_HZ 200 /* 4 times the vertical blank rate for now */ - -/* Interrupt facilities we provide */ -enum _facilities { - _FACILITY_SCHEDTIMER = 0, - _FACILITY_VBLANK, - _FACILITY_FLOPPYSYNC, - _FACILITY_FLOPPYBLOCK, - _FACILITY_SERIALRBF, - _FACILITY_SERIALTBE, - _FACILITY_AUDIO, - _FACILITY_BLITTERREADY, - _FACILITY_COPPER, - _FACILITY_CIATIMB0, - _FACILITY_KEYBOARD, - _FACILITY_TRAP, - _FACILITY_MAX -}; - - -/* Functions we provide */ -void _init_exceptions(void); -void _syscall(u_int32_t, void *, void *); -void _yield(void *); -void _port_init(void); -void _panic(u_int16_t); /* XXX */ - - - -#endif diff --git a/Xisop/src/ports/amiga/support_c.c b/Xisop/src/ports/amiga/support_c.c deleted file mode 100644 index 71aee29..0000000 --- a/Xisop/src/ports/amiga/support_c.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $Id: support_c.c,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include "support.h" - - - -/* These functions are similar to the _spl()/_splx() and spl()/splx() ones - * although they work directly with the Amiga hardware INTENA register, - * thus only disabling the specified interrupt (rather than setting a level). - * XXX Problem with this is that it's absolutely architecture-dependant. - * The general purpose spl() functions should be common to the various hardware - * Xisop supports. Hmm but the devices will be architecture dependant as well; - * unless kernel provides some basics to access some common things like - * RS-232 and console I/O. - */ - -u_int16_t asplvblank(void) -{ - u_int16_t old; - - old = CUSTOM->INTENAR; - CUSTOM->INTENA = INT_VBLANK; - - return old; -} - -/* Note: also prevents other CIA-B interrupts meanwhile */ -u_int16_t asplsched(void) -{ - u_int16_t old; - - old = CUSTOM->INTENAR; - CUSTOM->INTENA = INT_CIAB; - - return old; -} - -void asplx(u_int16_t old) -{ - CUSTOM->INTENA = old | INT_SETCLR; -} diff --git a/Xisop/src/ports/amiga/support_s.s b/Xisop/src/ports/amiga/support_s.s deleted file mode 100644 index 4f54c6e..0000000 --- a/Xisop/src/ports/amiga/support_s.s +++ /dev/null @@ -1,865 +0,0 @@ -/* $Id: support_s.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include "support.h" - - -| exec.library base -ExecBase = 0x0004 -| Various Amiga custom chips registers -VPOSR = 0x00DFF004 -VHPOSR = 0x00DFF006 -TODHI = 0x00BFEA01 -TODMID = 0x00BFE901 -TODLO = 0x00BFE801 -INTREQR = 0x00DFF01E -INTREQ = 0x00DFF09C -INTENAR = 0x00DFF01C -INTENA = 0x00DFF09A -COLOR0 = 0x00DFF180 -CIA_ICR = 0x00BFDD00 - - -.globl Alert, Forbid, Disable, AvailMem, AllocMem, AllocAbs, FreeMem -.globl _supervisor, _init_exceptions, _syscall, _yield -.globl jdelay, ldelay, atime - -.text - - -| AmigaOS minimal library. We include here the various functions which the -| kernel initialization may need. - - -| void [-108]Alert([d7]long alertNum,[a5]char *flags) -| -Alert: - moveml %d7/%a5-%a6, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d7 - moveal %sp@(20), %a5 - jsr %a6@(-108) - moveml %sp@+, %a6-%a5/%d7 - rts - - -| void [-132]Forbid(void) -| -Forbid: - movel %a6, %sp@- - moveal ExecBase:w, %a6 - jsr %a6@(-132) - moveal %sp@+, %a6 - rts - - -/* -| void [-120]Disable(void) -| -Disable: - movel %a6, %sp@- - moveal ExecBase:w, %a6 - jsr %a6@(-120) - moveal %sp@+, %a6 - rts - - -| [d0]long = [-216]Availmem([d1]long reqs) -| -AvailMem: - moveml %a6/%d1, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(12), %d1 - jsr %a6@(-216) - moveml %sp@+, %d1/%a6 - rts - - -| [d0]void * = [-198]AllocMem([d0]long bytes, [d1]long reqs) -| -AllocMem: - moveml %a6/%d0-%d1, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d0 - movel %sp@(20), %d1 - jsr %a6@(-198) - moveal %d0, %a0 - moveml %sp@+, %d1-%d0/%a6 - rts - - -| [d0]void * = [-204]AllocAbs([d0]long bytes, [a1]void *addr) -| -AllocAbs: - moveml %a1/%a6/%d0, %sp@- - moveal ExecBase:w, %a6 - movel %sp@(16), %d0 - moveal %sp@(20), %a1 - jsr %a6@(-204) - moveal %d0, %a0 - moveml %sp@+, %d0/%a6/%a1 - rts - - -| void [-210]FreeMem([a1]memptr, [d0]bytesize) -| -FreeMem: - moveml %a1/%a6/%d0, %sp@- - moveal ExecBase:w, %a6 - moveal %sp@(16), %a1 - movel %sp@(20), %d0 - jsr %a6@(-210) - moveml %sp@+, %d0/%a6/%a1 - rts -*/ - - -| void _supervisor(u_int32_t *sp, size_t sz, void (*func)(void)) -| Allows to gain m68k supervisor access, and sets up the supervisor stack -| pointer to the specified address. The supplied entry point function is -| then called. It is expected to never return, we thus don't need to worry -| about the registers we modify, except for A7/SSP. -| -_supervisor: - moveal %sp@(4), %a1 | SSP to set - movel %sp@(8), %d1 | Size to add - moveal %sp@(12), %a2 | Function to call - moveal ExecBase:w, %a6 - jsr %a6@(-150) | AmigaOS SuperState() exec.library call - moveal %a1, %a7 | Set SSP - addal %d1, %a7 | Jump to end of stack buffer - jsr %a2@ | Call famous function - rts | Should never be reached. - - -| void _init_exceptions(void) -| Called from C to initialize interrupts, traps and exception vectors -| -_init_exceptions: - clrl _interrupt_depth - bsrw trap_init - bsrw int_init - bsrw except_init - rts - - -| Other Amiga-specific assembler routines. The following deal with exceptions, -| traps and interrupts. - - -| void trap_init(void) -| Setup our 15 trap vectors -| -trap_init: - moveml %a0/%a1, %sp@- - moveal #0x80, %a0 - lea %pc@(trap_catch0), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch1), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch2), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch3), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch4), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch5), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch6), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch7), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch8), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch9), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch10), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch11), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch12), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch13), %a1 - movel %a1, %a0@+ - lea %pc@(trap_catch14), %a1 - movel %a1, %a0@ - moveml %sp@+, %a1/%a0 - rts - - -| And our trap handlers - -| This trap is special as it handles the backend for the _syscall() function -| which prototype is as follows: -| void _syscall(u_int32_t code, void *res, void *args) -| _syscall() just puts the arguments onto d0, a0 and a1 registers, and causes -| a trap 0. Our purpose is to copy those arguments on the supervisor -| stack, call _scatch(), free our arguments from the supervisor stack and -| return from the exception. The _syscall() caller will free it's own arguments -| from the user stack. -| -trap_catch0: - addql #1, _interrupt_depth - - | Backup registers on supervisor stack - | _syscall backed up d0 and a0-a1 as it modifies them to store the - | registers for us. - | - moveml %d0-%d7/%a0-%a6, %sp@- - - | Move registers which _syscall() setup for us into the stack and - | call void _scatch(u_int32_t, void *, void *). - | - movel %a1, %sp@- - movel %a0, %sp@- - movel %d0, %sp@- - bsrl _scatch - lea %sp@(12), %sp | faster than addl #12, %sp - - | Restore registers we backed up - | - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte - - -| This trap is also special in that it triggers an immediate context switch. -| Used to implement _yield(). It is implemented very similarly to the scheduler -| timer interrupt handler which forces task preemption. -| -trap_catch1: - addql #1, _interrupt_depth - - | First save SR and change it so that we be uninterruptible - | - movew %sr, %sp@- - movew #0x2700, %sr - - | Save current CPU context to root->curctx - | - movel %a0, %sp@- | Save A0 internally as we need it - movel %usp, %a0 - movel %a0, %sp@- | And USP - lea root, %a0 | Load root->curctx _ctx_t * - moveal %a0@(44), %a0 - lea %a0@(70), %a0 | Position now after struct's SR - - | Save SR, predecrementing. Normally stored at %sp@, but we saved - | 10 bytes in the stack, and are using %sp@(10). - movew %sp@(10), %a0@- - | Save PC from SS, which is normally stored at %sp@(2), but we saved - | 10 bytes in the stack, so are using %sp@(12). - movel %sp@(12), %a0@- | Save PC, from SS - moveml %a1-%a6/%d0-%d7, %a0@- | Save A6-A1, D7-D0 - movel %sp@+, %a0@- | Save USP/A7 from backup - movel %sp@+, %a0@- | Save A0 from backup - - | Now call schedule(), passing the supplied argument we were passed - | - movel _yieldparam, %sp@- - bsrl schedule - addql #4, %sp - - | Load context from root->curctx, which may have changed - | - lea root, %a0 | Load root->curctx _ctx_t * - moveal %a0@(44), %a0 - addql #4, %a0 | Skip A0 for now as we use it - movel %a0@+, %a1 - movel %a1, %usp | Restore USP/A7 - moveml %a0@+, %d7-%d0/%a6-%a1 | Restore D0-D7, A1-A6 - | Load PC from context and save in SP. Normally it would be %sp@(2) - | but there remains 2 bytes we saved in the stack and are using %sp@(4) - movel %a0@+, %sp@(4) | PC - | Restore SR, making sure that supervisor mode bit is set. Normally - | stored at %sp@, but we saved 2 bytes on the stack, so %sp@(2). - movew %a0@, %sp@(2) - moveal %a0@(-68), %a0 | Restore A0 - - | Restore normal SR - | - movew %sp@+, %sr - - | Return from exception, but to PC we loaded - | - subql #1, _interrupt_depth - rte - - -| These trap handlers consist of a backend for the C _tcatch() function. -| -trap_catch2: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 0 - braw 1f -trap_catch3: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 1 - braw 1f -trap_catch4: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 2 - braw 1f -trap_catch5: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 3 - braw 1f -trap_catch6: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 4 - braw 1f -trap_catch7: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 5 - braw 1f -trap_catch8: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 6 - braw 1f -trap_catch9: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 7 - braw 1f -trap_catch10: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 8 - braw 1f -trap_catch11: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 9 - braw 1f -trap_catch12: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 10 - braw 1f -trap_catch13: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 11 - braw 1f -trap_catch14: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 12 -1: - | Call our C function: void _tcatch(int); - | - bsrl _tcatch - addql #4, %sp - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte - - - -| C frontend to catch interrupts. Because of the way Amiga works with INTREQ -| it is important that they verify and reset their cause bits. This is easily -| done when dispatching all interrupt levels to a main single C function, with -| the interrupt level passed as an argument, and leave it do all the work. -| This is what was previously done here. However, leaving the C function do -| all the work implied wasting some CPU cycles. For instance, the level is -| already known via the handler being called, when we still let the C code -| perform that condition checking again. Moreover, INTREQ handling wasn't -| particularly optimized properly (using GCC 2.95.3 with m68k output). -| As some interrupt levels may be generated very frequently it is best to -| optimize this as much as possible. -| So we separated the handlers and let the assembler frontend handle INTREQ. -| For most interrupt handlers, We call a C function handler per interrupt -| level: -| void _icatch(u_int16_t intreqmask) -| where is obtained from INTREQR, and we make sure to reset -| the bits of the mask in INTREQ. It would also be possible to add some more -| assembly here if wanted to serve special interrupts faster, like RS-232 I/O. -| NOTE: GCC requires a 32-bit stack entry even for a 16-bit argument. - - -| void int_init(void) -| Setup our 6 interrupt vectors. Amiga does not use m68k interrupt level 7 -| and they are non-maskable (and hence are of no use to us anyways). -| -int_init: - moveml %a0-%a1, %sp@- - moveal #0x64, %a0 - lea %pc@(int_catch1), %a1 - movel %a1, %a0@+ - lea %pc@(int_catch2), %a1 - movel %a1, %a0@+ - lea %pc@(int_catch3), %a1 - movel %a1, %a0@+ - lea %pc@(int_catch4), %a1 - movel %a1, %a0@+ - lea %pc@(int_catch5), %a1 - movel %a1, %a0@+ - lea %pc@(int_catch6), %a1 - movel %a1, %a0@ - moveml %sp@+, %a1-%a0 - rts - - -| These handlers call the various C _icatch() functions -int_catch1: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - movew INTREQR, %sp@- - clrw %sp@- - bsrl _icatch1 - addql #4, %sp - movew #0x0007, INTREQ - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte -int_catch2: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - movew INTREQR, %sp@- - clrw %sp@- - bsrl _icatch2 - addql #4, %sp - movew #0x0008, INTREQ - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte -int_catch3: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - movew INTREQR, %sp@- - clrw %sp@- - bsrl _icatch3 - addql #4, %sp - movew #0x0070, INTREQ - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte -int_catch4: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - movew INTREQR, %sp@- - clrw %sp@- - bsrl _icatch4 - addql #4, %sp - movew #0x0780, INTREQ - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte -int_catch5: - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - movew INTREQR, %sp@- - clrw %sp@- - bsrl _icatch5 - addql #4, %sp - movew #0x1800, INTREQ - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte - - -| This interrupt handler is special as it also comports CIAB timer A interrupt, -| which is used by Xisop for the preeptive scheduler. We thus handle it -| especially, entirely in assembly. -| Unlike for other interrupt levels, we not just simply save and restore all -| registers. We store the current context into root->curctx, call schedule(), -| then load the context from root->curctx. -| This executes on the Supervisor Stack, and the User Stack Pointer as such -| is not modified except in context switches. -| -int_catch6: - addql #1, _interrupt_depth - - | Raise level to 7 - | - movew %sr, %sp@- - movew #0x2700, %sr - - | Save D0 as we need it - | - movel %d0, %sp@- - - | if (!(intreq & INT_CIAB)) goto 1 - | - movew INTREQR, %d0 - btst #13, %d0 - beqs 1f - - | if (icrmask & CIA_ICR_TIMA0) goto 2 - | - moveb CIA_ICR, %d0 - btst #0, %d0 - bnes 2f -1: - | Not the CIAB Timer A interrupt, Restore D0 and end - | - movel %sp@+, %d0 - braw 4f -2: - | Restore D0 and continue - | - movel %sp@+, %d0 - - | Tasks are expected to not run in supervisor mode. - | We have syscalls (including sys_call() one allowing to execute - | arbitrary code in supervisor mode), and public interrupt facilities - | (to which they can attach hooks) for them which should suffice. - | Moreover, system calls are uninterruptible by the scheduler when - | running. - - | Store current user context into root->curctx buffer - | - movel %a0, %sp@- | Save A0 internally as we need it - movel %usp, %a0 - movel %a0, %sp@- | And USP - lea root, %a0 | Load root->curctx _ctx_t * - moveal %a0@(44), %a0 - lea %a0@(70), %a0 | Position now after struct's SR - | Save SR, predecrementing. Normally stored at %sp@, but we saved - | 10 bytes in the stack, and are using %sp@(10). - movew %sp@(10), %a0@- - | Save PC from SS, which is normally stored at %sp@(2), but we saved - | 10 bytes in the stack, so are using %sp@(12). - movel %sp@(12), %a0@- | Save PC, from SS - moveml %a1-%a6/%d0-%d7, %a0@- | Save A6-A1, D7-D0 - movel %sp@+, %a0@- | Save USP/A7 from backup - movel %sp@+, %a0@- | Save A0 from backup - - | Execute _FACILITY_SCHEDTIMER hooks - | - clrl %sp@- - pea 0 | _FACILITY_SCHEDTIMER - bsrl facility_exechooks - addql #8, %sp - - | The following ensures to only perform a context switch if not - | currently executing a system call trap or other interrupt. The - | reason we need this is that the scheduler interrupt has a very - | high priority (6), which can actually interrupt most other - | exception handlers. - | - | if (_interrupt_depth != 1) goto 3 - | - cmpil #1, _interrupt_depth - bnes 3f - - | Call schedule(), which internally handles scheduling, and can - | modify root->curctx and root->curtask - | - pea 0 - bsrl schedule - addql #4, %sp - -3: - | Load back root->curctx into the current user CPU context - | - lea root, %a0 | Load root->curctx _ctx_t * - moveal %a0@(44), %a0 - addql #4, %a0 | Skip A0 for now as we use it - movel %a0@+, %a1 - movel %a1, %usp | Restore USP/A7 - moveml %a0@+, %d7-%d0/%a6-%a1 | Restore D0-D7, A1-A6 - | Load PC from context and save in SP. Normally it would be %sp@(2) - | but there remains 2 bytes we saved in the stack and are using %sp@(4) - movel %a0@+, %sp@(4) | PC - | Restore SR, making sure that supervisor mode bit is set. Normally - | stored at %sp@, but we saved 2 bytes on the stack, so %sp@(2). - movew %a0@, %sp@(2) - moveal %a0@(-68), %a0 | Restore A0 - -4: - | Exit point - | - | Reset INTREQ like for other levels interrupt handlers - | - movew #0x2000, INTREQ - - | Restore Interrupt Priority Level - | - movew %sp@+, %sr - - | Return using the %sp@(2) address from SS - | - subql #1, _interrupt_depth - rte - - - -| void except_init(void) -| Setup special exception handlers. -| -except_init: - moveml %a0-%a1, %sp@- - moveal #0x8, %a0 - lea %pc@(except_catch1), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch2), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch3), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch4), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch5), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch6), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch7), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch8), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch9), %a1 - movel %a1, %a0@+ - lea %pc@(except_catch10), %a1 - movel %a1, %a0@ - moveal #0x3c, %a0 - lea %pc@(except_catch11), %a1 - movel %a1, %a0@ - moveal #0x60, %a0 - lea %pc@(except_catch12), %a1 - movel %a1, %a0@ - moveal #0x7c, %a0 - lea %pc@(except_catch13), %a1 - movel %a1, %a0@ - moveml %sp@+, %a1-%a0 - rts - - -| Our exception handlers. Internally calling _ecatch() C function. -| -except_catch1: | Bus error - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 1 - braw 1f -except_catch2: | Address error - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 2 - braw 1f -except_catch3: | Illegal operation - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 3 - braw 1f -except_catch4: | Division by zero - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 4 - braw 1f -except_catch5: | CHK - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 5 - braw 1f -except_catch6: | TRAPV - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 6 - braw 1f -except_catch7: | Privilege violation - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 7 - braw 1f -except_catch8: | Trace - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 8 - braw 1f -except_catch9: | Line A Emu - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 9 - braw 1f -except_catch10: | Line F Emu - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 10 - braw 1f -except_catch11: | Uninitialized interrupt vector - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 11 - braw 1f -except_catch12: | Unjustified interrupt vector - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 12 - braw 1f -except_catch13: | NMI ? - addql #1, _interrupt_depth - moveml %d0-%d7/%a0-%a6, %sp@- - pea 13 -1: - | Call our C function: void _ecatch(int); - bsrl _ecatch - addql #4, %sp - moveml %sp@+, %a6-%a0/%d7-%d0 - subql #1, _interrupt_depth - rte - - - -| void _syscall(int function, void *res, void *args) -| C interface to Xisop syscalls. Because of the C prototype, the three -| arguments are already pushed unto the user stack before calling _syscall(). -| We thus place them into registers d0, a0 and a1, and cause a trap 0, -| which resumes execution at trap_catch0 in supervisor mode. -| -_syscall: - | Save registers we modify - moveml %d0/%a0-%a1, %sp@- - - | Prepare arguments - movel %sp@(16), %d0 - moveal %sp@(20), %a0 - moveal %sp@(24), %a1 - | Poof! Through the gate - trap #0 - - | Restore registers - moveml %sp@+, %a1-%a0/%d0 - rts - - -| void _yield(task_t *) -| Allows a task to immediately return control to the scheduler, allowing -| other tasks some CPU time immediately. The optional task_t pointer argument -| permits to suggest a task to run soon again to the scheduler, and should -| consist of another STATE_READY task. -| We use a special static buffer to hold this value because we do not want -| to taint the registers before the context gets saved. Moreover, if we tried -| to save and restore registers from the stack, we probably would be stealing -| bytes from the stack of another task which probably was preempted rather than -| interrupted using _yield() the last time. -| I tried pushing the argument on the stack and having the other side check -| it in via the User Stack Pointer, but it failed for some reason. -| -_yield: - | Use a static buffer since we're not supposed to modify any registers - | and that we can't save them on the stack since at return we won't - | have the same stack, obviously. - movel %sp@(4), _yieldparam - trap #1 - rts - - - -| These consist of various delay functions. These are not particularly -| useful in multitasking environments since they hug the CPU in loops, -| but are great for testing purposes. - - -/* -| void jdelay(long jiffies) -| Waits until completion of the current frame (vblank), 1/60th of a second -| for NTSC and 1/50th for PAL, by checking current hardware raster position. -| Not ideal as using an interrupt, but works. j stands for jiffy, a frame. -| -jdelay: - moveml %d0-%d1, %sp@- - movel %sp@(12), %d0 -1: - movel VPOSR, %d1 | Read both VPOSR and VHPOSR at once - andil #0x0001FF00, %d1 | Mask out the vertical beam position - bnes 1b - dbf %d0, 1b - moveml %sp@+, %d1-%d0 - rts -*/ - - -| void ldelay(long lines) -| Similar to the above function but waits approximately for the start of the -| next video raster line. -| -ldelay: - moveml %d0-%d1, %sp@- - movel %sp@(12), %d0 -1: movew VHPOSR, %d1 - andiw #0x000F, %d1 - bnes 1b - dbf %d0, 1b - moveml %sp@+, %d1-%d0 - rts - - -*/ -| Time related functions. - - -| u_int32_t atime(void) -| Obtains current time in 50/60Hz resolution, from CIA-A TOD counter -| -atime: - clrl %d0 - moveb TODHI, %d0 - lsll #4, %d0 - lsll #4, %d0 - moveb TODMID, %d0 - lsll #4, %d0 - lsll #4, %d0 - moveb TODLO, %d0 - rts -*/ - - -.data -.align 4 - -| This counter is used to count the depth of interrupts, so that the scheduler -| interrupt, which runs at a very high priority, only switches state if the -| depth is 1. All interrupt and trap handlers increase this variable at -| startup and decrease it at exit. -| -_interrupt_depth: - .long 0 - -| This consists of the parameter which is passed to _yield(), because we cannot -| save registers on the stack and expect the same values to be loaded back -| after causing trap #1, because obviously the context (and SP) may have -| changed. -| -_yieldparam: - .long 0 diff --git a/Xisop/src/processors/i386/make.sh b/Xisop/src/processors/i386/make.sh deleted file mode 100755 index 0772960..0000000 --- a/Xisop/src/processors/i386/make.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../makedefs.sh - -show $C_COMPS -I$SRCDIR support.s -show $C_COMPS udivsi3.s -show $C_COMPS mulsi3.s -show $C_AR ar/support.a support.o udivsi3.o mulsi3.o -show $C_RANLIB ar/support.a diff --git a/Xisop/src/processors/i386/support.h b/Xisop/src/processors/i386/support.h deleted file mode 100644 index 380c7ea..0000000 --- a/Xisop/src/processors/i386/support.h +++ /dev/null @@ -1,83 +0,0 @@ -/* $Id: support.h,v 1.3 2004/01/30 07:01:24 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef PROCESSOR_I386_H -#define PROCESSOR_I386_H - - - -#include - - - -#define _LITTLE_ENDIAN - -typedef struct _ctx { - void *esp, *ebp, *eip; /* eip == PC, esp = stack top */ - u_int32_t eax, ebx, ecx, edx; - u_int32_t esi, edi; - u_int32_t eflags; - u_int32_t es, fs, gs, ds; -} volatile _ctx_t; - -typedef volatile int32_t _lock_t; -typedef int32_t _rlock_t; - - - -void _lock_init(_lock_t *); -void _lock_acquire(_lock_t *); -void _lock_release(_lock_t *); -bool _lock_try(_lock_t *); -bool _lock_available(_lock_t *); - -void _rlock_init(_rlock_t *); -void _rlock_acquire(_rlock_t *); -void _rlock_release(_rlock_t *); -bool _rlock_try(_rlock_t *); -bool _rlock_available(_rlock_t *); - -u_int16_t _bswap16(u_int16_t); -u_int32_t _bswap32(u_int32_t); - -void _ctx_init(_ctx_t *, u_int32_t *, size_t, void *); - -void _idle(void); - - - -#endif diff --git a/Xisop/src/processors/i386/support.s b/Xisop/src/processors/i386/support.s deleted file mode 100644 index 34b4564..0000000 --- a/Xisop/src/processors/i386/support.s +++ /dev/null @@ -1,143 +0,0 @@ -/* $Id: support.s,v 1.4 2004/01/30 07:29:14 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -.globl _spl, _splx -.globl _lock_init, _lock_acquire, _lock_try, _lock_available, _lock_release -.globl _rlock_init, _rlock_acquire, _rlock_try, _rlock_release, _rlock_available -.globl _ctx_init -.globl setjmp, longjmp -.globl _idle -.globl _bswap16, _bswap32 - -.text - - -/* _spl_t _spl(_spl_t) _spl_t = ?XXX? -*/ -_spl: -/*XXX*/ - ret - - -_lock_init: - mov 0x4(%esp,1), %eax - movl $0x0, (%eax) - ret - -_lock_acquire: - mov 0x4(%esp,1), %edx - mov $0x1, %eax - lea 0x0(%esi), %esi -1: xchg %eax, (%edx) - test %eax, %eax - jne 1b - ret - -_lock_release: - mov 0x4(%esp,1), %eax - movl $0x0, (%eax) - ret - -_lock_try: - mov 0x4(%esp,1), %edx - mov $0x1, %eax - xchg %eax, (%edx) - test %eax, %eax - je 1f - xor %eax, %eax - ret -1: mov $0x1, %eax - ret - -_lock_available: - mov 0x4(%esp,1), %eax - cmpl $0x0, (%eax) - je 1f - xor %eax, %eax - ret -1: mov $0x1, %eax - ret - - -_rlock_init: - mov 0x4(%esp,1), %eax - movl $0x0, (%eax) - ret - -_rlock_acquire: - mov 0x4(%esp,1), %eax - incl (%eax) - ret - -_rlock_release: - mov 0x4(%esp,1), %eax - decl (%eax) - ret - -_rlock_try: - mov 0x4(%esp,1), %eax - incl (%eax) - cmpl $0x1, (%eax) - je 1f - decl (%eax) - xor %eax, %eax - ret -1: mov $0x1, %eax - ret - -_rlock_available: - mov 0x4(%esp,1), %eax - cmpl $0x0, (%eax) - je 1f - xor %eax, %eax - ret -1: mov $0x1, %eax - ret - - -_bswap16: - mov 0x4(%esp,1), %eax - ror $0x8, %ax - ret - -_bswap32: - mov 0x4(%esp,1), %eax - ror $0x8, %ax - ror $0x10, %eax - ror $0x8, %ax - ret - diff --git a/Xisop/src/processors/m68k/clean.sh b/Xisop/src/processors/m68k/clean.sh deleted file mode 100755 index 63982c8..0000000 --- a/Xisop/src/processors/m68k/clean.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# $Id: clean.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../generic_makedefs.sh - -cleanlib math -show $L_RM support.o ar/support.a diff --git a/Xisop/src/processors/m68k/make.sh b/Xisop/src/processors/m68k/make.sh deleted file mode 100755 index 20a99e2..0000000 --- a/Xisop/src/processors/m68k/make.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# $Id: make.sh,v 1.1 2003/10/26 21:19:57 mmondor Exp $ - -. ../../makedefs.sh - -show $C_COMPS -I$SRCDIR support.s -buildlib math -show $C_AR ar/support.a support.o math/*.o -show $C_RANLIB ar/support.a diff --git a/Xisop/src/processors/m68k/math/README b/Xisop/src/processors/m68k/math/README deleted file mode 100644 index 74461b6..0000000 --- a/Xisop/src/processors/m68k/math/README +++ /dev/null @@ -1,3 +0,0 @@ -Some math functions are required by GCC m68k compiled code. Those were obtained -from the NetBSD kernel m68k library and adapted. Their BSD license file headers -were unchanged, however. diff --git a/Xisop/src/processors/m68k/math/divsi3.s b/Xisop/src/processors/m68k/math/divsi3.s deleted file mode 100644 index 8c8aa40..0000000 --- a/Xisop/src/processors/m68k/math/divsi3.s +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id: divsi3.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matthew Fredette. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - - -.globl __divsi3 - - - -| NB: this requires that __udivsi3 preserve %a0: -__divsi3: - movel %sp@(4), %d1 | load the dividend - bpls 1f - negl %sp@(4) | store abs(dividend) -1: movel %sp@(8), %d0 | load the divisor - bpls 2f - negl %sp@(8) | store abs(divisor) -2: eorl %d1, %d0 - bpls 3f | branch if sgn(divisor) == sgn(dividend) - moveal %sp@+, %a0 | pop return address - pea %pc@(Lret) | push our return address -3: jmp __udivsi3 -Lret: negl %d0 | negate quotient - jmp %a0@ diff --git a/Xisop/src/processors/m68k/math/modsi3.s b/Xisop/src/processors/m68k/math/modsi3.s deleted file mode 100644 index b042612..0000000 --- a/Xisop/src/processors/m68k/math/modsi3.s +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: modsi3.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matthew Fredette. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - - -.globl __modsi3 - - - -| NB: this requires that __udivsi3 preserve %a0 and return -| the modulus in %d1: -__modsi3: - moveal %sp@+, %a0 | pop return address - movel %sp@(4), %d1 | load the divisor - bpls 1f - negl %sp@(4) | store abs(divisor) -1: movel %sp@, %d0 | load the dividend - pea %pc@(Lret) | push our return address - bpls 2f - negl %sp@(4) | store abs(dividend) - subql #2, %sp@ | adjust return address -2: jmp __udivsi3 - negl %d1 | negate modulus -Lret: movel %d1, %d0 | move modulus into %d0 - jmp %a0@ diff --git a/Xisop/src/processors/m68k/math/mulsi3.s b/Xisop/src/processors/m68k/math/mulsi3.s deleted file mode 100644 index a4cb7c8..0000000 --- a/Xisop/src/processors/m68k/math/mulsi3.s +++ /dev/null @@ -1,55 +0,0 @@ -/* $Id: mulsi3.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matthew Fredette. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -.globl __mulsi3 - -__mulsi3: - movew %sp@(6), %d0 - moveal %d0, %a0 | save B - muluw %sp@(8), %d0 | %d0 holds B * C - movew %sp@(10), %d1 - moveal %d1, %a1 | save D - muluw %sp@(4), %d1 | %d1 holds A * D - addw %d1, %d0 | %d0 holds (B * C) + (A * D) - swap %d0 - clrw %d0 | %d0 holds ((B * C) + (A * D)) << 16 - exg %a0, %d0 | restore B - movel %a1, %d1 | restore D - muluw %d1, %d0 | %d0 holds B * D - addl %a0, %d0 | final result - rts diff --git a/Xisop/src/processors/m68k/math/udivsi3.s b/Xisop/src/processors/m68k/math/udivsi3.s deleted file mode 100644 index 3c3d1da..0000000 --- a/Xisop/src/processors/m68k/math/udivsi3.s +++ /dev/null @@ -1,114 +0,0 @@ -/* $Id: udivsi3.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matthew Fredette. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -.globl __udivsi3 - -__udivsi3: - movel %d2, %sp@- | save %d2 - movel %sp@(12), %d0 | load divisor - movel %sp@(8), %d1 | load dividend - -| first, we divide the divisor and dividend by two until -| the divisor fits into 16 bits: -1: cmpil #0x10000, %d0 - bcss 2f - lsrl #1, %d0 - lsrl #1, %d1 - bras 1b -2: - -| now we can do the divide. to avoid overflow, we have to -| do the divide in two parts, high and low, and add the -| results together: - movew %d1, %d2 | save low(dividend) - clrw %d1 - swap %d1 | %d1 = dividend >> 16 - divuw %d0, %d1 | do the high divide - moveal %d1, %a1 | save high divide result - movew %d2, %d1 | concat(remainder, low(dividend)) - divuw %d0, %d1 | do the low divide - movel %a1, %d0 | recover high divide result - swap %d0 - clrw %d0 | %d0 = finished high divide result - andil #0xffff, %d1 | %d1 = finished low divide result - addl %d1, %d0 | %d0 = quotient guess - -| the quotient we have so far is only a guess. the divide we -| did above was really the divide of some dividendB by some -| divisorB, where the following hold: -| -| (dividend - divisor) <= dividendB <= dividend -| (divisor / 2) < divisorB <= divisor -| -| so our guess quotient cannot be less than our real desired -| quotient. however, it might be one too big. -| -| to adjust this quotient, we multiply it by the original -| divisor and subtract the result from the original dividend. -| if the result is nonnegative, our guessed quotient was -| correct, and the subtraction result is our remainder. -| if the result is negative, our guessed quotient was one -| too big, and the subtraction result plus the original -| divisor is our remainder. -| -| as in mulsi3, we have to do the multiply in stages to avoid -| overflow: - - movel %sp@(12), %d2 | load divisor - swap %d2 - movel %d0, %d1 - muluw %d2, %d1 | high(divisor) * low(guess) - moveal %d1, %a1 | save high(divisor) * low(guess) - swap %d2 - movel %d0, %d1 - swap %d1 - muluw %d2, %d1 | low(divisor) * high(guess) - addl %a1, %d1 - swap %d1 - clrw %d1 | %d1 = finished high multiply result - moveal %d2, %a1 | save original divisor - muluw %d0, %d2 | low(guess) * low(divisor) - addl %d1, %d2 | %d2 = guess * divisor - - movel %sp@(8), %d1 | load original dividend - subl %d2, %d1 | subtract - bccs 3f - subql #1, %d0 | adjust quotient - addl %a1, %d1 | adjust remainder -3: movel %sp@+, %d2 | restore %d2 - rts diff --git a/Xisop/src/processors/m68k/math/umodsi3.s b/Xisop/src/processors/m68k/math/umodsi3.s deleted file mode 100644 index 37898cf..0000000 --- a/Xisop/src/processors/m68k/math/umodsi3.s +++ /dev/null @@ -1,51 +0,0 @@ -/* $Id: umodsi3.s,v 1.1 2003/10/26 21:19:57 mmondor Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matthew Fredette. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - - -.globl __umodsi3 - - - -| NB: this requires that __udivsi3 preserve the %a0 -| register, and that it returns the modulus in %d1: -__umodsi3: - moveal %sp@+, %a0 | pop the return address - jsr __udivsi3 - movel %d1, %d0 | move the modulus into %d0 - jmp %a0@ | return diff --git a/Xisop/src/processors/m68k/support.h b/Xisop/src/processors/m68k/support.h deleted file mode 100644 index 4afe2a3..0000000 --- a/Xisop/src/processors/m68k/support.h +++ /dev/null @@ -1,138 +0,0 @@ -/* $Id: support.h,v 1.6 2004/06/03 05:44:05 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Derived from informations from the "Mise en oeuvre du 68000" book. - * The spl name was inspired from NetBSD SPL(9) man page. The code for - * these is in support.s - */ - - - -#ifndef PROCESSOR_M68K_H -#define PROCESSOR_M68K_H - - - -#include - - - -/* Definitions for optimizations and network byte order support */ -#define _ARCH_BIG_ENDIAN -#define _ARCH_INT_BITS 32 -/*#define _ARCH_LOWCACHE*/ -/*#define _ARCH_USEINDEXING*/ - - - -/* Abstract datatypes we must provide */ - -/* A CPU context which can also hold the state of user tasks. - * Also used as buffer area for setjmp()/longjmp() functions. - * Note that USP (User Stack Pointer) is actually SP/A7, as seen - * from supervisor code, which SP/A7 stack is set to SSP (Supervisor - * Stack Pointer). This means that from supervisor code the special - * usp related instructions must be used to manipulate the current - * user stack pointer, but that from userspace this simply is sp which - * can be manipulated without supervisor access (like in setjmp()/longjmp()). - */ -typedef struct _ctx { - void *a0, *usp; - u_int32_t d0, d1, d2, d3, d4, d5, d6, d7; - void *a1, *a2, *a3, *a4, *a5, *a6; - void *pc; - u_int16_t sr; - u_int16_t padding; -} volatile _ctx_t; - -/* A simple lock */ -typedef volatile u_int8_t _lock_t; -/* A recursive lock */ -typedef int32_t _rlock_t; - -/* An interrupt priority level context */ -typedef u_int16_t _ipl_t; - - - -/* Set interrupt level control functions */ -_ipl_t _spl(u_int16_t); -#define _spl0() _spl(0x2000) -#define _spl1() _spl(0x2100) -#define _spl2() _spl(0x2200) -#define _spl3() _spl(0x2300) -#define _spl4() _spl(0x2400) -#define _spl5() _spl(0x2500) -#define _spl6() _spl(0x2600) -#define _spl7() _spl(0x2700) -#define _splhigh() _spl(0x2700) -void _splx(_ipl_t); - -/* Atomic locking functions. These are SMP safe. */ -void _lock_init(_lock_t *); -void _lock_acquire(_lock_t *); -void _lock_release(_lock_t *); -bool _lock_try(_lock_t *); -bool _lock_available(_lock_t *); - -/* Atomic recursive locking functions. The same number of release operations - * must be performed for the lock to become available again, and there can - * be any number of concurrent lockers. - */ -void _rlock_init(_rlock_t *); -void _rlock_acquire(_rlock_t *); -void _rlock_release(_rlock_t *); -bool _rlock_try(_rlock_t *); -bool _rlock_available(_rlock_t *); - -/* Efficient byte order conversion functions */ -u_int16_t _bswap16(u_int16_t); -u_int32_t _bswap32(u_int32_t); - -/* Function to create a new CPU context for a task */ -void _ctx_init(_ctx_t *, u_int32_t *, size_t, void *); - -/* Function to put the CPU in idle mode until next interrupt occurs. - * Restricted to supervisor mode. - */ -void _idle(void); - -/* Useful to call Xisop main() from port-specific initialization code */ -void _usermode(int (*)(void)); - - - -#endif diff --git a/Xisop/src/processors/m68k/support.s b/Xisop/src/processors/m68k/support.s deleted file mode 100644 index 990d9a0..0000000 --- a/Xisop/src/processors/m68k/support.s +++ /dev/null @@ -1,321 +0,0 @@ -/* $Id: support.s,v 1.4 2004/01/30 07:08:57 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -.globl _spl, _splx -.globl _lock_init, _lock_acquire, _lock_try, _lock_available, _lock_release -.globl _rlock_init, _rlock_acquire, _rlock_try, _rlock_release, _rlock_available -.globl _bswap16, _bswap32 -.globl _ctx_init -.globl setjmp, longjmp -.globl _idle, _usermode - -.text - - -| _spl_t _spl(_spl_t) _spl_t == u_int16_t -| -_spl: movew %sr, %d0 - movew %sp@(6), %sr - rts - - -| void _splx(_spl_t oldstate) -| -_splx: movew %sp@(6), %sr - rts - - -| void _lock_init(_lock_t *lock) _lock_t == u_int8_t -| Used to create/init new locks -| -_lock_init: - movel %a0, %sp@- - moveal %sp@(8), %a0 - clrb %a0@ - moveal %sp@+, %a0 - rts - - -| void _lock_acquire(_lock_t *lock) -| Blocks current CPU in a loop until lock is obtained -| -_lock_acquire: - movel %a0, %sp@- - moveal %sp@(8), %a0 -1: tas %a0@ - bnes 1b - moveal %sp@+, %a0 - rts - - -| bool _lock_try(_lock_t *lock) -| Attempts to obtain lock, but returns immediately with TRUE/FALSE result -| -_lock_try: - movel %a0, %sp@- - moveal %sp@(8), %a0 - tas %a0@ - beqs 1f - clrl %d0 - moveal %sp@+, %a0 - rts -1: - moveq #1, %d0 - moveal %sp@+, %a0 - rts - - -| bool _lock_available(_lock_t *lock) -| Returns 1/TRUE if the lock is currently free, or 0/FALSE if it is locked. -| Note that this should not be used to attempt to obtain the lock using two -| steps (see _lock_try() above for this). It is useful to simply know if -| it is locked, nothing else. Useful for the scheduler on/off switch. -| -_lock_available: - movel %a0, %sp@- - moveal %sp@(8), %a0 - btst #7, %a0@ - bnes 1f - moveq #1, %d0 - moveal %sp@+, %a0 - rts -1: - clrl %d0 - moveal %sp@+, %a0 - rts - - -| void _lock_release(_lock_t *lock) -| Releases a previously acquired lock -| -_lock_release: - movel %a0, %sp@- - moveal %sp@(8), %a0 - clrb %a0@ - moveal %sp@+, %a0 - rts - - -| void _rlock_init(_rlock_t *rlock) _rlock_t = int32_t -| Initializes a recursive lock -| -_rlock_init: - movel %a0, %sp@- - moveal %sp@(8), %a0 - clrl %a0@ - moveal %sp@+, %a0 - rts - - -| void _rlock_acquire(_rlock_t *rlock) -| Acquires the lock, recursively -| -_rlock_acquire: - movel %a0, %sp@- - moveal %sp@(8), %a0 - addql #1, %a0@ - moveal %sp@+, %a0 - rts - - -| void _rlock_release(_rlock_t *rlock) -| Releases the lock. _rlock_acquire() and _rlock_release() instances must pair -| for the lock to eventually be available again. -| -_rlock_release: - movel %a0, %sp@- - moveal %sp@(8), %a0 - subql #1, %a0@ - moveal %sp@+, %a0 - rts - - -| bool _rlock_try(_rlock_t *rlock) -| Atomically acquires the lock like _rlock_acquire(), but returns TRUE if -| we then are the only locker. Otherwise, releases the lock back and return -| FALSE. Obviously, if we are the only locker, the _rlock_t counter will be -| one (1). This allows to perform an atomic -| _rlock_available() + _rlock_acquire() pair. -| -_rlock_try: - movel %a0, %sp@- - moveal %sp@(8), %a0 - moveq #1, %d0 - addql #1, %a0@ - cmpl %a0@, %d0 - beqs 1f - subql #1, %a0@ - clrl %d0 -1: moveal %sp@+, %a0 - rts - - -| bool _rlock_available(_rlock_t *rlock) -| Returns TRUE if the lock is available, or if FALSE if there are any lockers. -| -_rlock_available: - movel %a0, %sp@- - moveal %sp@(8), %a0 - clrl %d0 - cmpl %a0@, %d0 - bnes 1f - moveq #1, %d0 -1: moveal %sp@+, %a0 - rts - - -| u_int16_t _bswap16(u_int16_t) -| Swaps the order of the two bytes held in the supplied 16-bit word -| -_bswap16: - movew %sp@(6), %d0 - rorw #8, %d0 - rts - - -| u_int32_t _bswap32(u_int32_t) -| Reverses the order of the four bytes held in the supplied 32-bit word -| First cause a 16-bit byte swap, then perform a 16-bit word swap within the -| 32-bit word, and then perform another 16-bit byte swap. -| -_bswap32: - movel %sp@(4), %d0 - rorw #8, %d0 - swap %d0 - rorw #8, %d0 - rts - - -| void _ctx_init(_ctx_t *, u_int32_t *sp, size_t sz, void *pc) -| Creates a new CPU context which will use specified SP and PC pointers. -| Note that SP must be pointing at end of stack area, as it grows upwards. -| -_ctx_init: - moveml %a0/%d0, %sp@- | Save a0/d0 - moveal %sp@(12), %a0 | _ctx_t * - clrl %a0@+ | A0 - movel %sp@(16), %a0@ | A7/USP u_int32_t * - movel %sp@(20), %d0 | size_t - addl %d0, %a0@+ | A7/USP - clrl %a0@+ | D0 - clrl %a0@+ | D1 - clrl %a0@+ | D2 - clrl %a0@+ | D3 - clrl %a0@+ | D4 - clrl %a0@+ | D5 - clrl %a0@+ | D6 - clrl %a0@+ | D7 - clrl %a0@+ | A1 - clrl %a0@+ | A2 - clrl %a0@+ | A3 - clrl %a0@+ | A4 - clrl %a0@+ | A5 - clrl %a0@+ | A6 - movel %sp@(24), %a0@+ | PC void * - clrl %a0@ | SR + padding -| clrw %a0@+ | SR -| clrw %a0@ | 16-bit 32-bit padding - moveml %sp@+, %d0/%a0 | Restore d0/a0 - rts - - -| int setjmp(jmp_buf); -| We can manipulate SP/USP/A7 from user state without problems. We do not need -| to manipulate SR. We can safely run in usermode. -| The supplied jmp_buf is actually a pointer to a _ctx_t. We must return 0 -| normally, but must return the value supplied to longjmp() when it is called. -| To do this, we zero D0, save context to jmp_buf, and return. longjmp() will -| load that context back and set D0 to the wanted value before returning. -| -setjmp: - movel %a0, %sp@- | Save A0 (4 bytes) to current stack - moveal %sp@(8), %a0 | Pointer to _ctx_t - clrl %d0 | Default return value to 0 - lea %a0@(66), %a0 | Pos now after pc - movel %sp@(6), %a0@- | PC norm at %sp@(2), we saved 4 bytes - moveml %a1-%a6/%d0-%d7, %a0@- | Save A6-A1, D7-D0 - movel %sp, %a0@ | Save A7/USP (without saved 4 bytes) - addql #4, %a0@- - movel %sp@+, %a0@- | Restore A0 and save it - rts - - -| void longjmp(jmp_buf, int) -| No need to save registers since we are loading the supplied state. -| We technically never return, we however make sure to load D0 (which -| will become setjmp() return value) with the supplied value argument. -| -longjmp: - moveal %sp@(4), %a0 | _ctx_t pointer - movel %sp@(8), %d0 | Return value for setjmp() - addql #4, %a0 | Now at usp - moveal %a0@+, %sp | Restore context stack pointer - addql #4, %a0 | Now at d1 - moveml %a0@+, %d7-%d1/%a6-%a1 | Load registers from context - movel %a0@, %sp@(2) | Restore return PC - moveal %a0@(-68), %a0 | Restore A0 - rts | Resume at setjmp() saved PC - - -| void _idle(void) -| Puts CPU in sleep mode until next interrupt occurs. Useful to not use 100% -| CPU time and overheat when all tasks are idle. Also saves alot of power -| on battery powered systems. Restricted to supervisor mode. -| -_idle: - movew %sr, %sp@- - stop #0x2000 - movew %sp@+, %sr - rts - - -| void _usermode(int (*)(void)); -| Useful for port-specific init code to call Xisop main() -| Permits to switch from supervisor mode to usermode and jump to the specified -| function. The current supervisor stack is used to setup the user stack (US). -| The user stack we create is 1024 bytes. Obviously, the SS should have enough -| room for this. The function we jump to is expected to only perform minor -| initialization, like to start the first Xisop task, with it's own stack. -| Used to call Xisop's main() function from init.c -| -_usermode: - moveal %sp@(4), %a0 | Address to jump to - movel %sp, %a1 - lea %sp@(-1024), %sp - movel %a1, %usp - andiw #0xdfff, %sr | Switch to usermode - jmp %a0@ diff --git a/site/contributors.html b/site/contributors.html deleted file mode 100644 index 42b5895..0000000 --- a/site/contributors.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -Matthew Mondor's Software Site - Contributors - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-MMSoftware Contributors
-
- -

-These contributors generally consist of various mmsoftware users across the -globe who are developing related third-party software, to add features such as -frontends and configuration tools. They are free to release their software -under their prefered licenses and conditions. The contributors maintain -their own software themselves, so bug reports or suggestions should be sent -directly to them. The content of their section become their own responsibility. -To obtain sources for the official mmsoftware releases please visit the -software area. -

-I personally thank the contributors for their interest in my projects. -

- - - - - - -
-Jeroen Oostendorp -
-Daniel DeMaggio -
-Alexander Schlett -
-Jonas Koch Bentzen -
-Vahram Igityan -
-
-
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: contributors.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/cvs.html b/site/cvs.html deleted file mode 100644 index d5f219a..0000000 --- a/site/cvs.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - -Matthew Mondor's Software Site - CVS - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-MMSoftware CVS Repository
-
- -

-Note that the CVS repository contains the latest actual development tree -and should not be used by the general public, it is mostly intended for -developpers, maintainers and beta-testers. There also can be found some -software which never have previously been released in the form of an archive. -

-The HTTP cvsweb interface to the CVS repository is no longer available at -present time. However, read-only public CVS pserver access is provided. -I highly suggest getting aquainted with the command-line cvs(1) utility -for best results. -

-Those who want to access the repository via public pserver to access all -of my BSD-style licensed open source software can use the following command: -

-% cvs -z6 -d:pserver:anoncvs@cvs.accela.net:/cvsroot co mmondor -

-To only obtain the Xisop kernel, mmondor/Xisop may be used as the -module name. To only retreive the mmsoftware directory, -mmondor/mmsoftware will be used.

-The service is provided using the cvs(1), mmspawnd(8) and mmanoncvs(8) -utilities as an alternative to the common setup using inetd(8). This -ensures a secure public pserver setup which cannot affect the original -repositories or the rest of the system if exploited. - -

-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: cvs.html,v 1.7 2003/12/10 20:33:58 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/donations.html b/site/donations.html deleted file mode 100644 index d57d2f1..0000000 --- a/site/donations.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - -Matthew Mondor's Software Site - Donations - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-Donations to support MMSoftware
-
- -

-Free opensource software projects need the support of their users to evolve. -Programmers spend alot of time trying to make the code efficient, bug-free, -and user-friendly. In an area where security is a primary concern, like for -public internet services, the time required to roll safe code is often higher -than it would be for some other projects. There are design, coding, testing, -debugging, and auditing sessions. And at times even restructuring when -required to allow the software to be more manageable for the forthcoming new -features it should integrate. -

-There are many ways one can use to support the project. One is to help it -maintain public exposure by providing hosting and bandwidth for a mirror. -This obviously only should be done on stable connections, it can then become -useful for people to find a mirror closer to their location, and so that at -all times at least one mirror remains up if others are ever temporarily down. -The mmondor.gobot.ca DNS pool of addresses can then be updated once a day, -verifying the availability and stability of the mirrors. An FTP account or -other method can be used to mirror the site regularly. -

-Another way is to audit the software against potential security, portability -issues and bugs, as well as test the software. Beta testers are welcome to -track the CVS repository tree and to propose diff/patches whenever necessary. -Also considered a donation is the time other programmers can put in -contributing third party software related to the projects. Although this may -not necessarily affect mmsoftware directly, some of that software may be very -useful for many mmsoftware users. -

-It is also possible to sponsor the work on a particular opensource project or -feature of one of the existing project by material and/or money donations. -For example, one may want the software to support another UNIX-style system -for which the software does not currently work for some reason, and provide -the necessary hardware and/or software tools to allow to do it. -

-As we are mostly dealing with BSD licensed software it is also possible to -hire us in order to develop a closed-source implementation with -custom-specific needs of one of the existing projects. The customer would -decide whether or not the new branch should eventually be donated, back to the -main public repository, to fall back under the same BSD-license as well -(possibly with an advertising clause in the license text). -

-Finally, a thing which is always encouraging and doesn't cost much, is to -send positive feedback, via email or on freshmeat, about the features you -enjoy in mmsoftware, if you decide to use it. Gifts are also welcome. -

-We appreciate your contribution to our common goal. We would like to assure -you that we use it to the best of our efforts to help the project evolve. -

-Matthew Mondor -

- -
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: donations.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/favicon.ico b/site/favicon.ico deleted file mode 100644 index dcac83569bdadde1f9f299583a29f14a75982a71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318 zcmbV_F%H5|3`5_SkUEld=n9{yw?L>j>YaL>o`sPCAsoV&%FqRWIhGU4ABvutX&x90 z48SOwcot*72U}L=+eGMpa3OwjuQm1Z)%3-yNAsTIpSTKATh9AFdutw=Z+8`{_1^vR RafB_OCkV!Fn+^ZE!W*5;8Z7_- diff --git a/site/images/CVS.jpg b/site/images/CVS.jpg deleted file mode 100644 index 4e382fc57d885ff355c9dfb26338c8c55a548ae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1366 zcmb7Q)DB(dG=+#dos*PYk_pF7 zl9q!=?sLuM*?DSn2}kZnp^HK%hZMELb6(Wj^ZmX1exC2=d4B3)^%Q{daOb%LAP@-P zZXBTg0_eF!2}4f{kC0-Io{k{-MF>e8-ac>j7~ldRG&JBEFa#V9M zrbJWv|Bm`0fJFclAQ%EN1Hf1i1PfAk0R#YmYFz*)d1lC zVGtMsKw%nKoGDy~wukN$dO_DroLTq)&)|o(KY6#Y(c6@LYXd+4cvD8eZuXFG5eN&$ z(M;8&0BWNKV(ssKCDz!aZLz#pypp=ID`t;QP4~b# zhlusy;F>voQBBDZZrI9j`as)Ody$m0ThT&2HW5b|jAV9FleT%D*b!~+Xorp*TO8W* z2Cu?)mMgnyk(5XNzh%>3Q4Nv-u?H8ruy@K89`^Y!JysiZAo*S9dres@UEO`jhV1=;zt8wb-A>od1CU3=La zejEuF-WcVyWMKSMn4F5uuPP3I88KR_C79q1mz~PEf2QAE)@SB79dvLs1M@;QSoAo{ zS>Ws?syZ+B?~*BgJzPa}lScDQ<=1k&@7r+JG#IMR{9pR59|s=h66Dt4MDC;YPVJSz zyikR)Q{aA!!lP_Fq8(E`HGeR#ly0C&kaXBM%FQ)RK1dkBaq^h0OQlE=(#kg@#BBO` zg<(vRmG4OIZ4aeH*+h|_&l6<-jF>ySh)c7M9E&Y59lurcNj71;`gwX@*R4K|H=zS? z?J79r{il!%dd2$d9gwsdh!NDL zS?cp<@s`P%wSxzu(CA|FYj5YfveZVs^i}5WIcCx!$yz;Yxy@4)FPjZyRMa_^RneBA z=fYB=SIV2hrFSKFJgQ50UcOF~cyhcLcm`N-GG9S^QL_Blk6-bCwCwx-V;;SZ2c?A6vmTdT^sY<`^+ywyGkIAy@#YvSYc4oM{Cd~EcTGvP z4)I5NhnU=x4e0Gg93)H&}B$C z>Y0^w>{f?vNv&t|&feRVoS=4N@mz!T)uk&-QQR`V?A3evMM(}()3^4pPY3TWAcUA0 ln=Hjd3wi~1l5Cl$>z%5rS08GMU7%|*X(){Qormg?e*u!pFLVF^ diff --git a/site/images/key.jpg b/site/images/key.jpg deleted file mode 100644 index 6b3f9df6193c7f18a2fb847b2074bd84630e05ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1977 zcmb7>c{JOJ7RP@-5nEbBP_2lJrP_(;AeN9)F`_{vqNJs^ifvjdVyUgQGtV)zT$sk=CBrN_r@RYO9?tuX#Fi&b;&feE0r!@BQ5GJ@;POq--8gcO#KW z00@G>;cW+GUx8iDabY3xVN7&VRD2}*NMsn=l}w?@B!DxpQ&|P3qO=pH0#jApsfIvn zAv81)CP>sSwAp_1AI$b+O)c%*94xI#Hm2A^3@4I@C*7NF;oukIM+L0LZ~X2pp6>1atvF4)Se{|C#~_Rg{OwZ5Qp- z0T2R_gFuuO6d->A;5ID}g)3-$XYPe?3eh&Oz!5`PSDH1o4C!$_idHAs1vSQ&&fC3v zzM=o43(9Y2pbFbH6F49z2g*Sq(0`_aa&U;eIaCAjos*^)OUuB*(n=->b4AFava~TPD}FqVYwk3PGIQq} z4^1zSS9}%~`VI~@E{mz*!VWd)mV%&`ol)Erp87i9EAv?p?`}`Hz~xL0Uq6#3M3wc( z09cpl37c*cMbg5A>TBQc`F!d8Y(@*j5cGf zD~0MAKGefWs-EIXt+gmJ`K`iTJrmEf}C~hWt(|4q7 z9wLCC^P({D?CimWcPSk!C%)jYrMlU=@50swOV>Z;Xz0m+V+UuIUxw1$mQ9#XZP`eq zTF=Rnl>&y-jK&@h7%b^SBJ$j&1c(sZQN@M(*kYle6KH7K~jZMt0Y-{uKZZC=kzmI&PdtCdsja;Q>khU zX>B_?U$enUTJ{<&rHVQ$hkqUrCSKM7HeppXTImtHCP6S*eQE=9ol3V>bnv20!Nden zy4H(^{W`BI=|Am3j%Q9ST?`CGzFg%CuLkJl!uu6Vi0a7)DD$Mt49cM7=&OK=j~VAU zktOd4l0WXKeU0g5y5H@EIZPCu?sQg{j)z5>TzMimKGXO$4YlJwNjJZNRUGP={T5ohR)maEvoaS{X^=xb8HjdOG<0g zpXt`eyw!+Go|o)Jg{SWH>o4WyJc_(@-Le1DOqGS+uO>ZA20ryURg%WEeYyE>b877h4cstrJHOL zfx-EbGc)aqBEyp84e zf*)rtbL*CN$BdP58dgpwPzEMfQs|;L>?O@gY1ra)THj)ndNuLh8;i|xwMrBz(5~lg zBVM$xI*P6LI~RMcY1_7^xX-D0YLx5^ADbRODK$6U~nq8k<-bKoA!caq9&+9 V<0wIi>NU!zai~b*c}LmQe*iScVd($> diff --git a/site/images/sigil.jpg b/site/images/sigil.jpg deleted file mode 100644 index d6f6aceaa809168de37ca8b9eadb53e15b4f192f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3311 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 Q1I>XO@7w>d04)CSFS%hIjQ{`u diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 25f857c..0000000 --- a/site/index.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - -Matthew Mondor's Software Site - Main - - - - - - - - - -

- - - - - - - - -
-Sections
-
-Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-
-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-The MMSoftware Project
- -Image Copyright (c) 2002-2003, Matthew Mondor - -
- -

-NOTE: The french version is not yet available. Additionally, only -the master site currently works, mirrors should be up soon. -

-This site provides various opensource software -to anyone who find it useful. The projects mostly were written from scratch by -Matthew Mondor and released under a BSD-style license, but we also host -third-party software related to these projects, provided by other -contributors worldwide who wanted to make -their related work freely available. -

-The hosting and bandwidth for the mirrors is -provided by various donators accross the globe. -Although we attempt to encourage contributors and donators, we try to keep -this site as free from commercial ads as possible as a convenience to our -users. The main mmsoftware project philosophy -will describe our goals with more details. -

-Matthew Mondor can be contacted via email at -mmondor@gobot.ca for suggestions, -contributions, donations, flames, thanks, business and bug reports. -

-
-
-Languages
-

-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: index.html,v 1.9 2003/09/30 05:34:53 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/mirrors.html b/site/mirrors.html deleted file mode 100644 index ec0583f..0000000 --- a/site/mirrors.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -Matthew Mondor's Software Site - Mirrors - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-MMSoftware Mirrors
-
- -

-Here are the current site mirrors and their generous providers, appearing -in setup chronological order (first setup to last): -

- - - - - - - - - - - - - - - -
LocationProviderURL
United-StatesMatthew J Backeshttp://gobot.accela.net
HollandJeroen Oostendorphttp://mmondor.oostendorp-ict.nl
CanadaRyan Werberhttp://mmondor.dynup.net
-

-If you would like to provide hosting space and bandwidth for a new mirror, -this would consist of a service donation, please consult the -donations area for more information about the -requirements and suggestions. -

-
-
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: mirrors.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/new/TODO b/site/new/TODO deleted file mode 100644 index 9a13720..0000000 --- a/site/new/TODO +++ /dev/null @@ -1,93 +0,0 @@ -Because there is a general layout already for the site (left column with -a main menu, center column with the content for the current page and -right column for the language menu), I should design something which uses -templates or such. I did so for the spes project a while back, but which -dynamically generated the pages, using php. - -I want something with which I can simply type a make command for it to -generate the static html pages. There would be a list of languages and -for each the process would be automatically repeated, also. For each -language, a left main menu and right language selection menu would be -generated, and it's center column contents generated from a template. -Example of a possible layout: - -build/ -build/lang/english -build/lang/english/menu_main.txt -build/lang/english/menu_lang.txt -build/lang/english/page_index.txt -build/lang/english/page_cvs.txt -build/lang/english/page_software.txt -build/lang/english/page_philosophy.txt -build/lang/english/soft_descriptions.txt -build/soft_releases.txt -build/languages.txt -htdocs/ - -The files would be generated into htdocs/ -The soft_descriptions.txt file would hold a map of software name->short -description -> long description, to be used by build/soft_releases.txt in -lang/page_software.txt . -build/languages would hold a list of available languages. - -The format of the manu_*.txt files would be as follows: - -" -"" "" - -I.E. - -"Sections" -"index" "Main" -"software" "Software" -"donations" "Donations" -"contributors" "Contributors" -"philosophy" "Philosophy" -"cvs" "CVS" -"projects" "Projects" -"mirrors" "Mirrors" -"contact" "Contact" - -The filename will be suffixed with the language suffix in the htdocs/ -directory, and the file will be generated from the language/page_.txt -file. - -The format of the languages.txt file would be as follows: - - - -I.E. - -en english -fr french -ru russian - -The format of the page_*.txt files would be standard HTML, but which could -contain special keywords. The only current special keyword consists of: -.soft releases -which should be beginning at the first column, as-is, on a single line. -This keyword causes the soft_releases.txt file to be parsed with the -language/soft_descriptions.txt, to create a table of all the available -software. -It is possible to do: -.soft maintained -.soft unmaintained -etc. - -I also need a special command for mirrors table. And one for links. -The one for links would automatically append the language suffix and -html extension... - -.link -.mirrors - -A similar system for FAQs: - -.faq - - -TODO -==== - -- Verify apache multilingual support to use the same convention for - page storage... diff --git a/site/new/build/GNUmakefile b/site/new/build/GNUmakefile deleted file mode 100644 index f04011d..0000000 --- a/site/new/build/GNUmakefile +++ /dev/null @@ -1,20 +0,0 @@ -# $Id: GNUmakefile,v 1.1 2004/04/30 00:05:53 mmondor Exp $ - -MMLIBS := $(addprefix ../../../mmsoftware/mmlib/,mmpool.o mmlog.o \ -mmreadcfg.o mmstring.o mmhash.o) - -OBJS := mmsite.o - -CFLAGS += -Wall -DDEBUG - - -all: mmsite - -%.o: %.c - cc -c ${CFLAGS} -I. -I../../../mmsoftware/mmlib -o $@ $< - -mmsite: $(MMLIBS) $(OBJS) - cc -o $@ $(OBJS) -lc $(MMLIBS) - -clean: - rm -f mmsite $(OBJS) $(MMLIBS) diff --git a/site/new/build/README b/site/new/build/README deleted file mode 100644 index dc99aeb..0000000 --- a/site/new/build/README +++ /dev/null @@ -1,16 +0,0 @@ -It was chosen to use a simple system based on text files which could be -used with CVS rather than another type of database to build the site's -HTML files from. This allows contributors to simply send a diff generated -by CVS containing their update suggestions and additions. Also, generating -a static site has advantages, allowing cacheing for efficiency by HTTP -cache proxies, and easing the task of mirrors updating their copy of the site. - -This system makes it easy to maintain the list of available software, as -well as to translate the site to other languages, while avoiding HTML -formatting and linking bugs. It also enforces the site's general layout -through all the site pages. The generated pages are made from an W3C validated -template for HTML 4.0 Transitional. - -The default language causes the pages to have no special suffix, while -the others will have the short description of the language appended before -the '.html' extension. diff --git a/site/new/build/TODO b/site/new/build/TODO deleted file mode 100644 index 0832775..0000000 --- a/site/new/build/TODO +++ /dev/null @@ -1,10 +0,0 @@ -- Although it is nice to have a few hash tables for fast lookup, some - files need to be considered as sequencial lists and will be have to - be processed accordingly (using a hash table causes the entries to - become in an arbitrary order). Actually, most or all of the base files - are lists, while language-specific ones are tables for fast lookup - when mapping. - -- Work out a system for FAQs similar to the one for software. - -- Work out a system for news. This would be nice to announce releases etc diff --git a/site/new/build/english/faq_mmftpd.txt b/site/new/build/english/faq_mmftpd.txt deleted file mode 100644 index 886f552..0000000 --- a/site/new/build/english/faq_mmftpd.txt +++ /dev/null @@ -1,17 +0,0 @@ -# First line consists of FAQ .title -# Then following are .section for a section, -# .question <num> <title> for a question. Each can be followed by -# arbitrary HTML, and an index will be automatically generated. -# -.title "Frequently asked questions about mmftpd" -This FAQ deals with most common problems which first time users encounter. -.section "Installation" -This section deals exclusively with mmftpd installation. -.question "How do I compile mmftpd?" -Answer to the question -.question "Another question?" -Another answer. -.section "Configuration" -This section deals with mmftpd configuration. -.question "Blah??" -Answer!? diff --git a/site/new/build/english/faq_mmmail.txt b/site/new/build/english/faq_mmmail.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/faq_mmstatd.txt b/site/new/build/english/faq_mmstatd.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/menu_languages.txt b/site/new/build/english/menu_languages.txt deleted file mode 100644 index b7033ae..0000000 --- a/site/new/build/english/menu_languages.txt +++ /dev/null @@ -1,6 +0,0 @@ -# One line per entry, two columns: -# <language> <description> -# -MENU Languages -english English -french French diff --git a/site/new/build/english/menu_main.txt b/site/new/build/english/menu_main.txt deleted file mode 100644 index ad38d2a..0000000 --- a/site/new/build/english/menu_main.txt +++ /dev/null @@ -1,10 +0,0 @@ -MENU Sections -index Main -software Software -donations Donations -contributors Contributors -philosophy Philosophy -cvs CVS -projects Projects -mirrors Mirrors -contact Contact diff --git a/site/new/build/english/menu_mirrors.txt b/site/new/build/english/menu_mirrors.txt deleted file mode 100644 index 6ef947b..0000000 --- a/site/new/build/english/menu_mirrors.txt +++ /dev/null @@ -1,7 +0,0 @@ -# One line per entry, two columns: -# <name> <description> -# -MENU Mirrors -canada Canada -united-states United-States -holland Holland diff --git a/site/new/build/english/page_contact.txt b/site/new/build/english/page_contact.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_contributors.txt b/site/new/build/english/page_contributors.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_cvs.txt b/site/new/build/english/page_cvs.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_donations.txt b/site/new/build/english/page_donations.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_index.txt b/site/new/build/english/page_index.txt deleted file mode 100644 index 5604f94..0000000 --- a/site/new/build/english/page_index.txt +++ /dev/null @@ -1,22 +0,0 @@ -<p><b>NOTE:</b> The French version of this site is not yet available. -Additionally, only the master site currently works, mirrors should -be back up eventually.</p> -<p>This site provides various open source -.link software software -to anyone who finds it useful. The projects mostly were written from -scratch by Matthew Mondor and released under a BSD-style license, -but we also host third-party software related to these projects, -provided by other -.link contributors contributors -worldwide who wanted to make their related work freely available.</p> -<p>The hosting and bandwidth for the -.link mirrors mirrors -is provided by various -.link donations donators -accross the globe. Although we attempt to encourage contributors and -donators, we try to keep this site as free from commercial ads as -possible as a convenience to our users. The main mmsoftware project -.links philosophy philosophy will describe our goals with more details.</p> -<p>Matthew Mondor can be contacted via email at -<a href="mailto:mmondor@accela.net">mmondor@accela.net</a> for suggestions, -contributions, donations, flames, thanks, business and bug reports.</p> diff --git a/site/new/build/english/page_mirrors.txt b/site/new/build/english/page_mirrors.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_philosophy.txt b/site/new/build/english/page_philosophy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_projects.txt b/site/new/build/english/page_projects.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/page_software.txt b/site/new/build/english/page_software.txt deleted file mode 100644 index e69de29..0000000 diff --git a/site/new/build/english/soft_descriptions.txt b/site/new/build/english/soft_descriptions.txt deleted file mode 100644 index 3c2bc21..0000000 --- a/site/new/build/english/soft_descriptions.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Each project is separated by an empty line. The first line of a project -# consists of it's name, the second line of it's short description, and -# the following lines, in HTML format, of the long description, ending -# with an empty line. -# -mmftpd -Unprivileged virtual users FTP server -Long multiline description follows in HTML, until empty line. -So it continues... -And still... - -ginseng-ftpd -blah -blah - diff --git a/site/new/build/mmsite.c b/site/new/build/mmsite.c deleted file mode 100644 index 2ef1395..0000000 --- a/site/new/build/mmsite.c +++ /dev/null @@ -1,557 +0,0 @@ -/* $Id: mmsite.c,v 1.1 2004/04/30 00:05:53 mmondor Exp $ */ - -/* - * Copyright (C) 2003, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This program builds the site in htdocs/. Please read mmsite.8 for more - * information on the required layout. This is a helper to generate correct - * HTML, translate the site into multiple languages and build the software - * and faq indexes and tables, using static pages only. This then allows - * acceleration using cacheing HTTP proxies and helps to more easily provide - * a straightforward method for mirror providers. - */ - - - -/* HEADERS */ - -#include <sys/types.h> -#include <stdlib.h> -#include <stdio.h> - -#include <mmtypes.h> -#include <mmstring.h> -#include <mmpool.h> -#include <mmlist.h> -#include <mmhash.h> - - - -/* DEFINITIONS */ - -/* The following system allows to load arbitrary tables from files. The - * table field is only used for language map to the project descriptions. - */ -#define COLS_MAX 4 -#define LINE_MAX 256 - -typedef struct table_node { - hashnode_t node; - char line[LINE_MAX]; - char *columns[COLS_MAX]; - size_t lengths[COLS_MAX]; - hashtable_t *table; -} table_node; - -/* And for linked lists, where order is necessary */ -typedef struct list_node { - node_t node; - char line[LINE_MAX]; - char *columns[COLS_MAX]; - size_t lengths[COLS_MAX]; - u_int32_t hash; -} list_node; - -/* The following are definitions helping to use each of our known tables. - * Let's start with the global ones: - * -------------------------------- - */ - -/* table_languages */ -enum columns_languages { - LANGUAGES_NAME = 0, - LANGUAGES_MAX -}; -#define LANGUAGES_KEY LANGUAGES_NAME - -/* table_mirrors */ -enum columns_mirrors { - MIRRORS_NAME = 0, - MIRRORS_URL, - MIRRORS_CONTRIBUTOR, - MIRRORS_MAX -}; -#define MIRRORS_KEY MIRRORS_URL - -/* table_pages */ -enum columns_pages { - PAGES_NAME = 0, - PAGES_MAX -}; -#define PAGES_KEY PAGES_NAME - -/* table_software */ -enum columns_software { - SOFTWARE_CATEGORY = 0, - SOFTWARE_DIRECTORY, - SOFTWARE_MAX -}; -#define SOFTWARE_KEY SOFTWARE_CATEGORY - -/* For each of table_software, projects */ -enum columns_projects { - PROJECTS_NAME = 0, - PROJECTS_STATUS, - PROJECTS_VERSION, - PROJECTS_MAX -}; -#define PROJECTS_KEY PROJECTS_NAME - -/* Following are the language-specific tables: - * ------------------------------------------ - */ - -/* table_menu_languages */ -enum columns_menu_languages { - MENU_LANGUAGES_NAME = 0, - MENU_LANGUAGES_DESCR -}; - -#define MENU_LANGUAGES_KEY MENU_LANGUAGES_NAME - -/* This structure is hold to hold nodes in project description tables */ - -#define TDN_PROJECT_MAX 32 -#define TDN_DESCR_S_MAX 256 -#define TDN_DESCR_L_MAX 2048 - -typedef struct table_descr_node { - hashnode_t node; - char project[TDN_PROJECT_MAX]; - char descr_s[TDN_DESCR_S_MAX]; - char descr_l[TDN_DESCR_L_MAX]; -} table_descr_node; - - - -/* PROTOTYPES */ - -int main(void); - -static hashtable_t *table_load(const char *, unsigned int, unsigned int); -static hashtable_t *table_descr_load(const char *); -static hashtable_t *table_free(hashtable_t *); -static list_t *list_load(const char *, unsigned int, unsigned int); -static list_t *list_free(list_t *); - - - -/* GLOBALS */ - -static pool_t table_pool, table_descr_pool, list_pool; -static hashtable_t *table_languages = NULL, *table_descriptions = NULL; - -static list_t *list_software = NULL; - - - -/* CODE */ - -int main(void) -{ - /* First initialize our fast memory management pools */ - if (!pool_init(&table_pool, malloc, free, sizeof(table_node), - 65536 / sizeof(table_node), 0, 0)) { - (void) fprintf(stderr, "main() - pool_init(table_pool)\n"); - return EXIT_FAILURE; - } - if (!pool_init(&table_descr_pool, malloc, free, sizeof(table_descr_node), - 65536 / sizeof(table_descr_node), 0, 0)) { - (void) fprintf(stderr, "main() - pool_init(table_descr_pool)\n"); - return EXIT_FAILURE; - } - if (!pool_init(&list_pool, malloc, free, sizeof(list_node), - 65536 / sizeof(list_node), 0, 0)) { - (void) fprintf(stderr, "main() - pool_init(list_pool)\n"); - return EXIT_FAILURE; - } - - /* Load global lists */ - if ((list_languages = list_load("site_languages.txt", LANGUAGES_MAX, - LANGUAGES_KEY)) == NULL) { - (void) fprintf(stderr, "main() - list_load(site_languages.txt)\n"); - return EXIT_FAILURE; - } - if ((list_mirrors = list_load("site_mirrors.txt", MIRRORS_MAX, - MIRRORS_KEY)) == NULL) { - (void) fprintf(stderr, "main() - list_load(site_mirrors.txt)\n"); - return EXIT_FAILURE; - } - - /* Load required lists */ - if ((table_languages = table_load("site_languages.txt", LANGUAGES_MAX, - LANGUAGES_KEY)) == NULL) { - (void) fprintf(stderr, "main() - table_load(languages)\n"); - return EXIT_FAILURE; - } - if ((table_descriptions = table_descr_load( - "english/soft_descriptions.txt")) == NULL) { - (void) fprintf(stderr, "main() - table_descr_load(descriptions)\n"); - return EXIT_FAILURE; - } - if ((list_software = list_load("site_software.txt", SOFTWARE_MAX, - SOFTWARE_KEY)) == NULL) { - (void) fprintf(stderr, "main() - list_load(software)\n"); - return EXIT_FAILURE; - } else { - list_node *node; - - for (node = DLIST_TOP(list_software); node != NULL; - node = DLIST_NEXT(node)) - (void) printf("'%s|%s'\n", node->columns[SOFTWARE_CATEGORY], - node->columns[SOFTWARE_DIRECTORY]); - } - - { - table_node *node; - - if ((node = (table_node *)hashtable_lookup(table_languages, - "english", 7)) - != NULL) - (void) printf("%s\n", node->columns[LANGUAGES_NAME]); - else - (void) printf("'english' not found!\n"); - } - { - table_descr_node *node; - - if ((node = (table_descr_node *)hashtable_lookup(table_descriptions, - "mmftpd", 6)) != NULL) { - (void) printf("Project: %s\n", node->project); - (void) printf("Descr_s: %s\n", node->descr_s); - (void) printf("Descr_l: %s", node->descr_l); - } else - (void) printf("'mmftpd' not found!\n"); - } - - table_languages = table_free(table_languages); - return EXIT_SUCCESS; -} - - -/* Loads a hash table from the specified text file which holds one entry - * per line and <cols> expected columns each. Links each entry to the table - * using <key> column as the lookup key. Returns the hashtable_t pointer on - * success, or NULL. - */ -static hashtable_t *table_load(const char *file, unsigned int cols, - unsigned int key) -{ - hashtable_t *table = NULL; - table_node *node = NULL; - FILE *fh; - - if (cols >= COLS_MAX || key >= COLS_MAX) { - (void) fprintf(stderr, "table_load(%s) - cols|key >= COLS_MAX!\n", - file); - return NULL; - } - - if ((fh = fopen(file, "r")) != NULL) { - if ((table = malloc(sizeof(hashtable_t))) != NULL) { - if (hashtable_init(table, HT_DEFAULT_CAPACITY, HT_DEFAULT_FACTOR, - malloc, free, mm_memcmp, hashtable_hash, TRUE)) { - for (;;) { - int i; - size_t len; - - if (node == NULL && (node = (table_node *)pool_alloc( - &table_pool, FALSE)) == NULL) { - (void) fprintf(stderr, - "table_load(%s) - pool_alloc()\n", - file); - break; - } - if (fgets(node->line, LINE_MAX - 1, fh) == NULL) { - node = (table_node *)pool_free((pnode_t *)node); - break; - } - len = mm_strlen(node->line); - if (len > 0 && node->line[len - 1] == '\n') - len--; - if (len > 0 && node->line[len - 1] == '\r') - len--; - node->line[len] = '\0'; - if (*node->line == '#' || *node->line == '\0') - continue; - if (mm_strasplq(node->columns, node->line, cols) != cols) { - (void) fprintf(stderr, - "table_load(%s) - Invalid line '%s'\n", - file, node->line); - break; - } - for (i = 0; i < cols; i++) - node->lengths[i] = mm_strlen(node->columns[i]); - node->table = NULL; - if (!hashtable_link(table, (hashnode_t *)node, - node->columns[key], node->lengths[key])) { - (void) fprintf(stderr, - "table_load(%s) - link key '%s'\n", - file, node->columns[key]); - break; - } - node = NULL; - } - if (node != NULL) - table = table_free(table); - } else { - (void) fprintf(stderr, "table_load(%s) - hashtable_init()\n", - file); - free(table); - table = NULL; - } - } else - (void) fprintf(stderr, "table_load(%s) - malloc(table)\n", - file); - (void) fclose(fh); - } - - return table; -} - -/* This function loads another type of file-based table. For each entry, - * the first line consists of the project name, the second of the short - * project description, and the following lines of the long description - * with allowed embedded HTML for emphasis, ending with an empty line. - */ -static hashtable_t *table_descr_load(const char *file) -{ - hashtable_t *table = NULL; - table_descr_node *node = NULL; - FILE *fh; - char line[TDN_DESCR_S_MAX]; - - if ((fh = fopen(file, "r")) != NULL) { - if ((table = malloc(sizeof(hashtable_t))) != NULL) { - if (hashtable_init(table, HT_DEFAULT_CAPACITY, HT_DEFAULT_FACTOR, - malloc, free, mm_memcmp, hashtable_hash, TRUE)) { - int field = 0; - size_t descr_l_len = 0, project_len = 0; - - for (;;) { - size_t len; - - if (node == NULL) { - if ((node = (table_descr_node *)pool_alloc( - &table_descr_pool, FALSE)) == NULL) { - (void) fprintf(stderr, - "table_descr_load(%s) - pool_alloc()\n", - file); - break; - } - /* New entry */ - field = 0; - descr_l_len = project_len = 0; - } - if (fgets(line, TDN_DESCR_S_MAX - 1, fh) == NULL) { - if (field == 0) - node = (table_descr_node *)pool_free( - (pnode_t *)node); - else - (void) fprintf(stderr, "table_descr_load(%s) - \ -Incomplete entry for '%s'\n", file, node->project); - break; - } - len = mm_strlen(line); - if (len > 0 && line[len - 1] == '\n') - len--; - if (len > 0 && line[len - 1] == '\r') - len--; - line[len] = '\0'; - if (*line == '#' && field == 0) - continue; - if (len == 0) { - /* Empty line, ignore if between two entries, - * consider it as entry termination if we filled - * them all, generate an error otherwise. - */ - if (field == 0) - continue; - else if (field == 2) { - /* Link entry and force new entry creation */ - if (!hashtable_link(table, (hashnode_t *)node, - node->project, project_len)) { - (void) fprintf(stderr, "table_descr_load(%s) \ -- hashtable_link(%s)\n", file, node->project); - break; - } - node = NULL; - continue; - } else { - (void) fprintf(stderr, "table_descr_load(%s) - \ -Incomplete entry for '%s'\n", file, node->project); - break; - } - } - if (field == 0) { - /* Project field entry */ - if (len > TDN_PROJECT_MAX - 1) { - (void) fprintf(stderr, "table_descr_load(%s) - \ -Project field exceeds %d for '%s'\n", file, TDN_PROJECT_MAX - 1, - node->project); - break; - } - mm_memcpy(node->project, line, len + 1); - project_len = len; - field = 1; - continue; - } else if (field == 1) { - /* Short description entry */ - if (len > TDN_DESCR_S_MAX - 1) { - (void) fprintf(stderr, "table_descr_load(%s) - \ -Short description field exceeds %d for '%s'\n", file, TDN_DESCR_S_MAX - 1, - node->project); - break; - } - mm_memcpy(node->descr_s, line, len + 1); - field = 2; - continue; - } else if (field == 2) { - /* Long description entry */ - if (descr_l_len + len + 1 > TDN_DESCR_L_MAX - 1) { - (void) fprintf(stderr, "table_descr_load(%s) - \ -Long description field exceeds %d for '%s'\n", file, TDN_DESCR_L_MAX - 1, - node->project); - break; - } - mm_memcpy(&node->descr_l[descr_l_len], line, len); - descr_l_len += len; - node->descr_l[descr_l_len++] = '\n'; - continue; - } - } - if (node != NULL) - table = table_free(table); - } else { - (void) fprintf(stderr, - "table_descr_load(%s) - hashtable_init()\n", - file); - free(table); - table = NULL; - } - } else - (void) fprintf(stderr, "table_descr_load(%s) - malloc(table)\n", - file); - (void) fclose(fh); - } - - return table; -} - -static hashtable_t *table_free(hashtable_t *table) -{ - if (table != NULL) { - (void) hashtable_destroy(table, TRUE); - free(table); - } - - return NULL; -} - - -static list_t *list_load(const char *file, unsigned int cols, unsigned int key) -{ - list_t *list = NULL; - list_node *node = NULL; - FILE *fh; - - if (cols >= COLS_MAX || key >= COLS_MAX) { - (void) fprintf(stderr, "list_load(%s) - cols|key >= COLS_MAX!\n", - file); - return NULL; - } - - if ((fh = fopen(file, "r")) != NULL) { - if ((list = malloc(sizeof(list_t))) != NULL) { - DLIST_INIT(list); - for (;;) { - int i; - size_t len; - - if (node == NULL && (node = (list_node *)pool_alloc(&list_pool, - FALSE)) == NULL) { - (void) fprintf(stderr, - "list_load(%s) - pool_alloc()\n", - file); - break; - } - if (fgets(node->line, LINE_MAX - 1, fh) == NULL) { - node = (list_node *)pool_free((pnode_t *)node); - break; - } - len = mm_strlen(node->line); - if (len > 0 && node->line[len - 1] == '\n') - len--; - if (len > 0 && node->line[len - 1] == '\r') - len--; - node->line[len] = '\0'; - if (*node->line == '#' || *node->line == '\0') - continue; - if (mm_strasplq(node->columns, node->line, cols) != cols) { - (void) fprintf(stderr, - "list_load(%s) - Invalid line '%s'\n", - file, node->line); - break; - } - for (i = 0; i < cols; i++) - node->lengths[i] = mm_strlen(node->columns[i]); - node->hash = hashtable_hash(node->columns[key], - node->lengths[key]); - DLIST_APPEND(list, (node_t *)node); - node = NULL; - } - if (node != NULL) - list = list_free(list); - } else - (void) fprintf(stderr, "list_load(%s) - malloc(list)\n", - file); - (void) fclose(fh); - } - - return list; -} - -static list_t *list_free(list_t *list) -{ - if (list != NULL) { - node_t *node, *tnode; - - for (node = DLIST_TOP(list); node != NULL; node = tnode) { - tnode = DLIST_NEXT(node); - (void) pool_free((pnode_t *)node); - } - free(list); - } - - return NULL; -} diff --git a/site/new/build/mmsite.conf b/site/new/build/mmsite.conf deleted file mode 100644 index 586b8b5..0000000 --- a/site/new/build/mmsite.conf +++ /dev/null @@ -1,12 +0,0 @@ -# General configuration options about the site - -TITLE "Matthew Mondor's Software Site" -BGCOLOR #f0f0ff -TEXT #000000 -LINK #3535c5 -VLINK #700080 -MENU_BGCOLOR #d0d0f0 -MENU_TEXT #000066 -FONT "helvetica, arial" -HTDOCS ../htdocs -DEFAULT_LANG en diff --git a/site/new/build/site_faq.txt b/site/new/build/site_faq.txt deleted file mode 100644 index ad51485..0000000 --- a/site/new/build/site_faq.txt +++ /dev/null @@ -1,6 +0,0 @@ -# One FAQ entry per line, one column: -# <faq> -# -mmftpd -mmmail -mmstatd diff --git a/site/new/build/site_languages.txt b/site/new/build/site_languages.txt deleted file mode 100644 index 27884a1..0000000 --- a/site/new/build/site_languages.txt +++ /dev/null @@ -1,5 +0,0 @@ -# One language description per line, one column: -# <language> -# -english -french diff --git a/site/new/build/site_mirrors.txt b/site/new/build/site_mirrors.txt deleted file mode 100644 index 8e6834f..0000000 --- a/site/new/build/site_mirrors.txt +++ /dev/null @@ -1,6 +0,0 @@ -# One line per entry, three columns: -# <name> <URL> <provider> -# -canada http://mmondor.dynup.net/ "Ryan Werber" -united-states http://gobot.accela.net/ "Matthew J Backes" -holland http://mmondor.oostendorp-ict.nl/ "Jeroen Oostendorp" diff --git a/site/new/build/site_pages.txt b/site/new/build/site_pages.txt deleted file mode 100644 index 8d18ccc..0000000 --- a/site/new/build/site_pages.txt +++ /dev/null @@ -1,12 +0,0 @@ -# One entry per line, one column: -# <name> -# -index -software -donations -contributors -philosophy -cvs -projects -mirrors -contact diff --git a/site/new/build/site_software.txt b/site/new/build/site_software.txt deleted file mode 100644 index 19c965c..0000000 --- a/site/new/build/site_software.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Each software category, one entry per line, two columns: -# <category> <location> -# -stable software/stable -development software/devl -old software/old diff --git a/site/new/build/soft_development.txt b/site/new/build/soft_development.txt deleted file mode 100644 index 8f9ebe9..0000000 --- a/site/new/build/soft_development.txt +++ /dev/null @@ -1,4 +0,0 @@ -# One project per line, three columns per project: -# <projname> <status> <version> -# -mmftpd devl 1.0 diff --git a/site/new/build/soft_old.txt b/site/new/build/soft_old.txt deleted file mode 100644 index 0874594..0000000 --- a/site/new/build/soft_old.txt +++ /dev/null @@ -1,4 +0,0 @@ -# One project per line, three columns per project: -# <projname> <status> <version> -# -ginseng-ftpd devl 1.0 diff --git a/site/new/build/soft_stable.txt b/site/new/build/soft_stable.txt deleted file mode 100644 index 0874594..0000000 --- a/site/new/build/soft_stable.txt +++ /dev/null @@ -1,4 +0,0 @@ -# One project per line, three columns per project: -# <projname> <status> <version> -# -ginseng-ftpd devl 1.0 diff --git a/site/philosophy.html b/site/philosophy.html deleted file mode 100644 index bb21770..0000000 --- a/site/philosophy.html +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> - -<html><head> -<!-- $Id: philosophy.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $ - Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED. ---> -<title>Matthew Mondor's Software Site - Philosophy - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-Philosophy behind mmsoftware
-
- -

-Several primary goals were the basis to write my suite of public internet -services. One consisted of a challenge to learn UNIX APIs deeply at the time -I decided to write my own. This is no longer the case, but probably that the -most driving factor still has to do with my need to run such services. -

-Of course there exists a variety of solutions for each of the standard -protocols. However, most of them seemed historical, based on code which made -it though the years through extreme amounts of patching and kludges. This -generally results in solutions which are hard to configure, and have gone -though a long history of security-related issues. Most of them even support -obsolete protocols, or experimental ones which never have been widely used. -

-Moreover, several of them were subject to strict licensing issues. Writing -my own software I have the full rights to do whatever I want with it, as -well as eventually distribute closed-source special editions commercially. -But I didn't want to be the only one to be able to do this, hence I decided -to release my software under a BSD-style license (Berkeley Source Distribution -license), allowing others to modify it and distribute it under source or -binary form as wanted, only requireing them to add an aknowledgement to their -product documentation: -

-  This product includes software written by Matthew Mondor. -

-It however obviously is encouraged to report to me the various bug fixes -or enhancement patch so that the main publicly available tree also evolve. -

-Considering security aspects, most traditional UNIX internet services software -ran as the superuser, and required standard UNIX users to be added for each -remote user. I strongly beleive that most administrators enjoy being able to -only create virtual users rather than real UNIX shell ones for each of their -users. My daemons therefore only allow virtual users. Moreover, none of them -require to run as the superuser after their initial startup. Most of them -have support for chroot(2) as well, for administrators who need it. -

-These are public services afterall. I personally use them to contribute -software and services which are often free of charge, and would find it quite -discouraging if my services were exploited and servers virtually destroyed. -I think that many administrators are in the same position and would like to -run safe services. -

-Special care is taken when writing this software to avoid memory leaks (which -could be a threat to service uptime and autonomy), and to check every -error condition possible. As the services should remain up, system resources -error conditions are treated in a safe way; The current operation is cancelled -to not execute code which requires these new resources to be allocated, -previous allocated ones are released if any (but not all) were obtained for -the current operation as well, and the service keeps running as usual. This -also implies using I/O operations which can timeout where required. Also, -libc functions with uncertain delay periods get executed by an asynchroneous -parallel system when userspace threading systems are used, to prevent locking -the main process, allowing service to remain fluid among the multiple -simultaneous connections being served. Some effort was also made to keep the -code clean. -

-C was chosen to write these for several reasons. I am well used to it, having -used it for many years, was a primary one. A second worthwhile reason is that -the UNIX, POSIX and BSD APIs are intended for C programs. It is also possible -for the programmer to optimize C code decently rather than only relying on -compiler effeciency to do it, gaining speed advantage without having to use -less maintainable and unportable assembly. When well written, C programs are -also portable. C++ could have suited, but would result in generally less -efficient code. I also like to control my own use of memory useage, object -allocation and garbage collection, hence it was not worth it to use C++. -Where possible, ANSI-C compliance is observed. -

-Matthew Mondor -

-
-
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: philosophy.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/projects.html b/site/projects.html deleted file mode 100644 index 199eeb2..0000000 --- a/site/projects.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - -Matthew Mondor's Software Site - Projects - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-Various Projects and Background
-
- -

-Here first follows an overview of my computer-related background -

-A brief overview of my computer-related background: I touched my first computer -at the age of 8, an Apple][+, on which I immediately wanted to code games, -mostly of the text type. I then learned 6802 assembly, as AppleSoft BASIC was -pretty much useless, and Z80 assembly, which was available through a -bridgeboard. I then wrote disk utilities (backup, data retreival). -

-I then at my great joy had my first Amiga when I was 15, on which I first used -mildly AmigaBASIC. Of course a year later I was learning C, and using the RKMS -wrote AstralPortal (Voice/Fido/Data Modem software) in the few following years. -I then did some 2d vector graphics using 68000 assembly, C and sometimes -BlitzBasic (which accepted direct assembly instructions and had nice blit -routines. Some playing with ARexx was then done. The last thing I developed -on Amiga was audio sample manipulation and compression utilities in C, along -with a programmable binaural/hemisync braintrainer, and some custom GUI -library. Another latest project was a control server which allowed several -RS232 terminals to be synchronized with a main multitasking server application -with abstract tty-specific code translation. What a great box that was. -

-Then finally, I decided to get an i386DX/40/8megs although it was already -deprecated, and started doing some Turbo-C and 8088 assembly on MS-DOS, -and wrote trivial 2d 8-bit functions library along with a graphic -block-oriented editor for game programming. Some scrolling, sprite and -collision code was added, and it was a ready system to write games, but none -were ever written using it, but demos. As I always was avoiding windows since, -but had to at least confront it for a while, I finally bought an AMD-K6-2/450 -and learned some Win32 API, tried various compilers with GUI frontends. I -unfortunately was pretty discouraged after a year or so, and was not -programming anything useful; Until I made a discovery... Linux 2.0.35 (RH6) -in December 1999. -

-I used RedHat 6 for a few months, getting aquainted with GCC (which fortunately -had the same base interface than DICE dcc from Matt Dillon which I was using -on the Amiga). And, glibc info/man pages. Linux finally made me discover that -a PC could finally be worth it, as much as Amiga was. I soon found that on -an AmigaOS shell I couldn't remember the commands, erroneously typing unix -ones. The switch was made. I then tried Debian Potato, which of course made -me forget RH for good, and eventually did my own distribution, Ginseng, a -security and server related distribution. Between Debian and Ginseng I started -to write a few meaningful TCP server-oriented utilities. I then discovered -NetBSD. -

-Obviously I then had found my ideal OS, which I am still heavily using today -on all my systems. I finally was free from glibc, which was everyday getting -more bloated without true additionnal functionallity. -I tried other BSD variants and was more convinced that NetBSD still was my -choice. My current publically available software was written using it. -Current projects include mmmail, which is now being totally redesigned from -scratch (for v2), mmftpd, Xisop (a portable non-SMP multitasking preemptive -microkernel similar to AmigaOS), an arbitrary math library and C-like -simplified tokernizer/interpretor language for secure distributed network -clients, along with their distributed server counterpart. I mostly emphasize -my projects on security (good tactics as running virtual services as -non-privileged users, encryption, etc are useful). -

-I also use and test various tunnelling/VPN solutions, am working on a secure -NFS alternative, and various work-related projects. I try to eventually -provide easy solutions to common administration nightmares such as sendmail -administration, localized central data servers and similar tasks. Some work -has also been done on a state-persistant secure HTTP authentication protocol -where unique cookies are exchanged between each page under SSL, and their -origin/expiration verified on the server-side, possibly that an ssl-httpd will -eventually become available for safe remote administration of mmmail, mmftpd -and other server daemons I write. -

-I often don't mind to redesign existing systems, re-invent them or be -inspired by their concepts, when a happy result can be obtained afterwards. -Other non-computer related interests exist, including swimming, martial -arts, meditation (often a necessity for relaxation), international foods, -microbrewered and rare dark, rich beers, especially the stout type. -Writing also has always been a great passion all my life, from adventure -novels (unpublished) to technical documentation (some only has been made -available publically). And music. What a great way to express soul states, -composing and producing various music types, especially Fusion-Jazz remains -a never-ending story. -

-Matt -

-
-
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: projects.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/site/software.html b/site/software.html deleted file mode 100644 index 7781a2a..0000000 --- a/site/software.html +++ /dev/null @@ -1,342 +0,0 @@ - - - - -Matthew Mondor's Software Site - Software - - - - - - - - - -

- - - - - -

- - -
-Sections
-
-

Main 
Software 
Donations 
Contributors 
Philosophy 
CVS 
Projects 
Mirrors 
Contact 
-

-
Image Copyright (c) 2002-2003, Matthew Mondor -
-
-The Software
-
- -

-This page contains the various official mmsoftware sources. The third-party -software provided by the contributors can be found in the -contributors area. Access to the current -official mmsoftware sources CVS repository is available (via pserver). Details -about CVS can be found under the CVS section. It is -also possible to obtain the source archives of the old releases for reference -only, in the software archive: software/. -

Featured software:

-This software is actively maintained and in constant development. This also -means that bug reports are taken into consideration as fast as -possible and new version released accordingly, shortly after bug discovery, -when a suitable solution has been implemented to solve the issue. -

-
- - - - - - - - - - - -
mmftpd0.0.17Devl -ChangeLog -MD5
-Unprivileged virtual users FTP server -
-

-mmftpd was written from scratch from the ground up, and consists of a -featureful yet very security-aware FTP server. It is released under the -terms and conditions of the BSD license with advertizing clause to keep -credits to the author. It ensures to run under a single unprivileged user, -and provides FTP virtual users, as opposed to traditional UNIX/system ones, -which each appear jailed in their home directory using extensive path sanity -checking. It optionally also can chroot(2) at program startup for the whole -service and all users to be setup under a real alternative root jail. -Runs great on BSD and Linux systems and is fairly small in size. Well -documented via UNIX manual pages. -

-The server can limit the connection rate from an address and also has -bandwidth traffic shaping capabilities for both control and data ports, -on a per-connection and global basis. It also can limit the connections -on several factors (maximum number of addresses, number of allowed -connections per address and how many simultaneous connections from the same -FTP user to accept). Client hostname resolving is optional for speed, and -is performed using asynchroneous methods when enabled. -

-For each FTP user a number of permission parameters can be customized, -including the maximum upload and download speed, umask, rights to -change umask, upload, modify, maximum home directory tree size (even safe -among multiple simultaneous connections of the same user). Various techniques -were implemented to prevent common Denial Of Service attempts. -

-Various statistics are reliably maintained using the mmstat facility, -and the administrator can set the verbosity of wanted events and statistics -to be output via syslog. Moreover it uses efficient custom I/O buffering -around filedescriptors for speed. Users are stored in a configuration file -with their permissions, using native crypt(3) password hashes -(both MD5 and DES), so that it is possible to create virtual mmftpd users -from system ones using the same password hashes. The server options are -configured via a second configuration file. -


- - - - - - - - -
mmmail0.0.23Devl -ChangeLog -MD5
-Unprivileged virtual SMTP+POP3 server suite using MySQL -
-

-mmmail was written from scratch from the ground up, and consists of a -suite of SMTP and POP3 servers which can fully run under a unprivileged -user. It is released under the terms and conditions of the BSD license with -advertizing clause to keep credits to the author. It provides virtual mail -users, contrary to traditional UNIX/system ones. It optionally supports -chroot(2) at program startup to enclose itself into a jail. It runs great -on both BSD and Linux systems and is fairly small in size. Well documented -via UNIX manual pages. -

-The servers can limit their clients connection rate on a per-address basis, -and also support bandwidth traffic shaping capabilities in both directions -(connection-specific and global ones). It also can limit the connections -on several factors (maximum number of addresses, number of allowed -connections per address and how many simultaneous connections from the same -POP3 user to accept). Client hostname resolving is optional for speed, and -is performed using asynchroneous methods when enabled. Moreover, the -administrator may decide weither to check for HELO and/or MAIL MX DNS -records before accepting SMTP mail from a client. Use of HELO may be -disabled or enforced. Various techniques were implemented to prevent common -Denial Of Service attempts. -

-For each mail user/password pair can exist several email addresses at several -virtual hosts, and aliasing is supported to map unexisting addresses to others, -even optionally using wildcard pattern matching. The administrator can also -set the address and/or hostname masks through which mail with empty FROM -address is sent. Each mailbox can be set customizeable quotas (mailbox total -size and total number of messages). All storage (users, mailboxes, and mail -itself) uses MySQL, which permits a global database server to be used, even -remotely. A persistant connection is established and maintained with the -server by each daemon, and re-established if ever necessary. -

-Various statistics are reliably maintained using the mmstat facility, -and the administrator can set the verbosity of wanted events and statistics -to be output via syslog. Moreover it uses efficient custom I/O buffering -around filedescriptors for speed. Each daemon is configured through it's -own configuration file. User password hashes are stored in native crypt(3) -format (both MD5 and DES work) so it is possible to translate system users -to mmmail virtual ones keeping the same hash. -Also, mmpop3d supports unstandard POP3 PAGE command (better than TOP) which -was especially implemented for human POP3 clients. -

-Unfortunately, support for relaying will only be added for mmmail2, a future -re-implementation of mmmail which also should support multiple authentication -and storage methods, as well as many other features including IMAP. -If you are interested in knowing more about mmmail2 ongoing engineering -(diagrams and documentation), and to make suggestions, you can download this -mmmail-design.pdf document. -


- - - - - - - - - -
mmstatd0.0.8Devl -ChangeLog -MD5
-Statistics maintenance server daemon and client library -
-

-mmstatd was originally written for mmftpd and mmmail to asynchroneously -maintain statistical counters in an efficient manner. I however also -release it separately as it is used by some other people in their projects. -These include an IRC network services system which although using db4 for -most data storage uses mmstat(3) library for various statistics counters. -

-It does not require any additional libraries, and provides a simple API -for applications to either update counters or query statistics. The update -requests are done using an AF_LOCAL/UNIX datagram to the mmstatd service's -log socket, similarly to the way syslog(3) works. Statistics are queried -via an AF_LOCAL/UNIX stream on another mmstatd socket. Permissions for access -to both sockets can be different. -

-The service consists of a librarian and logger. The logger accumulates -requests filling a recovery log, while the librarian processes those logs -asynchroneously and syncs the disk database with them from time to time. -In case of a crash, the recovery logs which weren't synchronized yet to -disk are used to recover from the crash. Provided with it is a utility -to query and update statistics from the shell as well. -


Unmaintained software:

-

-This section contains software which works but which I am no longer -maintaining. These are Linux-specific and are getting old. I keep them -here because a fair amount of people find these handy and download -them. -

- - - - - - - - - -
mmtcpfwd0.1.0Stable -ChangeLog -MD5
-Port forwarder, MASQ fake identd and FTP proxy for Linux -
-

-Written from scratch, consists of a superserver daemon made of two parts, -one process running as the superuser (to perform tasks like modifying -firewall rules) and the other running as an unprivileged user performing -all the work. This privilege separation system is quite effective for -a secure setup. Linux 2.2 specific (can work with 2.4+ but without the -transparent proxying support). Released under the terms of the GPL -(GNU Public License). -

-mmtcpfwd provides transparent TCP/IP connection proxying from a MASQ enabled -gateway to other machines, including FTP connections, via a special userspace -passive FTP connections proxy supporting PASV, LPSV and EPSV, and masking the -actual FTP server LAN address by supplying the gateway's address instead. -Supports SMP where hardware permits. Uses a main configuration file to -configure all it's parameters. Also provides an optional random UNIX-ident -protocol daemon, allowing masqueraded connections behind the gateway to -use services requireing identd to run. -

-For each forwarded port, a non-privileged process is setup to listen to -and forward multiple connections to their configured destination. This -destination can consist of a remote or local host, and it is possible to -make it resolve IP address by hostname or to specify absolute IP addresses -for speed. -

-Several interesting techniques are implemented to counter Denial of Service -attacks: Total number of forwarded simultanious connections per port can be -set, as well as per address. Also permits to deny automatically an IP address -overflowing connections with a threshold, in which case each active connection -from that address are cleanly closed before applying the firewall deny rule, -executing a command of our choice. Allows to fake services like portsentry to -immediately DENY an IP address that connects, sending a configurable message -before closing and applying the DENY rule. Can also automatically undeny IP -addresses of offendants after a certain amount of minutes, or indefinitely. -As many IP addresses to never deny as we want can be specified. -

-Uses syslog logging, to keep log of connections/bytes transfered, elapsed -time, etc... Hostnames can be resolved or not, on a per-port basis. -Supports kernel's IP Transparent Proxying support to fake client's IP address -when forwarding. Aimed towards security as much as possible. -Fairly small, executable around 30k only. -

-

- - - - - - - - -
ginseng-ftpd1.6Devl -ChangeLog -MD5
-Security-enhanced Linux ftpd based on bsd-ftpd (NetBSD) -
-

-This server originally consisted of a port of BSD-FTPd to Linux, and various -custom features were added which I personally needed at the time. Since I -wrote mmftpd which much better suits my needs I no longer maintain -ginseng-ftpd. It's still available though, for people who need to run FTP -services with real users (where security is generally not that much of a -concern). An FTP server allowing use of standard UNIX system users obviously -required to run as the superuser. Run mmftpd if you need better security. -Was released under the terms of the BSD license. -

-I here describe a list of the various changes that I made on the original -BSD-FTPd code: The popular recently discovered single-byte vulnerability of -bsd-ftpd was fixed, some better sanity checking around seteuid(), -setegid() and fork() was added. Was fixed against the recursive LIST/NLST -problems which alot of FTP servers are vulnerable to, including BSD-FTPd -at the time. Now only requires a single configuration file (/etc/ftpusers) -for all account options, and users MUST be present in it to be allowed -FTP access (contrary to traditional behavior). The configuration file now -uses one user per line, and one column per user configurable option. -

-Support for read-only accounts, umask specification and homedir total size -limits on a per/user basis and number of connections per user was added, -note that the tree size quotas are only safe if only one simultaneous logins -of that user are allowed. Shared memory and semaphores would have been -required otherwise which would have strongly impacted performance. -This is not the case for mmftpd where threads are used and quotas are -safe no matter what. The server was modified to only accept to be launched -by the superuser. -

-The following command switches/parameters were added when starting the -daemon: -q to not display ftpd type/version to clients, -n to not resolve -hostnames for speed, -x to allow masquerading actual LAN IP address to -0.0.0.0 for passive replies (not that not all clients will work, I -recommend using mmtcpfwd passive FTP proxying to masquerade those to -the actual gateway's IP address instead, where all clients will work. -Finally, -q was added to specify which port to listen to. -

-
-
-
-Languages
-
-English 
French 
-

-

Mirrors
-
-Canada 
United-States 
Holland 
-

- -$Id: software.html,v 1.15 2003/12/12 15:58:39 mmondor Exp $
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED. -
- diff --git a/tests/entropy/README b/tests/entropy/README deleted file mode 100644 index 96844b5..0000000 --- a/tests/entropy/README +++ /dev/null @@ -1,12 +0,0 @@ -Attempts to generate enough rnd(4) entropy on NetBSD systems using -CGD for encrypted swap. Using it on a laptop. - -This implentation uses pseudo-random reads on a hard disk device -in order to hopefully cause the rnd(4) device (which is among other -devices fed by the wd* and sd* devices) to be fed entropy caused -by unstability features of the heads. - -The program can be launched before starting the encrypted builds, -then mounting the wanted CGD devices can be made, which shouldn't -cause a lockup anymore while cgdconfig(8) creates random the -cryptography keys with /dev/random. The program can then be killed. diff --git a/tests/entropy/entropy_disk.c b/tests/entropy/entropy_disk.c deleted file mode 100644 index fc5f154..0000000 --- a/tests/entropy/entropy_disk.c +++ /dev/null @@ -1,629 +0,0 @@ -/* $Id: entropy_disk.c,v 1.6 2007/02/15 21:17:31 mmondor Exp $ */ - -/* - * Copyright (c) 2006 Pulsar-Zone, Reg. - * All rights reserved. - * - * Written by Matthew Mondor for Pulsar-Zone, Reg. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project by - * Pulsar-Zone, Reg. - * 4. The name of Pulsar-Zone, Reg. may not be used to endorse - * or promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY PULSAR-ZONE, REG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PULSAR-ZONE, REG - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Strategy: - * - * 1) First obtain wd* or sd* devices using sysctl(3) which could be used to - * produce entropy. Error and exit if no such devices can be used. - * 2) Report our PID and detach, allowing SIGTERM to kill us. - * 3) In an endless loop, read various arbitrary blocks of random lenghts and - * at random positions from random disks. We take care to toggle the - * reading direction often enough to give the heads an opportunity to seek - * in both directions. - * 4) Upon receiving a SIGTERM signal, close the disk devices and exit. - * - * To obtain rather decent random values, we use the 4.2BSD random(3) PRNG - * but seed it using /dev/urandom. This prevents sucking up too much entropy - * from rnd(4), which we're designed to fill rather than waste, afterall. - * We periodically reseed the PRNG with /dev/urandom during the main loop as - * well. - * - * XXX Consider using arc4random(3) instead. However, possible problems could - * occur using it: it could void rnd(4) entropy, especially that at least - * 1024 bytes of the arcfour keystream should be discarded to be random - * enough. - * - * XXX Possibly add an option to tell the daemon to automatially exit after a - * certain number of seconds or minutes elapsed. We would use setitimer(2) - * to receive a SIGALRM, acting the same as for SIGTERM upon its reception. - * - * XXX Make lseek(2)/read(2) errors silent via compile time option to not - * disclose any information in case of disk problems for a final version of - * this program. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* - * Minimum block size to read (could be disk dependent but it doesn't matter - * much for this task. - */ -#define BLOCK_SIZE 16384 -/* - * Maximum number of BLOCK_SIZE blocks to read in a single read(2) - */ -#define BLOCK_MULTIPLE 16 -/* - * Minimum and maximum number of reads to perform in a single direction before - * switching direction. If these are too low the disk head thrashing could be - * excessive. - */ -#define DIRECTION_MIN 256 -#define DIRECTION_MAX 4096 -/* - * Minimum and maximum reseeding of PRNG from urandom(4) frequency (in reads). - * If we set these this too low, the entropy we're trying to accumulate in - * rnd(4) is sucked out as we create it, causing us to loop indefinitely for - * nothing. - */ -#define RESEED_MIN 32 -#define RESEED_MAX 256 - -enum direction { - DIR_FORWARD = 0, - DIR_BACKWARDS = 1 -}; - -typedef struct drive_entry { - SLIST_ENTRY(drive_entry) chain; - char *name; - off_t max, pos; - int fd; - int dir, dircnt; -} disk_t; - -SLIST_HEAD(slisthead, drive_entry); - -#define BALIGN_CEIL(v, s) ((((size_t)(v)) + (s) - 1) / (s) * (s)) - - - -int main(int, char **); - -static int prng_init(void); -static void prng_reseed(void); -static void prng_close(void); -static void signal_handler(int); -static int detach(const char *); -static void disk_open(const char *); -static int disks_open(void); -static void disks_close(void); -static void *buffer_alloc(size_t); -static void buffer_free(void *, size_t); - - - -static char *pidfile = "/var/run/entropy_disk.pid"; -static int maxdisks = 4; - -static struct slisthead disks_list = SLIST_HEAD_INITIALIZER(drive_entry); -static int ndisks = 0; -static disk_t **disks_array = NULL; - -static int urandom = -1; -static int reseed = 0; - -static size_t pagesize = 0; - -static int run = 1; - - - -int -main(int argc, char **argv) -{ - char c; - void *readbuf; - int ret = EXIT_FAILURE; - - setprogname(argv[0]); - - /* Parse commad line arguments */ - while ((c = getopt(argc, argv, "p:n:?")) != -1) { - switch (c) { - case 'p': - pidfile = optarg; - break; - case 'n': - maxdisks = strtol(optarg, NULL, 10); - if (maxdisks < 1 || maxdisks > 100) { - (void) fprintf(stderr, - " must be between 1 and 100\n"); - return EXIT_FAILURE; - } - break; - case '?': - /* FALLTHROUGH */ - default: - (void) fprintf(stderr, - "Usage: %s [-p ] [-n ]\n", - getprogname()); - return EXIT_FAILURE; - } - argc -= optind; - argv += optind; - } - - /* - * Initialization - */ - if (prng_init() != 0) - return EXIT_FAILURE; - - if (disks_open() != 0) - return EXIT_FAILURE; - - if ((readbuf = buffer_alloc(BLOCK_SIZE * BLOCK_MULTIPLE)) == NULL) - goto end; - if (detach(pidfile) != 0) - goto end; - - /* Main loop */ - while (run) { - disk_t *e; - int blocks; - unsigned long diff; - - /* Choose a disk */ - e = disks_array[random() % ndisks]; - - /* Choose a block size */ - blocks = random() % BLOCK_MULTIPLE; - - /* - * Choose a position relative to a previous one and doesn't - * exceed e->max (which already accounts for the block size - * and is already BLOCK_SIZE aligned). Our new position must - * also be BLOCK_SIZE aligned. - */ - diff = BALIGN_CEIL(random() % (e->max / DIRECTION_MIN), - BLOCK_SIZE); - if (e->dir == DIR_BACKWARDS) { - if ((e->pos -= diff) < 0) - e->dir = DIR_FORWARD; - } - if (e->dir == DIR_FORWARD) - e->pos = BALIGN_CEIL((e->pos + diff) % (e->max + 1), - BLOCK_SIZE); - if (--e->dircnt < 0) { - e->dir = (e->dir == DIR_FORWARD ? - DIR_BACKWARDS : DIR_FORWARD); - e->dircnt = DIRECTION_MIN + - (random() % (DIRECTION_MAX - DIRECTION_MIN)); - } - - /* Seek and read block(s) */ - if (lseek(e->fd, e->pos, SEEK_SET) != -1) { - if (read(e->fd, readbuf, blocks * BLOCK_SIZE) != - blocks * BLOCK_SIZE) - (void) fprintf(stderr, - "read(%s, %llu, %u): %s\n", - e->name, e->pos, blocks * BLOCK_SIZE, - strerror(errno)); - } else - (void) fprintf(stderr, - "lseek(%s, %llu): %s\n", - e->name, e->pos, strerror(errno)); - - /* Sleep for a slight random delay */ - (void) usleep(random() % 1000); - - /* Reseed PRNG out of /dev/urandom periodically */ - prng_reseed(); - } - - ret = EXIT_SUCCESS; - /* FALLTHROUGH */ - -end: - /* Cleanup */ - if (readbuf != NULL) - buffer_free(readbuf, BLOCK_SIZE * BLOCK_MULTIPLE); - (void) unlink(pidfile); - disks_close(); - prng_close(); - - return ret; -} - -/* - * Seed 4.2BSD random(3) using rnd(4)'s /dev/urandom - */ -static int -prng_init(void) -{ - unsigned long seed; - - if ((urandom = open("/dev/urandom", O_RDONLY)) == -1) { - (void) fprintf(stderr, - "open(/dev/urandom): %s\n", strerror(errno)); - goto err; - } - if (read(urandom, &seed, sizeof(seed)) != sizeof(seed)) { - (void) fprintf(stderr, - "read(/dev/urandom): %s\n", strerror(errno)); - goto err; - } - - srandom(seed); - reseed = RESEED_MIN + (random() % (RESEED_MAX - RESEED_MIN)); - - return 0; - -err: - if (urandom != -1) { - (void) close(urandom); - urandom = -1; - } - - return -1; -} - -static void -prng_reseed(void) -{ - unsigned long seed; - - if (--reseed < 1) { - if (read(urandom, &seed, sizeof(seed)) != sizeof(seed)) { - (void) fprintf(stderr, - "read(/dev/urandom): %s\n", strerror(errno)); - } - srandom(seed); - reseed = RESEED_MIN + (random() % (RESEED_MAX - RESEED_MIN)); - } -} - -static void -prng_close(void) -{ - - if (urandom != -1) { - (void) close(urandom); - urandom = -1; - } -} - -/* - * Called upon reception of SIGTERM - */ -static void -signal_handler(int sig) -{ - - switch (sig) { - case SIGTERM: /* FALLTHROUGH */ - default: - run = 0; - } -} - -/* - * Become a background daemon and write our PID file. - * Returns 0 on success or -1 on error. - */ -static int -detach(const char *pidfile) -{ - pid_t pid; - int fd; - struct sigaction act; - - if ((pid = fork()) == -1) - return -1; - if (pid != 0) - exit(EXIT_SUCCESS); - - /* Create PID file */ - if ((fd = open(pidfile, O_CREAT | O_TRUNC | O_WRONLY, 0600)) != -1) { - char str[16]; - - (void) snprintf(str, 15, "%d\n", getpid()); - if (write(fd, str, strlen(str)) == -1 || close(fd) == -1) { - (void) fprintf(stderr, - "Error writing PID file [%s]: %s\n", - pidfile, strerror(errno)); - return -1; - } - } else { - (void) fprintf(stderr, - "Error creating PID file [%s]: %s\n", - pidfile, strerror(errno)); - return -1; - } - - /* Be paranoid, redirect our stdio file descriptors to null(4) */ - (void) setsid(); - (void) chdir("/"); - if ((fd = open("/dev/null", O_RDWR)) != -1) { - (void) dup2(fd, STDIN_FILENO); - (void) dup2(fd, STDOUT_FILENO); - /* Keep stderr */ - if (fd > STDERR_FILENO) - (void) close(fd); - } - - /* Set our SIGTERM handler and ignore some signals */ - act.sa_handler = signal_handler; - act.sa_flags = 0; - (void) sigemptyset(&act.sa_mask); - (void) sigaction(SIGTERM, &act, NULL); - act.sa_handler = SIG_IGN; - (void) sigaction(SIGTTOU, &act, NULL); - (void) sigaction(SIGTTIN, &act, NULL); - (void) sigaction(SIGTSTP, &act, NULL); - - return 0; -} - -/* - * Attempts to open specified disk device and on success adds a new disk_t - * entry to the disks_list. Logs any errors to stderr. - */ -static void -disk_open(const char *dname) -{ - disk_t *e; - char devname[16]; - - if ((e = malloc(sizeof(disk_t))) == NULL) { - (void) fprintf(stderr, - "malloc(%d): %s\n", sizeof(disk_t), strerror(errno)); - goto err; - } - if ((e->name = strdup(dname)) == NULL) { - (void) fprintf(stderr, - "strdup(%d): %s\n", strlen(dname), strerror(errno)); - goto err; - } - - (void) snprintf(devname, 16, "/dev/r%sd", dname); - if ((e->fd = open(devname, O_RDONLY)) == -1) { - (void) fprintf(stderr, - "open(%s): %s\n", devname, strerror(errno)); - goto err; - } - - /* - * Although we could use an ioctl(2) to read the label of the device, - * using lseek(2) is simpler. If it generates head movement, it's all - * for the better. - */ - if (lseek(e->fd, 0, SEEK_END) == -1) { - (void) fprintf(stderr, - "lseek(%s): %s\n", devname, strerror(errno)); - goto err; - } - if ((e->max = lseek(e->fd, 0, SEEK_SET)) == -1) { - (void) fprintf(stderr, - "lseek(%s): %s\n", devname, strerror(errno)); - goto err; - } - /* - * Substract so that any position is valid for reading up to - * BLOCK_SIZE * BLOCK_MULTIPLE bytes. We also ensure that size - * is always a multiple of BLOCK_SIZE. - */ - e->max = BALIGN_CEIL(e->max - (BLOCK_SIZE * BLOCK_MULTIPLE), - BLOCK_SIZE); - - /* Set a random but valid start position, BLOCK_SIZE aligned. */ - e->pos = BALIGN_CEIL(((off_t)random() * (off_t)random()) % - (e->max + 1), BLOCK_SIZE); - - /* And a random direction/count */ - e->dir = random() % 2; - e->dircnt = DIRECTION_MIN + - (random() % (DIRECTION_MAX - DIRECTION_MIN)); - - SLIST_INSERT_HEAD(&disks_list, e, chain); - ndisks++; - return; - -err: - if (e != NULL) { - if (e->name != NULL) - free(e->name); - if (e->fd != -1) - (void) close(e->fd); - free(e); - } -} - -/* - * Queries sysctl(3) for wd* and sd* drive names and opens the devices. - * Returns 0 on success or -1 on failure. - */ -static int -disks_open(void) -{ - int mib[] = { CTL_HW, HW_DISKNAMES }; - char buf[1024], *cptr, *sptr; - size_t size = sizeof(buf); - - /* Query local disks */ - if (sysctl(mib, 2, buf, &size, NULL, 0) != 0) { - (void) fprintf(stderr, - "Error querying sysctl(3) for disk names: %s\n", - strerror(errno)); - goto err; - } - - /* Open for each sd(4) or wd(4) disk reported, up to maxdisks */ - /* XXX We actually could use strsep(3) easily here as well */ - for (cptr = buf, ndisks = 0; ndisks < maxdisks; ) { - for (; *cptr != '\0' && *cptr == ' '; cptr++) ; - if (*cptr == '\0') - break; - sptr = cptr; - for (; *cptr != '\0' && *cptr != ' '; cptr++) ; - if (*cptr == '\0') - break; - *cptr++ = '\0'; - if ((sptr[0] == 's' || sptr[0] == 'w') && - sptr[1] == 'd') - disk_open(sptr); - } - - if (ndisks == 0) { - (void) fprintf(stderr, - "No sd(4) or wd(4) disks to generate entropy from\n"); - goto err; - } - - /* Initialize fast index array */ - if ((disks_array = malloc(sizeof(disk_t *) * ndisks)) == NULL) { - (void) fprintf(stderr, - "malloc(%d): %s\n", sizeof(disk_t *) * ndisks, - strerror(errno)); - goto err; - } - { - int i = 0; - disk_t *e; - - SLIST_FOREACH(e, &disks_list, chain) - disks_array[i++] = e; - } - - return 0; - -err: - disks_close(); - - return -1; -} - -/* - * Closes any open drive devices if any. - */ -static void -disks_close(void) -{ - disk_t *e; - - if (disks_array != NULL) - free(disks_array); - - while (!SLIST_EMPTY(&disks_list)) { - e = SLIST_FIRST(&disks_list); - SLIST_REMOVE_HEAD(&disks_list, chain); - if (e->fd != -1) - (void) close(e->fd); - if (e->name != NULL) - free(e->name); - free(e); - } - - ndisks = 0; -} - -/* - * Allocate a wired memory buffer. - */ -static void * -buffer_alloc(size_t size) -{ - void *buf = NULL; - - if (pagesize == 0) { - if ((pagesize = (size_t)sysconf(_SC_PAGESIZE)) == -1) { - perror("sysconf(_SC_PAGESIZE)"); - goto err; - } - } - - size = (size_t)BALIGN_CEIL(size, pagesize); - - if ((buf = mmap(NULL, size, PROT_WRITE, MAP_ANON, -1, 0)) == - MAP_FAILED) { - (void) fprintf(stderr, - "mmap(%d): %s\n", size, strerror(errno)); - buf = NULL; - goto err; - } - if (mlock(buf, size) == -1) { - perror("mlock()"); - goto err; - } - if (madvise(buf, size, MADV_WILLNEED) == -1) { - perror("madvise()"); - goto err; - } - - return buf; - -err: - if (buf != NULL) { - (void) munlock(buf, size); - (void) munmap(buf, size); - } - - return NULL; -} - -/* - * Free a previously allocated wired buffer. - */ -static void -buffer_free(void *buf, size_t size) -{ - - assert(pagesize != 0 && buf != NULL); - - size = (size_t)BALIGN_CEIL(size, pagesize); - - (void) memset(buf, 0, size); - (void) munlock(buf, size); - (void) munmap(buf, size); -} diff --git a/tests/js-test/README b/tests/js-test/README deleted file mode 100644 index 5922bc8..0000000 --- a/tests/js-test/README +++ /dev/null @@ -1,7 +0,0 @@ -$Id: README,v 1.3 2006/07/22 04:47:43 mmondor Exp $ - -Note that this was a test tree only. The current code which is in use -can be found under /cvsroot/mmondor/mmsoftware/js/ - -Thanks, -Matt diff --git a/tests/js-test/js/copy.js b/tests/js-test/js/copy.js deleted file mode 100644 index 49dcc82..0000000 --- a/tests/js-test/js/copy.js +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id: copy.js,v 1.2 2005/07/01 13:11:08 mmondor Exp $ */ - -/* - * Test our read() and write() methods, mapping to unix read(2) and write(2). - * Seems to be working great so far. - */ - -src = '/tmp/src.bin' -dst = '/tmp/dst.bin' - -err = new FD(); -err.set(FD.STDERR_FILENO); - -srcfd = new FD(); -dstfd = new FD(); - -try { - srcfd.open(src, FD.O_RDONLY); - dstfd.open(dst, FD.O_WRONLY | FD.O_CREAT); - - var data; - - while (data = srcfd.read(16384)) { - if (data.length == 0) - break; - err.put('Copied ' + data.length + " bytes block\n"); - dstfd.write(data); - } - - srcfd.close(); - dstfd.fdatasync(); - dstfd.close(); -} catch (x) { - err.put(x + "\n"); -} - -err.close(); diff --git a/tests/js-test/js/fd.js b/tests/js-test/js/fd.js deleted file mode 100644 index 8e8f998..0000000 --- a/tests/js-test/js/fd.js +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: fd.js,v 1.5 2005/02/10 10:34:25 mmondor Exp $ */ - -var out = new FD(); -out.set(FD.STDOUT_FILENO); - -try { - - var fd = new FD(); - - { - var size; - - fd.open("/tmp/test.txt", FD.O_WRONLY | FD.O_CREAT); - size = fd.put("Yo!\n"); - out.put('Wrote bytes=' + size + ' to file="' + fd.path + - '", fd=' + fd.fd + ', created with mode=' + fd.mode + - "\n"); - fd.close(); - } - - { - var buf; - - fd.open("/tmp/test.txt", FD.O_RDONLY); - while (buf = fd.get()) - out.put(buf); - fd.close(); - } - -} catch (x) { - out.put(x + "\n"); -} - -out.put("done\n"); -out.close(); diff --git a/tests/js-test/js/game/objects.js b/tests/js-test/js/game/objects.js deleted file mode 100644 index 96fdfe7..0000000 --- a/tests/js-test/js/game/objects.js +++ /dev/null @@ -1,341 +0,0 @@ -/* $Id: objects.js,v 1.7 2005/11/25 07:38:35 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Primarily written in JavaScript for easy and quick prototyping/testing. - * May eventually be written in C afterwards if need be, but the game might - * actually be implemented in JavaScript too depending on future decisions. - */ - -/* - * Simple but rather realistic implementation of items and containers. - * We observe containers maximum allowed volume and weight, container neck - * size, as well as expandable containers, such as cloth bags which can expand - * to eventually fill their parent container too. We allow nestled - * containers. We also add the concept of arbitrary marks which a user might - * add to objects to differenciate them. Containers can be open or closed, - * and obviously need to be open for items to be added/removed from them. - * We flag containers as such to accept either only solids or liquids, or - * both. We could consider flowing sand or salt as a liquid in this case. - * - * XXX - * - For liquids, we might need to provide a special object or flag for them - * to be able to have a volume/weight ratio, so that we could perform - * actions easily such as fill bottles/bags, etc. - * - The code dealing with the container parents, weights and expanding volume - * containers needs to throughly be tested, both for success and failing - * cases of all kinds. - * - XXX FIXME XXX - * When removing items from a container, the container's weight becomes 0, - * as well as its volume if it is expandable. - */ - - - -/* - * Describes a game item or object. - */ - -/* Used so that every item has a unique index ID */ -var unique = 0; - -/* Content types */ -const CT_SOLID = (1 << 0); -const CT_LIQUID = (1 << 1); -/* And container type flag */ -const CT_EXPAND = (1 << 2); -/* If item cannot be taken */ -const CT_FIXED = (1 << 3); - -function Item(name, description, volume, weight, ctype) -{ - this.name = name; - this.description = description; - this.volume = volume; - this.weight = weight; - this.ctype = ctype; - - this.marks = []; - - this.index = ++unique; -} - -Item.prototype = { - isContainer: function() - { - return false; - }, - - getVolume: function() - { - return this.volume; - }, - - getWeight: function() - { - return this.weight; - }, - - mark: function(mark) - { - this.mark.push(mark); - } -}; - - -/* - * And an object to handle container Items, inheriting the Item object. - */ - -const E_OK = 0; -const E_TOOLARGE = "Item too large"; -const E_TOOHEAVY = "Item too heavy"; -const E_FIXED = "Item is well fixed and cannot move"; -const E_BADTYPE = "Item is not of proper type (solid vs liquid)"; -const E_SELF = "Item could not penetrate itself"; -const E_NONE = "Item not in container"; -const E_ALREADY = "Item already in container"; -const E_CLOSED = "Container is closed"; - -function ContainerItem(name, description, volume, weight, ctype, - con_neck, con_volume_max, con_weight_max, con_ctype) -{ - this.base = Item; - this.base(name, description, volume, weight, ctype); - - this.con_neck = con_neck; - this.con_volume_max = con_volume_max; - this.con_weight_max = con_weight_max; - this.con_volume_cur = this.con_weight_cur = 0; - this.con_ctype = con_ctype; - - this.con_items = {}; - this.con_items_cnt = 0; - this.con_open = false; -} - -ContainerItem.prototype = { - isContainer: function() - { - return true; - }, - - open: function() - { - this.con_open = true; - }, - - close: function() - { - this.con_open = false; - }, - - getVolume: function() - { - /* - * Objects which expand, such as bags, need to report proper - * volume relating to the volume of the objects they hold. - * Objects which do not expand, such as boxes or bottles, - * need to always report the same volume. - */ - return ((this.con_ctype & CT_EXPAND) != 0) ? - this.volume + this.con_volume_cur : - this.volume; - }, - - getWeight: function() - { - return this.weight + this.con_weight_cur; - }, - - items: function() - { - return this.con_items_cnt; - }, - - add: function(item) - { - /* We can't accept fixed items */ - if ((item.ctype & CT_FIXED) != 0) - return E_FIXED; - - /* Can only add items to open container */ - if (!this.con_open) - return E_CLOSED; - - /* We can't add ourself in :) */ - if (item.index == this.index) - return E_SELF; - - /* Nor items which are already inside */ - if (this.con_items[item.index] != undefined) - return E_ALREADY; - - /* We only accept items of proper type */ - if ((this.con_ctype & item.ctype) == 0) - return E_BADTYPE; - - /* We can only hold objects which are small enough */ - if (this.con_neck < item.getVolume()) - return E_TOOLARGE; - if (this.con_volume_cur + item.getVolume() > - this.con_volume_max) - return E_TOOLARGE; - - /* We can only hold objects which are light enough */ - if (this.con_weight_cur + item.getWeight() > - this.con_weight_max) - return E_TOOHEAVY; - - this.con_volume_cur += item.getVolume(); - this.con_weight_cur += item.getWeight(); - - /* - * The weight has to propagate to parent containers. - * The volume also has, in the case where containers - * are expandable. - * We need to observe the maximum allowed volume and weight - * of all parent containers as well. - * We need to climb through the parents list to do this. - * Moreover, we need to actually reverse any changes made - * to the parents in case of any volume/weight exceeded. - */ - var err = E_OK; - for (var o = this.con_parent; o != undefined; - o = o.con_parent) { - if (o.getWeight() + this.getWeight() > - o.con_weight_max) { - err = E_TOOHEAVY; - break; - } - o.con_weight_cur += this.getWeight(); - if ((o.con_ctype & CT_EXPAND) != 0) { - if (o.getVolume() + this.getVolume() > - o.con_volume_max) { - err = E_TOOLARGE; - break; - } - o.con_volume_cur += this.getVolume(); - } - } - if (err != E_OK) { - for (var t = this.con_parent; t != o; - t = t.con_parent) { - t.con_weight -= this.getWeight(); - if ((t.con_ctype & CT_EXPAND) != 0) - t.con_volume_cur -= this.getVolume(); - } - if (err == E_TOOLARGE) - o.con_weight_cur -= this.getWeight(); - - this.con_volume_cur -= item.getVolume(); - this.con_weight_cur -= item.getWeight(); - - return err; - } - - if (item.isContainer()) - item.con_parent = this; - this.con_items[item.index] = item; - this.con_items_cnt++; - - return E_OK; - }, - - remove: function(item) - { - /* Can only remove items from open container */ - if (!this.con_open) - return E_CLOSED; - - /* We can only remove items which are really inside */ - if (this.con_items[item.index] == undefined) - return E_NONE; - - /* - * Climb up our parents containers list to update them - */ - for (var o = this.con_parent; o != undefined; - o = o.con_parent) { - o.con_weight_cur -= this.getWeight(); - if ((o.con_ctype & CT_EXPAND) != 0) - o.con_volume_cur -= this.getVolume(); - } - - if (item.isContainer()) - delete item.con_parent; - this.con_weight_cur -= item.getWeight(); - this.con_volume_cur -= item.getVolume(); - delete this.con_items[item.index]; - this.con_items_cnt--; - - return E_OK; - }, - - inventory: function(level) - { - print(' - ' + level + - ': name=' + this.name + - ' volume=' + this.getVolume() + - ' weight=' + this.getWeight()); - - if (!this.con_open) - return 'already_open!'; - - level++; - for (var i in this.con_items) { - /* - if (this.con_items[i] == undefined) - continue; - */ - print(level + - ': name=' + this.con_items[i].name + - ' volume=' + this.con_items[i].getVolume() + - ' weight=' + this.con_items[i].getWeight()); - if (this.con_items[i].isContainer()) - this.con_items[i].inventory(level); - } - level--; - } -}; - - - -/* - * Some testing in order - */ - -/* Create an item */ -var i = new Item('a ring', 'the one ring', 5, 5, CT_SOLID); - -/* Create a container item */ -var c = new ContainerItem('a bag', 'a soft cloth bag', 5, 5, CT_SOLID, - 10, 15, 20, CT_SOLID | CT_EXPAND); - -/* Create a second container item */ -var c2 = new ContainerItem('another bag', 'another soft cloth bag', 5, 5, - CT_SOLID, 10, 15, 20, CT_SOLID | CT_EXPAND); - -print(); -c2.inventory(0); -print(); - -c.open(); -print(c.add(i)); -c.close(); -c2.open(); -print(c2.add(c)); -c2.close(); - -c.open(); -c2.open(); -c2.inventory(0); -c.remove(i); -c2.remove(c); - -print(); -c2.inventory(0); diff --git a/tests/js-test/js/httpd/httpd.js b/tests/js-test/js/httpd/httpd.js deleted file mode 100644 index 0b24dac..0000000 --- a/tests/js-test/js/httpd/httpd.js +++ /dev/null @@ -1,1679 +0,0 @@ -/* $Id: httpd.js,v 1.74 2005/12/17 00:13:12 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Little example showing the versatility of ECMAScript, provided with a - * custom library for BSD socket support, using SpiderMonkey. - * This tiny HTTPd allows simultaneous concurrent client connections without - * using multiple threads or processes. Must be ran through - * ../../src/js-server. - * - * Configuration options can be found in options.js - * - * XXX Possibly that with close var semantics changes or such, we could - * support Keep-Alive for HTTP/1.1 connections. This however is not a - * priority at current time. - * - * TODO: - * - There is a problem if the remote socket closes when we're sending - * alot of data, poll(2) apparently doesn't always save us from this - * despite checking POLLHUP/POLLERR events. A SIGPIPE signal is sent - * to the process, and we must be able to handle some common signals. - * This would also allow an opportunity for applications to register - * server cleanup handlers when SIGTERM is received, i.e. to save to - * disk in-memory cached data, etc. - * We probably should ensure to block the signal when executing the - * user function for an occurred signal... - * - Read http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - * and see if we meet conformance, adjust as needed. - * - We might want to check Accept-Language: for multilingual sites... - * - See what to do for HEAD and PUT - * - Possibly limit rate of connections per address like I did in - * mmftpd/mmsmtpd/mmpop3d/mmspawnd, a requested feature of 3s4i. - * If enabling this, it probably should be per-vhost configurable. - * I'm not sure HTTP protocol is well suited to this type of limiting, - * some testing will be required. - * - Provide a function to scripts to redirect to another page. - * - We might want vhost-specific default login page, and provide - * an easy means in the server to have non-authenticated users automatically - * redirected to that page using server-side magic. A special session - * variable should be used for this, and registered when the user logins. - * - Similar to the above, but should be special provision for scripts to - * easily specify their required access level, which must be met by a - * currently logged in user, which is otherwise redirected to an - * application-specific page. - * - Implement logging - * - It might be nice to implement a minimal database-like facility, where - * for performance we could log changes, and only sync to disk once in a - * while, discarding obsolete logs... JSON would be used - * - Enhance the JS shell to report errors better - * - We should have support for easy storage and safe export of files, - * like I implemented for ascpi.com. This is useful for instance to - * store and post user profile images and related thumbnail, etc. - */ - - - -/* - * Server identification - */ -SERVER_VERSION = 'mmondor_js_httpd/0.0.1 (NetBSD)'; -SERVER_CVSID = '$Id: httpd.js,v 1.74 2005/12/17 00:13:12 mmondor Exp $'; - - - -/* - * Open standard error FD for diagnostics output - */ -err = new FD(); -err.set(FD.STDERR_FILENO); - - - -/* - * Import needed functionality from external modules, since #include is - * missing :) - */ -function file_read(file) -{ - var contents = ''; - var data; - var fd; - - try { - /* - * If we were provided with a filename, rather than a - * filedescriptor object, open the filename. Otherwise, - * read from the specified FD. - */ - if (typeof file != 'object') { - fd = new FD(); - fd.open(file, FD.O_RDONLY); - } else - fd = file; - } catch (x) { - err.put(x + " at file_read()\n"); - } - - try { - for (;;) { - data = fd.read(65536); - if (data.length == 0) - break; - contents += data; - } - } catch (x) { - err.put(x + " at file_read()\n"); - } - - fd.close(); - - return contents; -} - -try { - eval(file_read('options.js')); /* Configuration */ -} catch (x) { - err.put(x + " while reading options file\n"); - exit(); -} -eval(file_read('string.js')); /* startsWith()/endsWith() */ -eval(file_read('ml.js')); /* MLTag object for HTML generation */ -eval(file_read('root.js')); /* Root object for virtual chroot(2) */ - - - -/* - * Client states (enumeration) - */ -const STATE_TRANSFER_READ = 1; -const STATE_TRANSFER_WRITE = 2; - - - -/* - * Quick lookup object from virtual hosts names and aliases to VHost objects - */ -var vhosts_table = {}; -var default_vhost = undefined; - -/* - * The VHost object - */ -function VHost(o) -{ - /* - * A few properties are definitely required - */ - if (o.name == undefined || o.root == undefined) - throw ('name and root properties missing from vhost'); - o.name = o.name.toLowerCase(); - this.name = o.name; - - if (o.scripts != undefined && o.scripts == true) { - this.scripts = true; - this.globals = {}; - } - - /* - * Create VHost object - */ - try { - this.htdocs_root = new Root(o.root); - } catch (x) { - throw (x); - } - - if (o.charset != undefined) - this.charset = o.charset; - if (o.session_exp != undefined) - this.session_exp = o.session_exp; - - /* - * Link object to vhosts table - */ - if (vhosts_table[o.name] != undefined) - throw ('Conflicting vhost name: ' + o.name); - vhosts_table[o.name] = this; - - if (o.aliases != undefined) { - for (i in o.aliases) { - o.aliases[i] = o.aliases[i].toLowerCase(); - if (vhosts_table[o.aliases[i]] != undefined) - throw ('Conflicting vhost alias: ' + - o.aliases[i]); - vhosts_table[o.aliases[i]] = this; - } - } -} - - - -/* - * The Session object allows to maintain persistent session variables among - * multiple client queries. We are using a cookie with the unique session ID - * to link those queries together into a session. - */ - -var o = new FD(); -o.set(FD.STDOUT_FILENO); - -var session_randfd = new FD(); -try { - session_randfd.open('/dev/urandom', FD.O_RDONLY); -} catch (x) { - err.put(x + " while attempting to open /dev/urandom\n"); - exit(); -} - -var session_charlist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + - 'abcdefghijklmnopqrstuvwxyz' + - '0123456789-_'; - -var sessions_table = {}; - -/* - * To be called at regular but spaced intervals, - * destroys expired session objects. - */ -function session_gc(time) -{ - var i; - - for (i in sessions_table) { - if (sessions_table[i].expires <= time) - delete sessions_table[i]; - } -} - -function Session(time, exp) -{ - var rval; - var i; - - try { - rval = session_randfd.read(options.sess_id_size); - } catch (x) { - err.put(x + " while attempting to read from /dev/urandom\n"); - } - this.sessid = ''; - for (i = 0; i < options.sess_id_size; i++) - this.sessid += - session_charlist.charAt(rval.charCodeAt(i) & 0x3f); - - this.variables = {}; - this.expires = time + exp; - sessions_table[this.sessid] = this; -} - - - -/* - * For the mime types database - */ - -var mimetypes_table = {}; - - - -/* - * And our pre-evaluated scripts cache - */ -var jso_cache = {}; - -function JSO(path, time, script) -{ - this.path = path; - this.time = time; - this.script = script; - - jso_cache[this.path] = this; -} - - - -/* - * The HTTPReply object allows to cache addHeader() and addContent() requests, - * and to eventually flush the whole reply to an arbitrary FD afterwards. - */ - -/* - * Constructor - */ -function HTTPReply(code, desc, type) -{ - this.code = code; - this.desc = desc; - this.headers = []; - this.contents = []; - this.type = type; - - /* - * Insert our standard headers. - */ - this.gmttime = (new Date()).toGMTString(); - this.headers.push('Date: ' + this.gmttime); - this.headers.push('Server: ' + SERVER_VERSION); - this.headers.push('Connection: close'); - this.headers.push('Accept-Ranges: bytes'); -} -/* - * HTTPReply prototype object - */ -HTTPReply.prototype = { - setType: function(type) - { - - this.type = type; - }, - - addHeader: function(data) - { - - this.headers.push(data); - }, - - addNoCacheHeaders: function() - { - - this.headers.push('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); - this.headers.push('Last-Modified: ' + this.gmttime); - this.headers.push('Cache-Control: no-cache, must-revalidate'); - this.headers.push('Pragma: no-cache'); - }, - - addContent: function(data) - { - - this.contents.push(data); - }, - - flush: function(fd, size) - { - var headers = ''; - var contents = ''; - var i; - - for (i = 0; i < this.contents.length; i++) - contents += this.contents[i]; - - this.headers.push('Content-Length: ' + - (size == null ? contents.length : size)); - headers += 'HTTP/1.1 ' + this.code + ' ' + this.desc + "\r\n"; - for (i = 0; i < this.headers.length; i++) - headers += this.headers[i] + "\r\n"; - if (this.type != null) - headers += 'Content-Type: ' + this.type + "\r\n"; - headers += "\r\n"; - - try { - if (!fd.http_old_get) - fd.bwrite(headers + contents); - else - fd.bwrite(contents); - } catch (x) {} - } -} - -/* - * Generates an error page and sends it to specified FD object. - */ -function http_error(fd, code, desc, ldesc) -{ - var res = new HTTPReply(code, desc, 'text/html; charset=' + - options.default_charset); - res.addNoCacheHeaders(); - - res.addContent('' + code + ' ' + desc + - '

' + code + ' ' + desc + '

' + - '

' + ldesc + '


'); - - res.addContent(fd.httpDebug()); - - res.addContent('
' + SERVER_VERSION + '
' + SERVER_CVSID + - '
'); - - res.flush(fd, null); - delete res; -} - - - -/* - * Add new methods to the FD prototype object (JavaScript is great like that). - * We need to add these properties one by one to the prototype object of FD, - * since we wouldn't want to override its default prototype, just expand it. - */ - -/* - * Handles request query processing, to be assigned to FD.process() while in - * the request query state. This then invokes parseRequest() which may - * either send an HTTP response and/or cause a switch to another state. - */ -function process_query(time) -{ - var len; - var done = false; - var close = false; - var idx; - var data; - - /* - * If we reach a request of 32768 bytes, stop reading. - * If there is no request terminating line within - * that buffer, close connection. - * - * On read error, close connection. - * - * If we do find request terminating line, parse query - * to modify state accordingly, and let the parsing - * method decide if we'll close the connection. - */ - len = 32768 - this.request_data.length; - if (len < 1) { - done = true; - close = true; - } else { - try { - data = this.read(len); - if (data.length == 0) - close = true; - this.request_data += data; - this.updateTimeout(time); - } catch (x) { - if (this.errno != Errno.EAGAIN) - close = true; - } - } - if ((idx = this.request_data.indexOf("\r\n\r\n")) != -1) - done = true; - else if (!this.checked_old && - (idx = this.request_data.indexOf("\r\n")) != -1) { - var w; - - this.checked_old = true; - if ((w = (this.request_data.substr(0, idx)).split(' ')). - length == 2 && w[0] == 'GET') { - /* - * Old-style HTTP request, we need to respond - * immediately in this case without any headers. - */ - done = true; - } - } - - if (done && !close) { - /* - * Store remaining of buffer after "\r\n" so that we may - * be able to process POST for instance, without needing - * to read one char at a time here. - * Then call our request parsing function. - */ - idx += 4; - this.bread_buffer = this.request_data.substr(idx); - this.request_data = this.request_data.substr(0, idx); - close = this.parseRequest(time); - } - - return close; -} - -function process_post(time) -{ - var close = false; - var len; - var data; - - if (this.post_data.length < this.http_content_length) { - len = this.http_content_length - this.post_data.length; - if (len > options.readbuf_size) - len = options.readbuf_size; - try { - data = this.read(len); - if (data.length == 0) - close = true; - this.post_data += data; - this.updateTimeout(time); - } catch (x) { - if (this.errno != Errno.EAGAIN) - close = true; - } - } else - close = this.parsePost(time); - - return close; -} - -/* - * Handles transfer processing, to be assigned to FD.process() while in the - * transfer state. - */ -function process_transfer(time) -{ - var close = false; - - /* - * STATE_TRANSFER_READ specifies that we're reading to the - * buffer from transfer_src, or writing from the buffer - * to transfer_dst (STATE_TRANSFER_WRITE). We can do - * both steps one after another if possible. - * On EAGAIN errors, simply pass our turn to go back to - * polling. On EOF reading from either end, exit transfer - * state after writing to the other and syncing/closing, - * and order to close client descriptor. - * We take care not to transfer more than this.transfer_size bytes - * outbound. - * XXX We might also want to observe it for inbound, where it could - * be set to the user-provided Content-Length... for PUT ? - */ - if (this.transfer_state == STATE_TRANSFER_READ) { - if (this == this.transfer_src) { - /* Reading from client */ - try { - this.transfer_data = - this.read(options.readbuf_size); - if (this.transfer_data.length == 0) - this.transfer_eof = true; - this.transfer_state = STATE_TRANSFER_WRITE; - this.updateTimeout(time); - } catch (x) { - if (this.errno != Errno.EAGAIN) { - close = true; - try { - this.transfer_dst.fdatasync(); - } catch (x) {} - try { - this.transfer_dst.close(); - } catch (x) {} - } - } - } else { - /* Reading from file */ - var bufsiz = this.transfer_size; - if (bufsiz > options.readbuf_size) - bufsiz = options.readbuf_size; - try { - if (bufsiz > 0) - this.transfer_data = - this.transfer_src.read(bufsiz); - else - this.transfer_data = ''; - if (this.transfer_data.length == 0) - this.transfer_eof = true; - this.transfer_size -= - this.transfer_data.length; - this.transfer_state = STATE_TRANSFER_WRITE; - } catch (x) { - close = true; - try { - this.transfer_src.close(); - } catch (x) {} - } - } - } - if (this.transfer_state == STATE_TRANSFER_WRITE) { - if (this == this.transfer_dst) { - /* Writing to client */ - if (this.transfer_eof) - close = true; - else { - try { - this.bwrite(this.transfer_data); - this.transfer_state = - STATE_TRANSFER_READ; - this.updateTimeout(time); - } catch (x) { - if (this.errno != Errno.EAGAIN) - close = true; - } - } - if (close) { - try { - this.transfer_src.close(); - } catch (x) {} - } - } else { - /* Writing to file */ - if (this.transfer_eof) - close = true; - else { - try { - this.transfer_dst.write( - this.transfer_data); - this.transfer_state = - STAT_TRANSFER_READ; - } catch (x) { - close = true; - } - } - if (close) { - try { - this.transfer_dst.fdatasync(); - } catch (x) {} - try { - this.transfer_dst.close(); - } catch (x) {} - } - } - } - - return close; -} - -/* - * Updates input timeout expiration time for this FD. - * To be passed current time in seconds since epoch. - */ -FD.prototype.updateTimeout = function(time) -{ - /* Update input timeout expiration time */ - this.expires = time + options.io_timeout; -} - -/* - * Reset FD to a consistent known state, to use after accept(2). - * To be passed current time in seconds since epoch, and unique id to be used - * as an index. - */ -FD.prototype.init = function(time, idx) -{ - /* Not a bound socket */ - this.bound = false; - /* Initial state */ - this.transfer_state = STATE_TRANSFER_READ; - this.transfer_src = this.transfer_dst = null; - this.transfer_eof = false; - this.transfer_data = ''; - /* Empty request string */ - this.request_data = ''; - /* Unique index */ - this.index = idx; - /* - * Events interested in. FD.POLLOUT to be eventually used instead in - * transfer state if transfering from server to client. - */ - this.events = FD.POLLIN; - /* - * Default handler to process this FD, the request state one. - * To be changed to the transfer one as needed for transfer state. - */ - this.process = process_query; - /* Initial input timeout */ - this.updateTimeout(time); - /* For process_request()/process_post() */ - this.bread_buffer = this.bwrite_buffer = ''; - /* - * Flag used to speed up request parsing related to old HTTP requests - */ - this.checked_old = false; - - /* - * Note that fcntl(2) and setsockopt(2) flags applied to the bound - * descriptors are inherited to their children sockets at accept(2). - * We therefore can save a few syscalls here. - * We are non-blocking already, for instance. - */ -} - -/* - * To be called once our client request has been read, to decide what action - * to perform and modify state accordingly. - */ -FD.prototype.parseRequest = function(time) -{ - var close = valid = false; - var evil_browser = evil_os = false; - var vhost = ''; - var lines; - var words; - var i; - var sessid, sess; - - this.http_protocol = ''; - this.http_method = ''; - this.http_vhost = undefined; - this.http_path = ''; - this.http_vars_get = {}; - this.http_vars_post = {}; - this.http_vars_cookies = {}; - this.http_agent = ''; - this.http_content_length = -1; - this.http_modified_since = undefined; - this.http_sessid = undefined; - this.http_vars_session = {}; - this.http_range = undefined; - this.http_old_get = false; - - /* Split request lines */ - lines = this.request_data.split("\r\n"); - - /* Verify if first line has a request which seems valid */ - if (lines.length > 0) { - words = lines[0].split(' '); - if (words.length == 2 && words[0] == 'GET') { - this.http_method = words[0]; - this.http_path = words[1]; - this.http_protocol = 'HTTP/1.1'; - this.http_old_get = true; - valid = true; - } else if (words.length == 3) { - if ((words[0] == 'GET' || words[0] == 'POST' || - words[0] == 'PUT') && (words[2] == 'HTTP/1.0' || - words[2] == 'HTTP/1.1')) { - this.http_method = words[0]; - this.http_path = words[1]; - this.http_protocol = words[2]; - valid = true; - } - } - } - - /* - * Parse header for interesting lines. - */ - if (valid && !this.http_old_get) { - for (i in lines) { - words = lines[i].split(' '); - if (words[0] == 'Host:' && words.length == 2) { - var i2; - - if ((i2 = words[1].indexOf(':')) != -1) - words[1] = words[1].substr(0, i2); - vhost = words[1]; - } else if (words[0] == 'Cookie:') { - words = (lines[i].substr(8)).split('='); - if (words.length == 2) - property_add(this.http_vars_cookies, - words[0], words[1]); - } else if (words[0] == 'User-Agent:') { - this.http_agent = lines[i].substr(12); - if (options.ban_msie == true && - this.http_agent.indexOf('MSIE') != -1) - evil_browser = true; - if (options.ban_windows == true && - this.http_agent.indexOf('Windows') != -1) - evil_os = true; - } else if (words[0] == 'Content-Length:' && - words.length == 2) - this.http_content_length = words[1].valueOf(); - else if (words[0] == 'If-Modified-Since:') - this.http_modified_since = Math.round( - Date.parse(lines[i].substr(19)) / 1000); - else if (words[0] == 'Range:') - this.http_range = lines[i].substr(7); - } - } - - /* - * If no Host: line set the vhost, set the default one. - * If there is a vhost set, but is unknown, also set the default one. - * Also set the name of the vhost to the actual vhost name despite - * it possibly being resolved through an alias. - */ - if (vhost == '' || vhosts_table[vhost] == undefined) - vhost = options.default_vhost; - this.http_vhost = vhosts_table[vhost.toLowerCase()]; - - if (this.http_old_get && this.http_vhost.scripts) { - /* - * We only allow old style GET request on static vhosts - */ - this.bwrite('' + - 'Unsupported Old-Style Request' + - '

Unsupported Old-Style Request

' + - 'Your browser sent an old-style HTTP request, which ' + - 'this server does not support on dynamic content ' + - 'virtual hosts. Use an HTTP/1.0 or HTTP/1.1 compliant ' + - 'client to continue.

' + "\r\n"); - return true; - } - - /* - * Filter out definitely invalid requests - */ - if (!valid) { - http_error(this, 400, 'Bad Request', - 'Your browser sent an invalid HTTP query.'); - return true; - } - - /* - * Block out evil Microsoft products. Start reporting the OS - * so that an unwanted windows user doesn't install another - * browser to then realize that his OS is banned nevertheless :) - */ - if (evil_os) { - http_error(this, 666, 'Evil Operating System Banished!', - 'Your Operating System is evil born.
At least ' + - 'upgrade to a ' + - 'decent OS to survive on these grounds.
'); - return true; - } else if (evil_browser) { - http_error(this, 666, 'Evil Browser Banished!', - 'Your browser is evil born.
At least ' + - 'upgrade to a ' + - 'decent browser to survive on these grounds.
'); - return true; - } - - /* - * Verify if client sent a session cookie, and if it consists of a - * valid one, load session data. - */ - if (this.http_vhost.scripts && - (sessid = this.http_vars_cookies['SessionID']) != undefined && - (sess = sessions_table[sessid]) != undefined && - sess.expires > time) { - this.http_sessid = sessid; - this.http_vars_session = sess.variables; - } - - /* - * Fill in associative array with any GET-style supplied - * variables (as part of the URL). We want this even for POST method. - */ - if ((i = this.http_path.lastIndexOf('?')) != -1) { - var v; - var t; - - v = this.http_path.substr(i + 1); - /* - * Note: substring() and substr() are semantically different - */ - this.http_path = this.http_path.substring(0, i); - words = v.split('&'); - for (i in words) { - t = words[i].split('='); - if (t.length == 2) - property_add(this.http_vars_get, t[0], t[1]); - } - } - - /* - * Switch to POST parsing mode if needed. - * This will then call this.parsePost() rather than this function, - * which will also invoke this.httpRespond(). - */ - if (this.http_method == 'POST' && this.http_content_length != -1) { - /* - * First obtain buffer stored by process_query() for us, - * if any. If the full post_data was found in it, simply - * call the parsing function immediately, which will return - * with close status after invking httpRespond(). - */ - this.post_data = ''; - if (this.bread_buffer.length > 0) { - this.post_data += this.bread_buffer; - this.bread_buffer = ''; - } - if (this.post_data.length < this.http_content_length) { - /* Go back to polling, activating process_post */ - this.post_data = ''; - this.process = process_post; - return false; - } else - return this.parsePost(time); - } - - if (!close) - close = this.httpRespond(time); - - return close; -} - -/* - * After reading post data, allows to parse it down into variables - */ -FD.prototype.parsePost = function(time) -{ - var words; - var i; - var t; - - /* - * We need to strip "\n", "\r" and "\r\n" which may be sent by broken - * clients. - */ - this.post_data = this.post_data.replace(/\n/g, ''); - this.post_data = this.post_data.replace(/\r/g, ''); - - words = this.post_data.split('&'); - for (i in words) { - t = words[i].split('='); - if (t.length == 2) - property_add(this.http_vars_post, t[0], t[1]); - } - - delete this.post_data; - - return this.httpRespond(time); -} - -/* - * Finally respond to client request - */ -FD.prototype.httpRespond = function(time) -{ - var path, fd, st, res, ext, mimetype, i, sess, size; - - /* - * Verify if requested path is valid - */ - path = this.http_vhost.htdocs_root.valid_virtual(this.http_path); - if (!path) { - http_error(this, 403, 'Permission Denied', - 'You do not have the permission to access this ' + - 'resource.'); - return true; - } - - /* - * We now want to verify if the client sent a valid session cookie. - * If it didn't, we present it with a page with meta-tag reload - * instructions to attempt to reload the originally supplied URL, - * and with a new session cookie. - */ - if (this.http_vhost.scripts == true && this.http_sessid == undefined) { - var doc, sess; - - doc = new HTTPReply(200, 'OK', - 'text/html; charset=' + options.default_charset); - doc.addNoCacheHeaders(); - - sess = new Session(time, - (this.http_vhost.session_exp != undefined ? - this.http_vhost.session_exp : - options.default_session_exp)); - sess.variables.count = 0; - doc.addHeader('Set-Cookie: SessionID=' + sess.sessid + - '; expires=' + - (new Date(sess.expires * 1000)).toGMTString() + - '; path=/'); - doc.addContent('Cookies' + - '

Cookies

We are ' + - ' verifying if your browser supports HTTP cookies. ' + - 'These are required to keep persistent session data ' + - 'among your connections. The destination page should ' + - 'load automatically in a few seconds.

' + - '

If it doesn\'t, please ensure that HTTP cookies ' + - 'are enabled on your HTTP client and are accepted ' + - 'from this server.

' + - '

If the page still does not load properly after a ' + - 'few seconds, please click on this link.


' + SERVER_VERSION + - '
' + SERVER_CVSID + '
'); - doc.flush(this, null); - - return true; - } - if (this.http_sessid != undefined) - this.http_vars_session.count++; - - - /* - * Attempt to find requested file. - * If it consists of a directory, attempt to first find index.html in - * it, then index.jso in it, fail with error 403 if none can be found. - * Otherwise, continue forward keeping the descriptor open, and the - * stat information already filled in. - */ - fd = new FD(); - - try { - fd.open(path.real, FD.O_RDONLY); - st = fd.fstat(); - } catch (x) { - http_error(this, 404, 'Not Found', - path.virtual + ' could not be found.'); - return true; - } - - if ((st.st_mode & FD.S_IFDIR) != 0) { - var error = false; - - fd.close(); - try { - fd.open(path.real + '/index.html', FD.O_RDONLY); - st = fd.fstat(); - path.real += '/index.html'; - path.virtual += '/index.html'; - } catch (x) { - try { - fd.open(path.real + '/index.jso', - FD.O_RDONLY); - st = fd.fstat(); - path.real += '/index.jso'; - path.virtual += '/index.jso'; - } catch (x) { - error = true; - } - } - if (error) { - http_error(this, 403, 'Permission Denied', - 'You do not have the permission to access the ' + - 'resource ' + path.virtual); - return true; - } - } - - /* - * Only continue if file is a regular file - */ - if ((st.st_mode & FD.S_IFREG) == 0) { - fd.close(); - http_error(this, 403, 'Permission Denied', - 'You do not have the permission to access the resource ' + - path.virtual); - return true; - } - - /* - * Extract file extension, as well as its mime type. - */ - if ((i = path.virtual.lastIndexOf('.')) != -1) { - ext = (path.virtual.substr(i + 1)).toLowerCase(); - if (ext.lastIndexOf('/') == -1 && - mimetypes_table[ext] != undefined) - mimetype = mimetypes_table[ext]; - else - mimetype = options.default_mimetype; - } - mimetype += '; charset=' + (this.http_vhost.charset == undefined ? - options.default_charset : this.http_vhost.charset); - - /* - * JavaScript Object (JSO) files are processed especially. - * We interpret them, providing them with an environment to - * access the needed resources (get/post/cookie/session variables, - * as well as the document object they can use). - * We flush the document once the script returns, or fire up - * an error if something fails. - */ - if (ext == 'jso') { - - /* Create document object */ - var obj = new HTTPReply(200, 'OK', mimetype); - obj.addNoCacheHeaders(); - - /* XXX Add other objects to export as necessary */ - obj.get = this.http_vars_get; - obj.post = this.http_vars_post; - obj.cookie = this.http_vars_cookies; - obj.session = this.http_vars_session; - obj.global = this.http_vhost.globals; - - /* - * Check if object in our cache already and file not modified - * since cached entry. Reuse function then. Otherwise, - * load in function from file, store a cache entry for it - * and launch it. - */ - - var data, s, o; - - if (((o = jso_cache[path.real]) != undefined) && - o.time == st.st_mtime) { - obj.script = o.script; - fd.close(); - } else { - try { - /* file_read() closes fd for us */ - data = file_read(fd); - s = 'obj.script = function() {' + data + '}'; - eval(s); - o = new JSO(path.real, st.st_mtime, - obj.script); - } catch (x) { - err.put(x + ' evaluating script ' + path.real - + "\n"); - http_error(this, 500, 'Internal Server Error', - 'Please try again later.'); - return true; - } - } - - try { - if (obj.script != undefined) - obj.script(); - obj.flush(this, null); - } catch (x) { - err.put(x + ' executing script ' + path.real + "\n"); - http_error(this, 500, 'Internal Server Error', - 'Please try again later.'); - } - - delete obj; - return true; - } - - /* - * If client only wanted the document if it wasn't modified since - * a certain time, report that it wasn't if it is the case. - */ - if (this.http_modified_since != undefined && - st.st_mtime <= this.http_modified_since) { - fd.close(); - res = new HTTPReply(304, 'Not Modified', null); - res.flush(this, null); - return true; - } - - /* - * If client only requested a range of bytes of the file, verify if - * the range is valid, and if so, arrange to only transfer the - * requested part of the file. - * In any other case, simply transfer the whole file. - */ - if (this.http_range != undefined) { - var w; - - if (this.http_range.startsWith('bytes')) - this.http_range = this.http_range.substr(5); - if (this.http_range.length > 0 && - this.http_range.charAt(0) == '=') - this.http_range = this.http_range.substr(1); - if ((w = this.http_range.split('-')).length == 2) { - var from, to; - - if (w[0] == '') - w[0] = 0; - if (w[1] == '') - w[1] = st.st_size - 1; - from = Number(w[0]); - to = Number(w[1]); - - if (from >= 0 && to < st.st_size && to >= from) { - res = new HTTPReply(206, 'Partial Content', - mimetype); - res.addHeader('Content-Range: bytes ' + - from + '-' + to + '/' + st.st_size); - this.transfer_size = Math.abs((to - from) + 1); - if (from > 0) { - try { - fd.lseek(from, FD.SEEK_SET); - } catch(x) { - err.put(x + " at lseek()\n"); - } - } - } - } - } - if (res == undefined) { - res = new HTTPReply(200, 'OK', mimetype); - this.transfer_size = Math.abs(st.st_size); - } - - /* - * Flush HTTP header, sending it - */ - res.flush(this, this.transfer_size); - - /* - * Switch to outbound transfer mode. - */ - this.transfer_src = fd; - this.transfer_dst = this; - this.process = process_transfer; - this.events = FD.POLLOUT; - - /* - * Return with close=false, to delegate operations to - * process_transfer(). - */ - return false; -} - -FD.prototype.httpDebug = function() -{ - table = new MLTag('table', true); - table.addAttr('width', '100%'); - table.addAttr('border', '1'); - - var tr = new MLTag('tr', true); - var td = new MLTag('td', true); - td.addAttr('width', '10%'); - td.addAttr('align', 'right'); - td.addContent('You are:'); - tr.addContent(td); - td = new MLTag('td', true); - td.addAttr('width', '90%'); - td.addContent(this.client_addr + ':' + this.client_port); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('You sent:'); - tr.addContent(td); - td = new MLTag('td', true); - var font = new MLTag('font', true); - font.addAttr('size', '-3'); - pre = new MLTag('pre', true); - pre.addContent(this.request_data); - font.addContent(pre); - td.addContent(font); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('GET vars:'); - tr.addContent(td); - td = new MLTag('td', true); - var font = new MLTag('font', true); - font.addAttr('size', '-3'); - pre = new MLTag('pre', true); - pre.addContent(uneval(this.http_vars_get)); - font.addContent(pre); - td.addContent(font); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('POST vars:'); - tr.addContent(td); - td = new MLTag('td', true); - var font = new MLTag('font', true); - font.addAttr('size', '-3'); - pre = new MLTag('pre', true); - pre.addContent(uneval(this.http_vars_post)); - font.addContent(pre); - td.addContent(font); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('Cookies:'); - tr.addContent(td); - td = new MLTag('td', true); - var font = new MLTag('font', true); - font.addAttr('size', '-3'); - pre = new MLTag('pre', true); - pre.addContent(uneval(this.http_vars_cookies)); - font.addContent(pre); - td.addContent(font); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('VHost:'); - tr.addContent(td); - td = new MLTag('td', true); - td.addContent(this.http_vhost.name); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('Path:'); - tr.addContent(td); - td = new MLTag('td', true); - td.addContent(this.http_path); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('Mod-Since:'); - tr.addContent(td); - td = new MLTag('td', true); - td.addContent(this.http_modified_since); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('SessID:'); - tr.addContent(td); - td = new MLTag('td', true); - td.addContent(this.http_sessid); - tr.addContent(td); - table.addContent(tr); - - tr = new MLTag('tr', true); - td = new MLTag('td', true); - td.addAttr('align', 'right'); - td.addContent('Sess vars:'); - tr.addContent(td); - td = new MLTag('td', true); - var font = new MLTag('font', true); - font.addAttr('size', '-3'); - pre = new MLTag('pre', true); - pre.addContent(uneval(this.http_vars_session)); - font.addContent(pre); - td.addContent(font); - tr.addContent(td); - table.addContent(tr); - - return table.toStr(0); -} - -/* - * Since we are using nonblocking mode, it is possible for write(2) to return - * a short count, in which case we must be able to resume writing the - * remaining buffer after poll(2). There are currently two write paths, - * HTTPResponse.flush() and process_transfer(). Both can use this function - * instead of write(2). The main poll(2) based loop can then handle buffer - * flushing. However, we first attempt to immediately write as much as we can - * before queuing what needs to be written again. - * Like write(2), this function can throw an exception on error, including - * for EAGAIN. - */ -FD.prototype.bwrite = function(data) -{ - var size; - - if ((size = this.write(data)) == data.length) - return data.length; - - this.bwrite_buffer += data.substr(size); - return size; -} - -/* - * Called by the main loop to know if there exists queued data, and to write - * it out if needed. Returns an object with two properties, done which if - * true tells the caller that there is no more data to flush, and close - * which if true means that an error occurred in which case connection should - * be closed. - */ -FD.prototype.bwrite_flush = function() -{ - var size; - var obj = new Object(); - - obj.done = obj.close = false; - - if (this.bwrite_buffer.length == 0) { - obj.done = true; - return obj; - } - - b = true; - try { - size = this.write(this.bwrite_buffer); - this.bwrite_buffer = this.bwrite_buffer.substr(size); - if (this.bwrite_buffer.length == 0) - obj.done = true; - } catch (x) { - if (this.errno != Errno.EAGAIN) - obj.close = true; - } - - return obj; -} - -/* - * Verifies if property name ends with [], which considers it as an array of - * values which are then pushed into that array. - * Sets the property normally otherwise. - */ -function property_add(obj, prop, val) -{ - prop = unescape(prop.replace(/\+/g, ' ')); - val = unescape(val.replace(/\+/g, ' ')); - - if (prop.endsWith('[]')) { - /* Array entry */ - prop = prop.substring(0, prop.length - 2); - if (obj[prop] == undefined) - obj[prop] = []; - obj[prop].push(val); - } else - obj[prop] = val; -} - - - -/* - * To know how many connections we are currently serving and limit them - */ -var counters_connections = 0; -var counters_addresses = []; - -function counters_inc(fd) -{ - - if (counters_connections >= options.max_connections) - return false; - - var addr = fd.client_addr; - if ((addrcnt = counters_addresses[addr]) != undefined && - addrcnt >= options.max_connections_addr) - return false; - - if (addrcnt == undefined) - addrcnt = 1; - else - addrcnt++; - counters_addresses[addr] = addrcnt; - - return true; -} - -function counters_dec(fd) -{ - var addr = fd.client_addr; - if ((--counters_addresses[addr]) == 0) - delete counters_addresses[addr]; - - counters_connections--; -} - - - -/* - * Main program - */ -function main() { - var i; - var sess_gc_secs = 0; - - /* - * Populate vhosts database - */ - for (i in vhosts) { - try { - var v = new VHost(vhosts[i]); - } catch (x) { - err.put(x + " creating VHost object\n"); - } - } - /* - * Attempt to link default_vhost to a VHost object - */ - if (options.default_vhost == undefined) { - err.put("No default_vhost property in options, exiting\n"); - exit(); - } - if (vhosts_table[options.default_vhost.toLowerCase()] != undefined) - default_vhost = - vhosts_table[options.default_vhost.toLowerCase()]; - else { - err.put('Default vhost ' + options.default_vhost + - " unkonwn, exiting\n"); - exit(); - } - - /* - * Populate mimetypes database. - * XXX If this got very large, because the destination strings - * are rather large, it might be good to use indexes or references - * to them rather than provide the string for each extension. - */ - for (i in mimetypes) { - var i2, ext; - - for (i2 in mimetypes[i]) { - ext = mimetypes[i][i2].toLowerCase(); - if (mimetypes_table[ext] != undefined) { - err.put('Conflicting mime type ' + - ext + ' -> ' + i + "\n"); - continue; - } - mimetypes_table[ext] = i; - } - } - if (mimetypes_table['jso'] == undefined) - mimetypes_table['jso'] = 'text/html'; - - /* - * Create polling array set - */ - var set = []; - - /* - * Initialize server - */ - for (i in listen) { - var fd; - - try { - fd = new FD(); - fd.socket(FD.AF_INET, FD.SOCK_STREAM, 0); - fd.bind(listen[i].address, listen[i].port); - - fd.setsockopt(FD.SO_REUSEADDR, 1); - fd.setsockopt(FD.SO_LINGER, -1); - fd.setsockopt(FD.SO_KEEPALIVE, 1); - fd.setsockopt(FD.TCP_NODELAY, 1); - - fd.fcntl(FD.F_SETFL, FD.O_NONBLOCK); - fd.listen(options.max_connections); - /* - * Mark socket as bound one and add it to - * polling set - */ - fd.events = FD.POLLIN; - fd.bound = true; - set.push(fd); - } catch (x) { - err.put(x + " preparing listening socket\n"); - } - } - if (set.length == 0) - exit(); - - /* - * Used for unique index associated to each FD for efficient removal - * from polling set when closing connection - */ - var count = listen.length + 1; - - /* - * Main loop - */ - for (;;) { - /* - * Determine next to expire FD event, so that we can sleep - * as long as possible. Also get rid of expired requests. - */ - var cur = Date.parse(new Date) / 1000; - var exp = cur + 3600; - var old; - for (i in set) { - var fd; - - if ((fd = set[i]) == undefined || fd.bound == true) - continue; - if (fd.expires <= cur) { - /* - * Request timeout expired for this - * descriptor, we must close it. - */ - fd.close(); - counters_dec(fd); - delete set[fd.index]; - delete fd; - continue; - } - if (fd.expires < exp) - exp = fd.expires; - } - exp -= cur; - - /* - * Poll our set of descriptors for events - */ - var e; - try { - e = FD.poll(set, exp * 1000); - } catch (x) { - err.put(x + " for poll(2)\n"); - continue; - } - - /* - * Verify if a timeout occurred. Because our poll - * implementation returns an array, its timeout event can be - * checked against by verifying if the set is empty. - */ - if (e.length == 0) { - /* Timeout */ - continue; - } - - /* - * XXX We should perhaps check timeouts after, so that we - * only need to query time once per loop? - * We could only do this if we knew that all our next - * processing is non-blocking, however. Otherwise we - * would loose track of actual time. - */ - old = cur; - cur = (Date.parse(new Date) / 1000); - - /* - * Verify if we should call the session gc, and if so, do so. - */ - sess_gc_secs += cur - old; - if (sess_gc_secs >= options.sess_gc_interval) { - sess_gc_secs = 0; - session_gc(cur); - } - - /* - * Run through set of descriptors with pending events - */ - for (i in e) { - if (e[i] == undefined) - continue; - - /* - * If descriptor is a bound one, attempt to accept - * the new client connection - */ - if (e[i].bound == true && - (e[i].revents & FD.POLLIN) != 0) { - var fd; - - try { - fd = e[i].accept(); - if (!counters_inc(fd)) { - http_error(fd, 403.9, - 'Too Many Connections', - 'Your browser has exceeded its maximum ' + - 'allowed number of concurrent ' + - 'connections.'); - fd.close(); - delete fd; - } else { - /* - * Setup client's initial - * state and add FD to polling - * set - */ - if (++count > 999999) - count = listen.length - + 1; - fd.init(cur, count); - set[count] = fd; - } - } catch (x) { - err.put(x + " at accept(2)\n"); - } - continue; - } - - /* - * Not a new connection event - */ - var close = false; - - /* - * Close connection on error conditions, - * Call the FD's process function on interesting - * events, which will tell when we should drop the - * client. - */ - if ((e[i].revents & (FD.POLLHUP | FD.POLLERR)) != 0) - close = true; - else if ((e[i].revents & (FD.POLLIN | FD.POLLOUT)) - != 0) { - /* - * Flush output queue if any and possible, - * since we're in non-blocking mode writes - * can yield short counts. - */ - var o = e[i].bwrite_flush(); - - if (o.close == true) - close = true; - else if (o.done == true) - close = e[i].process(cur); - } - - if (close) { - try { - e[i].close(); - } catch (x) {} - counters_dec(e[i]); - delete set[e[i].index]; - delete e[i]; - } - } - } - - /* NOTREACHED */ - err.close(); -} - -main(); -/* NOTREACHED */ -exit(0); diff --git a/tests/js-test/js/httpd/ml_clean.js b/tests/js-test/js/httpd/ml_clean.js deleted file mode 100644 index e0283c6..0000000 --- a/tests/js-test/js/httpd/ml_clean.js +++ /dev/null @@ -1,192 +0,0 @@ -/* $Id: ml_clean.js,v 1.4 2005/07/12 13:09:07 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Define prototype of the MLTag object. - */ -MLTag.prototype = { - /* A string of spaces to be used for indenting */ - indent_str: ' ' + - ' ', - - /* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ - wrap: function(str, level) - { - var len = str.length; - var newstr = this.indent_str.substr(0, level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent_str.substr(0, - level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; - }, - - /* - * Add specified attribute with optional associated value to this tag - */ - addAttr: function(attr, value) - { - - this.attributes[attr] = value; - }, - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - addContent: function(item) - { - - this.contents.push(item); - }, - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - toStr: function(level) - { - var str = ''; - - /* Null tags may exist as containers */ - if (this.tag != null) { - - /* Open opening tag */ - str += this.indent_str.substr(0, level) + '<' + - this.tag; - - /* - * Store these immediately for performance since we - * use those values several times later on, also - * saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* - * Add each of our attributes with their optional - * values - */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + - this.indent_str.substr(0, len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - } - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i in this.contents) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * If this tag required closing, do so - */ - if (this.tag != null) { - level--; - if (this.close) - str += this.indent_str.substr(0, level) + - '\n"; - } - - return str; - } -} - - -var entitites_table = { - '<': '<', - '>': '>', - '&': '&', - '"': '"', - "`": '‘', - "'": '’' -}; - -/* - * Function to convert a supplied string to use HTML/SGML special entitites. - * This also allows HTML escaping from user-supplied strings. - */ -function toHTMLEntities(str) -{ - var s = ''; - var i, t, c, e; - - for (i = 0, t = str.length; i < t; i++) { - c = str.charAt(i); - if ((e = entitites_table[c]) != undefined) - s += e; - else - s += c; - } - - return s; -} diff --git a/tests/js-test/js/httpd/ml_machine.js b/tests/js-test/js/httpd/ml_machine.js deleted file mode 100644 index d9783e9..0000000 --- a/tests/js-test/js/httpd/ml_machine.js +++ /dev/null @@ -1,146 +0,0 @@ -/* $Id: ml_machine.js,v 1.4 2005/07/12 13:09:07 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Define prototype of the MLTag object. - */ -MLTag.prototype = { - - /* - * Add specified attribute with optional associated value to this tag - */ - addAttr: function(attr, value) - { - - this.attributes[attr] = value; - }, - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - addContent: function(item) - { - - this.contents.push(item); - }, - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - toStr: function(level) - { - var str = ''; - - /* Null tags may exist as containers */ - if (this.tag != null) { - - /* Open opening tag */ - str += '<' + this.tag; - - /* - * Store these immediately for performance since we - * use those values several times later on, also - * saves typing - */ - var taglen = this.tag.length; - var len = taglen + 1; - var attributes = this.attributes; - - /* - * Add each of our attributes with their optional - * values - */ - for (var attr in attributes) { - var value; - - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - - /* Close opening tag */ - str += ">"; - - } - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i in this.contents) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(0); - else - str += a; - } - - /* - * If this tag required closing, do so - */ - if (this.tag != null && this.close) - str += '"; - - return str; - } - -} - - -var entitites_table = { - '<': '<', - '>': '>', - '&': '&', - '"': '"', - "`": '‘', - "'": '’' -}; - -/* - * Function to convert a supplied string to use HTML/SGML special entitites. - * This also allows HTML escaping from user-supplied strings. - */ -function toHTMLEntities(str) -{ - var s = ''; - var i, t, c, e; - - for (i = 0, t = str.length; i < t; i++) { - c = str.charAt(i); - if ((e = entitites_table[c]) != undefined) - s += e; - else - s += c; - } - - return s; -} diff --git a/tests/js-test/js/httpd/options.js b/tests/js-test/js/httpd/options.js deleted file mode 100644 index b0e49c0..0000000 --- a/tests/js-test/js/httpd/options.js +++ /dev/null @@ -1,82 +0,0 @@ -/* $Id: options.js,v 1.17 2005/12/12 09:55:45 mmondor Exp $ */ - -var options = { - max_connections: 32, - max_connections_addr: 4, - io_timeout: 60, - readbuf_size: 65536, - default_vhost: "chat.pulsar-zone.net", - default_mimetype: "application/octet-stream", - default_charset: "us-ascii", - default_session_exp: 1800, - sess_gc_interval: 600, - sess_id_size: 64, - ban_msie: false, - ban_windows: false -}; - -/* Address:port combinations to listen to */ -var listen = [ - { - address: "127.0.0.1", - port: 8080 - }, - { - address: "192.168.1.12", - port: 8080 - } -]; - -var vhosts = [ - /* Default virtual host */ - { - name: "chat.pulsar-zone.net", - root: "/home/mmondor/jswww/chat", - scripts: true, - charset: 'iso-8859-1', - session_exp: 14400 - }, - - /* Dynamic application virtual host for ascpi.com */ - { - name: "ascpi.com", - aliases: [ "www.ascpi.com", "ascpi.hal.xisop", - "ascpi.hal" ], - root: "/home/mmondor/jswww/ascpi.com" - }, - - /* Static only test virtual host */ - { - name: "test.localhost", - root: "/home/mmondor/jswww/welcome" - } -]; - -var mimetypes = { - 'text/html': [ "html", "htm", "dhtml", - "jso" ], - 'text/plain': [ "txt" ], - 'text/css': [ "css" ], - 'application/x-xpinstall': [ "xpi" ], - 'application/vnd.mozilla.xul+xml': [ "xul" ], - 'text/rdf': [ "rdf" ], - 'application/pdf': [ "pdf" ], - 'application/postscript': [ "ps" ], - 'application/x-tar': [ "tar" ], - 'application/x-gzip': [ "gz" ], - 'application/x-bzip2': [ "bz2" ], - 'application/zip': [ "zip" ], - 'application/x-javascript': [ "js" ], - 'application/x-c': [ "c", "h", "cpp", "cc" ], - 'application/x-sh': [ "sh" ], - 'application/x-shockwave-flash': [ "swf" ], - 'application/xml': [ "xml" ], - 'application/xml-dtd': [ "dtd" ], - 'image/jpg': [ "jpg", "jpeg" ], - 'image/png': [ "png" ], - 'image/gif': [ "gif" ], - 'image/x-icon': [ "ico" ], - 'video/mpeg': [ "mpeg", "mpg" ], - 'video/quicktime': [ "mov" ], - 'video/x-msvideo': [ "asf", "asx", "wmv", "avi" ] -}; diff --git a/tests/js-test/js/httpd/root.js b/tests/js-test/js/httpd/root.js deleted file mode 100644 index c46fd2b..0000000 --- a/tests/js-test/js/httpd/root.js +++ /dev/null @@ -1,197 +0,0 @@ -/* $Id: root.js,v 1.1 2005/07/07 00:11:43 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Implementation of a virtual chroot(2) system. - */ - - - -const PATH_MAX = 255; - - - -function Root(root) -{ - - if (!(this.root = this.valid_path(root))) - throw('Invalid root path "' + root + '"!'); - this.cwd = '/'; -} - -Root.prototype = { - - /* - * Quick lookup table of valid characters within pathnames. - * Currently 'a'-'z', 'A'-'Z', '0'-'9', '.', '/', '-', '_' - */ - valid_char_table: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ], - - /* - * Base function to return formatted valid path, or false. - * Returned path will always begin with '/' and not have any - * trailing '/'. Multiple '/' are also collapsed into one. - */ - valid_path: function(path) - { - var i, t, l, p, c, code; - - p = l = '/'; - for (i = 0, t = path.length; i < t; i++) { - c = path.charAt(i); - if (l == '/') { - /* Collapse multiple '/' */ - if (c == '/') - continue; - /* Prohibit '.' at start of element */ - if (c == '.') - return false; - } - /* Validate chars */ - code = c.charCodeAt(0); - if (code != code & 0xff || - this.valid_char_table[code] == 0) - return false; - p += c; - l = c; - } - /* Strip last '/' if any, unless only one */ - if (c == '/' && p.length > 1) - p = p.substr(0, p.length - 1); - - /* If exceeding PATH_MAX, return false */ - if (p.length > PATH_MAX) - return false; - - return p; - }, - - /* - * Returns version of provided path which points to the parent - * directory if possible. Returns false otherwise. - * Should only be used with paths first copied using valid_path(). - * Can typically be used with the cwd. - */ - parent: function(path) - { - var i; - - /* First make sure that path starts with '/' */ - if (path.length < 2 || path.charAt(0) != '/') - return false; - - /* Strip trailing '/' chars */ - for (i = path.length - 1; i >= 0 && path.charAt(i) == '/'; - i--) ; - if (i <= path.length) - path = path.substr(0, i + 1); - - /* - * Locate previous '/', strip everything after it, including - * it, except in the case where it is the only remaining, - * where path must remain '/'. - */ - if ((i = path.lastIndexOf('/')) == 0) - i = 1; - return path.substring(0, i); - }, - - /* - * This function should always be called when processing user-supplied - * paths. The application should then only trust the object it - * returns. Returns false if the path is invalid. - * Otherwise, returns an object, with the following properties: - * - * System-wide absolute real fullpath, to be used by the - * application to access the files/directories in - * question. - * Virtual root based absolute fullpath, useful to report - * to the user. Can also be useful to change a Root - * object's cwd to, after verifying that really - * points to an existing directory. - */ - valid_virtual: function(path) - { - var cwd, c, l, t, o; - - o = {}; - cwd = this.cwd; - - /* - * Look for '~', or '/' in the beginning of the path, - * in which case cwd gets cleared to '/'. Also look for - * './' or '.[EOS]', which we simply skip, meaning the - * current directory. - */ - if ((l = path.length) > 0) { - c = path.charAt(0); - if (c == '~' || c == '/') { - cwd = '/'; - path = path.substr(1); - } else if (c == '.') { - if (l == 1) - path = ''; - else if (l > 1 && path.charAt(1) == '/') - path = path.substr(2); - } - } - - /* - * Now process all starting '..' or '../', modifying cwd if - * allowed, and stripping them from path. In case of '../', - * also strip any multiple '/'. - */ - for (;;) { - t = false; - l = path.length; - if ((l == 2 && path == '..') || - (l > 2 && path.substr(0, 2) == '..' && - (t = (path.charAt(2) == '/')))) { - if (!(cwd = this.parent(cwd))) - return false; - if (t) { - for (i = 2; path.charAt(i) == '/'; - i++) ; - path = path.substr(i); - continue; - } else { - path = path.substr(2); - continue; - } - } - break; - } - - /* - * Now attempt to fill in our object properties. - * this.valid_path() performs necessary sanity checking. - */ - if (!(o.virtual = this.valid_path('/' + cwd + '/' + path))) - return false; - o.real = this.root + o.virtual; - - return o; - } - -}; diff --git a/tests/js-test/js/httpd/string.js b/tests/js-test/js/httpd/string.js deleted file mode 100644 index 5ed8080..0000000 --- a/tests/js-test/js/httpd/string.js +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id: string.js,v 1.1 2005/07/11 01:50:56 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Extension to the standard String object to support startsWith() and - * endsWith() very useful methods. - */ - - - -String.prototype.startsWith = function(str) -{ - var t = str.length; - - if (this.length >= t && this.substr(0, t) == str) - return true; - - return false; -} - -String.prototype.endsWith = function(str) -{ - var t1 = str.length; - var t2 = this.length; - - if (t2 >= t1 && this.substr(t2 - t1, t1) == str) - return true; - - return false; -} diff --git a/tests/js-test/js/ml.js b/tests/js-test/js/ml.js deleted file mode 100644 index dd09de6..0000000 --- a/tests/js-test/js/ml.js +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id: ml.js,v 1.4 2005/06/27 18:21:21 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -const ident_str = ' ' + - ' '; - -function indent(level) -{ - if (level == null) - return false; - - return ident_str.substr(0, level); -} - -function wrap(str, level) -{ - if (str == null || level == null) - return false; - - var len = str.length; - var newstr = indent(level); - var newlen = level; - var i; - - /* - * Could find index to space and use substring as necessary instead of - * looping through every character. Of course, this could also all be - * implemented using C native code. - */ - for (i = 0; i < len; i++) { - if (str.charAt(i) == ' ' && newlen > 70) { - newstr += "\n" + indent(level); - newlen = level; - continue; - } - newstr += str.charAt(i); - newlen++; - } - - return newstr; -} - - - -function MLAttr(attr, value) -{ - /* We allow null value */ - if (attr == null) - return false; - - this.attr = attr; - this.value = value; -} - - - -/* - * XXX Using prototypes to inherit functions would be ideal for speed, - * probably, to avoid having to redeclare the functions in the constructor for - * every new object instance. However, I seemed to have problems when using - * that method, mostly related to the constructor of the object no longer - * being tracable. - */ - -function MLTag(attr, close) -{ - if (attr == null || close == null) - return false; - - this.attr = attr; - this.close = close; - this.attributes = new Array(); - this.attributes_count = 0; - this.contents = new Array(); - this.contents_count = 0; - - this.addAttr = function(attr, value) - { - if (attr == null) - return false; - - this.attributes[this.attributes_count++] = - new MLAttr(attr, value); - } - - this.addContent = function(item) - { - if (item == null) - return false; - - this.contents[this.contents_count++] = item; - } - - this.toStr = function(level) - { - if (level == null) - return false; - - var str = ''; - var i, attrlen, len, a; - - str += indent(level) + '<' + this.attr; - attrlen = this.attr.length; - len = level + attrlen + 1; - for (i = 0; i < this.attributes_count; i++) { - a = this.attributes[i]; - - if (len > 70) { - len = level + attrlen + 1; - str += "\n" + indent(len); - } - str += ' ' + a.attr; - len += attrlen + 1; - if (a.value != null) { - var value = a.value; - str += '="' + value + '"'; - len += value.length + 3; - } - } - str += ">\n"; - - if (this.close) - level++; - - for (i = 0; i < this.contents_count; i++) { - a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += wrap(a, level) + "\n"; - } - - if (this.close) - str += indent(--level) + '\n"; - - return str; - } -} - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/ml2.js b/tests/js-test/js/ml2.js deleted file mode 100644 index 6a1eab6..0000000 --- a/tests/js-test/js/ml2.js +++ /dev/null @@ -1,209 +0,0 @@ -/* $Id: ml2.js,v 1.3 2005/06/27 19:45:22 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * XXX Using prototypes to inherit functions would be ideal for speed, - * probably, to avoid having to redeclare the functions in the constructor for - * every new object instance. However, I seemed to have problems when using - * that method, mostly related to the constructor of the object no longer - * being tracable. At worse, we could define our methods as MLTag_foo() and - * in the constructor function just assign them to the proper properties... - * The currently used method at least has advantage of being cleaner to read. - */ - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - if (tag == null || close == null) - return false; - - /* - * A few utility functions used by our methods later on. - * Adding these here prevents namespace pollution. - */ - - /* Returns a string with requested number of spaces */ - const indent_str = ' ' + - ' '; - this.indent = function(level) - { - if (level == null) - return false; - - return indent_str.substr(0, level); - } - - /* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ - this.wrap = function(str, level) - { - if (str == null || level == null) - return false; - - var len = str.length; - var newstr = this.indent(level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent(level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; - } - - - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = new Object(); - this.contents = new Array(); - this.contents_count = 0; - - /* - * Add specified attribute with optional associated value to this tag - */ - this.addAttr = function(attr, value) - { - if (attr == null) - return false; - - eval('this.attributes.' + attr + ' = \'' + value + '\''); - } - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - this.addContent = function(item) - { - if (item == null) - return false; - - this.contents[this.contents_count++] = item; - } - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - this.toStr = function(level) - { - if (level == null) - return false; - - /* Open opening tag */ - var str = this.indent(level) + '<' + this.tag; - - /* - * Store these immediately for performance since we use those - * values several times later on, also saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* Add each of our attributes with their optional values */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + this.indent(len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents_count; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * This tag required closing, so add corresponding closing tag - * and decrease indent level. - */ - level--; - if (this.close) - str += this.indent(level) + '\n"; - - return str; - } -} - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/ml3.js b/tests/js-test/js/ml3.js deleted file mode 100644 index 3b8cb3b..0000000 --- a/tests/js-test/js/ml3.js +++ /dev/null @@ -1,209 +0,0 @@ -/* $Id: ml3.js,v 1.3 2005/06/27 19:45:22 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * XXX Using prototypes to inherit functions would be ideal for speed, - * probably, to avoid having to redeclare the functions in the constructor for - * every new object instance. However, I seemed to have problems when using - * that method, mostly related to the constructor of the object no longer - * being tracable. At worse, we could define our methods as MLTag_foo() and - * in the constructor function just assign them to the proper properties... - * The currently used method at least has advantage of being cleaner to read. - */ - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - if (tag == null || close == null) - return false; - - /* - * A few utility functions used by our methods later on. - * Adding these here prevents namespace pollution. - */ - - /* Returns a string with requested number of spaces */ - const indent_str = ' ' + - ' '; - this.indent = function(level) - { - if (level == null) - return false; - - return indent_str.substr(0, level); - } - - /* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ - this.wrap = function(str, level) - { - if (str == null || level == null) - return false; - - var len = str.length; - var newstr = this.indent(level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent(level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; - } - - - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = new Array(); /* Associative */ - this.contents = new Array(); - this.contents_count = 0; - - /* - * Add specified attribute with optional associated value to this tag - */ - this.addAttr = function(attr, value) - { - if (attr == null) - return false; - - this.attributes[attr] = value; - } - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - this.addContent = function(item) - { - if (item == null) - return false; - - this.contents[this.contents_count++] = item; - } - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - this.toStr = function(level) - { - if (level == null) - return false; - - /* Open opening tag */ - var str = this.indent(level) + '<' + this.tag; - - /* - * Store these immediately for performance since we use those - * values several times later on, also saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* Add each of our attributes with their optional values */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + this.indent(len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents_count; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * This tag required closing, so add corresponding closing tag - * and decrease indent level. - */ - level--; - if (this.close) - str += this.indent(level) + '\n"; - - return str; - } -} - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/ml4.js b/tests/js-test/js/ml4.js deleted file mode 100644 index e2d3383..0000000 --- a/tests/js-test/js/ml4.js +++ /dev/null @@ -1,203 +0,0 @@ -/* $Id: ml4.js,v 1.5 2005/06/27 19:45:22 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - if (tag == null || close == null) - return false; - - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Force creation of prototype object - */ -MLTag('prototype', false); - -/* - * A few utility functions used by our methods later on. - * Adding these here prevents namespace pollution. - */ - -MLTag.prototype.indent_str = ' ' + - ' '; -/* Returns a string with requested number of spaces */ -MLTag.prototype.indent = function(level) -{ - if (level == null) - return false; - - return this.indent_str.substr(0, level); -} - -/* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ -MLTag.prototype.wrap = function(str, level) -{ - if (str == null || level == null) - return false; - - var len = str.length; - var newstr = this.indent(level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent(level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; -} - -/* - * Add specified attribute with optional associated value to this tag - */ -MLTag.prototype.addAttr = function(attr, value) -{ - if (attr == null) - return false; - - this.attributes[attr] = value; -} - -/* - * Add arbitrary content in sequencial order to this tag's body - */ -MLTag.prototype.addContent = function(item) -{ - if (item == null) - return false; - - this.contents.push(item); -} - -/* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ -MLTag.prototype.toStr = function(level) -{ - if (level == null) - return false; - - /* Open opening tag */ - var str = this.indent(level) + '<' + this.tag; - - /* - * Store these immediately for performance since we use those - * values several times later on, also saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* Add each of our attributes with their optional values */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + this.indent(len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents.length; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * This tag required closing, so add corresponding closing tag - * and decrease indent level. - */ - level--; - if (this.close) - str += this.indent(level) + '\n"; - - return str; -} - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/ml5.js b/tests/js-test/js/ml5.js deleted file mode 100644 index 9c7b772..0000000 --- a/tests/js-test/js/ml5.js +++ /dev/null @@ -1,213 +0,0 @@ -/* $Id: ml5.js,v 1.3 2005/06/27 19:45:22 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - /* - if (tag == null || close == null) - return false; - */ - - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Define prototype of the MLTag object. - */ -MLTag.prototype = { - /* A string of spaces to be used by indent() */ - indent_str: ' ' + - ' ', - - /* Returns a string with requested number of spaces */ - indent: function(level) - { - /* - if (level == null) - return false; - */ - - return this.indent_str.substr(0, level); - }, - - /* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ - wrap: function(str, level) - { - /* - if (str == null || level == null) - return false; - */ - - var len = str.length; - var newstr = this.indent(level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent(level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; - }, - - /* - * Add specified attribute with optional associated value to this tag - */ - addAttr: function(attr, value) - { - /* - if (attr == null) - return false; - */ - - this.attributes[attr] = value; - }, - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - addContent: function(item) - { - /* - if (item == null) - return false; - */ - - this.contents.push(item); - }, - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - toStr: function(level) - { - /* - if (level == null) - return false; - */ - - /* Open opening tag */ - var str = this.indent(level) + '<' + this.tag; - - /* - * Store these immediately for performance since we use those - * values several times later on, also saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* Add each of our attributes with their optional values */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + this.indent(len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents.length; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * This tag required closing, so add corresponding closing tag - * and decrease indent level. - */ - level--; - if (this.close) - str += this.indent(level) + '\n"; - - return str; - } -} - - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/ml6.js b/tests/js-test/js/ml6.js deleted file mode 100644 index 15c3b8c..0000000 --- a/tests/js-test/js/ml6.js +++ /dev/null @@ -1,182 +0,0 @@ -/* $Id: ml6.js,v 1.1 2005/11/16 00:35:01 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Define prototype of the MLTag object. - */ -MLTag.prototype = { - /* A string of spaces to be used for indenting */ - indent_str: ' ' + - ' ', - - /* - * Wraps specified string at 70 columns and observing specified - * indentation level - */ - wrap: function(str, level) - { - var len = str.length; - var newstr = this.indent_str.substr(0, level); - var newlen = level; - - /* - * Could find index to space and use substring as necessary - * instead of looping through every character. Of course, - * this could also all be implemented using C native code. - */ - for (var i = 0; i < len; i++) { - var c = str.charAt(i); - - if (c == ' ' && newlen > 70) { - newstr += "\n" + this.indent_str.substr(0, - level); - newlen = level; - continue; - } - newstr += c; - newlen++; - } - - return newstr; - }, - - /* - * Add specified attribute with optional associated value to this tag - */ - addAttr: function(attr, value) - { - - this.attributes[attr] = value; - }, - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - addContent: function(item) - { - - this.contents.push(item); - }, - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - toStr: function(level) - { - - /* Open opening tag */ - var str = this.indent_str.substr(0, level) + '<' + this.tag; - - /* - * Store these immediately for performance since we use those - * values several times later on, also saves typing - */ - var taglen = this.tag.length; - var len = level + taglen + 1; - var attributes = this.attributes; - - /* Add each of our attributes with their optional values */ - for (var attr in attributes) { - var value; - - if (len > 70) { - len = level + taglen + 1; - str += "\n" + this.indent_str.substr(0, len); - } - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - /* Close opening tag */ - str += ">\n"; - - /* Increase our indent level for content */ - level++; - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents.length; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(level); - else - str += this.wrap(a, level) + "\n"; - } - - /* - * This tag required closing, so add corresponding closing tag - * and decrease indent level. - */ - level--; - if (this.close) - str += this.indent_str.substr(0, level) + '\n"; - - return str; - } -} - - - - -/* - * Now test our functionality - */ - -out = new FD(); -out.set(FD.STDOUT_FILENO); - -for (i = 0; i < 1000; i++) { - -var table = new MLTag('table', true); -table.addAttr('border', 0); -table.addAttr('width', '100%'); - -var tr = new MLTag('tr', true); - -var td = new MLTag('td', true); -td.addAttr('bgcolor', '#000000'); - -var p = new MLTag('p', true); -p.addContent('Hello'); - -td.addContent(p); -tr.addContent(td); -table.addContent(tr); - -out.put(table.toStr(8)); - -//out.put(uneval(table)); - -} diff --git a/tests/js-test/js/parse.js b/tests/js-test/js/parse.js deleted file mode 100644 index 672b115..0000000 --- a/tests/js-test/js/parse.js +++ /dev/null @@ -1,318 +0,0 @@ -/* $Id: parse.js,v 1.1 2005/11/16 00:36:58 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -/* - * Useful object to use for HTML tags. consists of tag name, and - * of a boolean specifying of the tag requires a corresponding closing - * tag (i.e.

[body]

. Attributes and body elements may be added after - * creating such an object, and toStr() used to obtain the actual HTML result. - */ -function MLTag(tag, close) -{ - /* - * MLTag object properties - */ - this.tag = tag; - this.close = close; - this.attributes = {}; /* Object with associative attributes */ - this.contents = []; /* Array object */ -} - -/* - * Define prototype of the MLTag object. - */ -MLTag.prototype = { - - /* - * Add specified attribute with optional associated value to this tag - */ - addAttr: function(attr, value) - { - - this.attributes[attr] = value; - }, - - /* - * Add arbitrary content in sequencial order to this tag's body - */ - addContent: function(item) - { - - this.contents.push(item); - }, - - /* - * Returns a string consisting of this tag along with its body and - * optional corresponding closing tag - */ - toStr: function(level) - { - var str = ''; - - /* Null tags may exist as containers */ - if (this.tag != null) { - - /* Open opening tag */ - str += '<' + this.tag; - - /* - * Store these immediately for performance since we - * use those values several times later on, also - * saves typing - */ - var taglen = this.tag.length; - var len = taglen + 1; - var attributes = this.attributes; - - /* - * Add each of our attributes with their optional - * values - */ - for (var attr in attributes) { - var value; - - str += ' ' + attr; - len += taglen + 1; - if ((value = attributes[attr]) != null) { - str += '="' + value + '"'; - len += value.length + 3; - } - } - - /* Close opening tag */ - str += ">"; - - } - - /* - * Now add all our contents, if any, which may consist of - * other MLTag objects or arbitrary String objects. Use - * recursion to process MLTag ones, which may also have their - * respective bodies and closing tags. - */ - for (var i = 0; i < this.contents.length; i++) { - var a = this.contents[i]; - - if (typeof a == 'object') - str += a.toStr(0); - else - str += a; - } - - /* - * If this tag required closing, do so - */ - if (this.tag != null && this.close) - str += '"; - - return str; - } - -} - - -var entitites_table = { - '<': '<', - '>': '>', - '&': '&', - '"': '"', - "`": '‘', - "'": '’' -}; - -/* - * Function to convert a supplied string to use HTML/SGML special entitites. - * This also allows HTML escaping from user-supplied strings. - */ -function toHTMLEntities(str) -{ - var s = ''; - var i, t, c, e; - - for (i = 0, t = str.length; i < t; i++) { - c = str.charAt(i); - if ((e = entitites_table[c]) != undefined) - s += e; - else - s += c; - } - - return s; -} - - - -/* - * This is a parsing test. - * - * For now, we want to simply accept patterns in the form %x{...}, where - * there may be arbitrary data within the { }, and function %x must be - * performed on it. For instance, %b{some text} would denote this text - * as bold. However, we should also allow %b{some text %i{more text}} and - * such. Because %, { and } characters are special, we should support - * escaping with \. Because \ is special for escaping, we should support - * \\ meaning a single \. Unclosed } should either generate an error, - * or we might want to automatically consider them all closed at the end - * of the user provided string. - * - * XXX One level currently seems to work, but there are recursive problems! - * Also, we are loosing a space. - */ - -function tokenize(str, ctag, i) -{ - var t, c; - var escaped = false; - var tags = new MLTag(null, false); - var ss = ''; - - if (ctag != undefined) { - if (str.length < i || str.charAt(i) != '{') - return tags; - i++; - } else - i = 0; - - for (t = str.length; i < t; i++) { - c = str.charAt(i); - - /* Handle '\' escaping, valid for the whole string */ - if (escaped && - (c == '\\' || c == '%' || c == '{' || c == '}')) { - ss += c; - escaped = false; - continue; - } - if (c == '\\') { - escaped = true; - continue; - } - - /* - * Special character which delimits commands strings. Since - * we are recursively called we must detect this condition and - * exit just like for the end of string. - */ - if (c == '{' || c == '}' && ctag == undefined) { - ss += c; - continue; - } - if (c == '}') { -// i++; /* XXX */ - break; - } - - /* - * Command mode. Make sure that we do have a command name, - * followed with required '{'. If an invalid command, simply - * allow enclosed string to be litteral. For valid commands, - * create the required tag and recurse into ourselves on the - * enclosed string in '{' and '}'. - */ - /* Command mode */ - if (c == '%') { - var ntag, o; - - if (/*ctag != undefined ||*/ i > t - 1 || - str.charAt(i + 2) != '{') { - ss += c; - continue; - } - - /* Flush current string if any */ - if (ss.length > 0) { - tags.addContent(ss); - ss = ''; - } - - switch (str.charAt(i + 1)) { - case 'b': - ntag = new MLTag('b', true); - break; - case 'i': - ntag = new MLTag('i', true); - break; - case 'e': - ntag = new MLTag('em', true); - break; - case 'S': - ntag = new MLTag('sup', true); - break; - case 's': - ntag = new MLTag('sub', true); - break; - case 't': - ntag = new MLTag('tt', true); - break; - case 'h': - ntag = new MLTag('h', true); - break; - case 'p': - ntag = new MLTag('p', true); - break; - case 'n': - ntag = new MLTag('br', false); - break; - case 'A': - ntag = new MLTag('a', true); - break; - case 'I': - ntag = new MLTag('img', true); - break; - default: - ntag = new MLTag(null, false); - } - - o = tokenize(str, ntag, i + 2); - i = o.i; - /* XXX */ - ntag.addContent(o.tags.toStr(0)); - tags.addContent(ntag); - continue; - } - - ss += c; - } - - /* - * Now that we gathered command-enclosed string, take care of special - * cases for and , and add resulting content. - */ - if (ctag != undefined) { - switch (ctag.tag) { - case 'a': - ctag.addAttr('href', ss); - break; - case 'img': - ctag.addAttr('src', ss); - break; - } - if (ss.length > 0) { - ctag.addContent(ss); - ss = ''; - } - tags.addContent(ctag); - } - if (ss.length > 0) - tags.addContent(ss); - - /* - * Return object with current index in string, as well as new tag - * container - */ - var obj = {}; - obj.i = i; - obj.tags = tags; - - return obj; -} - - -//print((tokenize('Some %b{enclosed} string', undefined, 0)).tags.toStr(0)); -print((tokenize('Some %b{enclo%i{s}ed} string', undefined, 0)).tags.toStr(0)); -//print(uneval((tokenize('Some %b{enclo%i{s}ed} string', undefined, 0)).tags)); diff --git a/tests/js-test/js/poll_test.js b/tests/js-test/js/poll_test.js deleted file mode 100644 index ba04111..0000000 --- a/tests/js-test/js/poll_test.js +++ /dev/null @@ -1,93 +0,0 @@ -/* $Id: poll_test.js,v 1.3 2005/02/13 09:02:06 mmondor Exp $ */ - -function events(e) -{ - s = new String(); - - if (e & FD.POLLIN) - s += 'POLLIN '; - if (e & FD.POLLOUT) - s += 'POLLOUT '; - if (e & FD.POLLERR) - s += 'POLLERR '; - if (e & FD.POLLHUP) - s += 'POLLHUP '; - if (e & FD.POLLNVAL) - s += 'POLLNVAL '; - - return s; -} - -output = new FD(); -output.set(FD.STDOUT_FILENO); - -try { - - input = new FD(); - input.set(FD.STDIN_FILENO); - - set = new Array(); - - /* - * This is interesting, because we allow normal arrays, either dense - * using set.push(), or sparse using set[n] = fd, but we also allow - * associative array elements such as set['string'] = fd. The - * returned set only holds FD objects for which events occurred. One - * can run through that resulting set using for (v in a) ... format, - * but it is also possible to verify the associative string name to - * see if it is in the set. As usual with poll(2), POLLHUP, POLLERR - * and POLLNVAL are always possible even for descriptor objects with - * their events property set to 0. The default events property for - * an FD object is also 0. The user can then verify the revents - * property of each FD object in the result set, and take appropriate - * I/O action or processing. - * - * Moreover, JavaScript being a very dynamic language, one can add - * properties or methods to individual FD objects as wanted, and of - * course can use those to say, process events of the descriptors - * returned in the set with pending events. This means that a common - * method name with different functionality added to each FD object - * permits a main events loop to transparently execute the wanted code - * using, for instance, fd.process(). In a case where two types of - * common events, input and output need to be processed differently - * with such a method, one can even define new methods as a prototype - * for base custom FD objects, which can be automatically inherited - * in shared mode by all children objects derived from the prototype - * object. - */ - - /* - * Set interesting events mask for our FD objects to monitor - */ - input.events = FD.POLLIN; - output.events = 0; - - /* - * Add our FD objects to an array - */ - set.push(input); - set.push(output); - - /* - * Invoke poll(2) on descriptors in our FD objects array, sleep for a - * maximum of 5000 milliseconds (5 seconds). Retreive result set of - * FD objects with pending events into rset. - */ - rset = FD.poll(set, 5000); - - /* - * Display rset contents - */ - output.put('Set size: ' + rset.length + "\n"); - for (var i in rset) { - output.put(i + ': type=' + rset[i].constructor.name + ' fd=' + - rset[i].fd + ' revents=' + events(rset[i].revents) + "\n"); - } - - input.close(); - -} catch (x) { - output.put(x + "\n"); -} - -output.close(); diff --git a/tests/js-test/js/sock_httpd.js b/tests/js-test/js/sock_httpd.js deleted file mode 100644 index d12533b..0000000 --- a/tests/js-test/js/sock_httpd.js +++ /dev/null @@ -1,292 +0,0 @@ -/* $Id: sock_httpd.js,v 1.8 2005/06/28 00:19:03 mmondor Exp $ */ - -/* - * Little example showing the versatility of ECMAScript, provided with a - * custom library for BSD socket support, using SpiderMonkey. - * This tiny HTTPd allows simultaneous concurrent client connections without - * using multiple threads or processes. Must be ran through ../src/test, - * compiled with ../src/classes/js_fd.[ch] support. - * - * We support a maximum of 4 concurrent connections per IP address, as well - * as a total maximum of 32 concurrent connections by default. - * Change MAX_CONNECTIONS and MAX_CONNECTIONS_ADDR as needed. - * - * We also support per-connection request timeouts, defaulting to 60 seconds. - * Change REQUEST_TIMEOUT as wanted. - * Note that this timeout consists of a total timeout for the connection, - * rather than an actual input timeout (which would require to reset the - * expiration time everytime user input occurs). Using the current timeout - * method suits most embedded applications, but would not be adequate to - * support large file transfers or the like (connection would timeout - * during a long transfer). However, if we supported this kind of long - * file transfers, because we are single-threaded, we would need two states - * in our machine, one where small requests take place, and another - * specialized for ongoing file transfers. Although this could be - * implemented, it was not a required functionality for this demonstration. - */ - - - -/* - * Configuration - */ -const MAX_CONNECTIONS = 32; -const MAX_CONNECTIONS_ADDR = 4; -const REQUEST_TIMEOUT = 60; - - - -/* - * Open standard error FD for diagnostics output - */ -err = new FD(); -err.set(FD.STDERR_FILENO); - - -/* - * Initialize server - */ -try { - sock = new FD(); - sock.socket(FD.AF_INET, FD.SOCK_STREAM, 0); - sock.bind('127.0.0.1', 1337); - sock.listen(MAX_CONNECTIONS); -} catch (x) { - err.put(x + "\n"); - exit(); -} - - -/* - * Create polling array set and insert bound socket in it - */ -var set = []; -sock.events = FD.POLLIN; -set['bind'] = sock; - - - -/* - * Used for unique index associated to each FD for efficient removal from - * polling set when closing connection - */ -var count = 0; - - -/* - * To know how many connections we are currently serving and limit them - */ -var connections = 0; -var addresses = []; - -function counters_inc(fd) -{ - if (connections >= MAX_CONNECTIONS) - return false; - - var addr = fd.client_addr; - if ((addrcnt = addresses[addr]) != undefined && - addrcnt >= MAX_CONNECTIONS_ADDR) - return false; - - if (addrcnt == undefined) - addrcnt = 1; - else - addrcnt++; - addresses[addr] = addrcnt; - - return true; -} - -function counters_dec(fd) -{ - var addr = fd.client_addr; - if ((--addresses[addr]) == 0) - delete addresses[addr]; - - connections--; -} - - -/* - * Handles client request and replies back - */ -function handle_request(fd) -{ - try { - fd.put( - "HTTP/1.1 200\r\n" + - "Content-type: text/html\r\n" + - "Server: js/1\r\n" + - "Connection: close\r\n" + - "\r\n" + - "Detected!\n" + - "
\n" +
-		    "You are: " + fd.client_addr + ":" + fd.client_port +
-		    "\n" + "ID: " + fd.index + "\n\n" +
-		    "You sent:\n" + fd.request + "\n" +
-		    "
\n" + "

Tracing in progress...

\n" + - "\r\n"); - } catch (x) {} -} - - -/* - * Main server loop - */ -for (;;) { - try { - - /* - * Determine next to expire FD event, so that we can sleep - * as long as possible. Also get rid of expired requests. - */ - var cur = Date.parse(new Date) / 1000; - var exp = cur + 3600; - for (i in set) { - var fd; - - if ((fd = set[i]) == undefined || i == 'bind') - continue; - if (fd.expires <= cur) { - /* - * Request timeout expired for this - * descriptor, we must close it. - */ - fd.close(); - counters_dec(fd); - delete set[fd.index]; - delete fd; - continue; - } - if (fd.expires < exp) - exp = fd.expires; - } - exp -= cur; - - /* - * Poll our set of descriptors for events - */ - var e = FD.poll(set, exp * 1000); - /* - * Verify if a timeout occurred. Because our poll - * implementation returns an array, its timeout event can be - * checked against by verifying if the set is empty. However, - * associative-array/object-attributes are not accounted - * properly with 'length' in JS, so also test fo the case of - * the 'bind' entry. - */ - if (e.length == 0 && e['bind'] == undefined) { - /* Timeout */ - continue; - } - - /* - * Process occurred events. First handle new connections, - * if any. - */ - if (e['bind'] != undefined) { - /* - * New connection, accept it - */ - var fd = sock.accept(); - - if (!counters_inc(fd)) { - fd.put("HTTP/1.1 403.9\r\n" + - "Connection: close\r\n\r\n"); - fd.close(); - delete fd; - } else { - /* - * Associate a new string with FD object - * which will serve to hold the client request - */ - fd.request = ''; - /* - * We add this custom property to efficiently - * be able to remove FD from polling set later - * on - */ - count++; - fd.index = count; - /* - * Set its interesting polling event to - * POLLIN - */ - fd.events = FD.POLLIN; - /* - * Also set request expiration time - */ - fd.expires = (Date.parse(new Date) / 1000) + - REQUEST_TIMEOUT; - /* - * Add descriptor to polling set - */ - set[count] = fd; - } - } - - /* - * Run through set of descriptors with pending events - */ - for (i in e) { - if (e[i] == undefined || i == 'bind') - continue; - if ((e[i].revents & (FD.POLLHUP | FD.POLLERR)) != 0) { - /* - * Unexpected connection loss, close and - * remove from polling set. - */ - e[i].close(); - counters_dec(e[i]); - delete set[e[i].index]; - delete e[i]; - } else if ((e[i].revents & FD.POLLIN) != 0) { - var l, close = false; - - /* - * New data to read from this FD, add to - * request string, verify if we should answer - * and close connection. - * We also limit the maximum request length. - */ - if ((l = e[i].get()) != null) { - if (e[i].length > 32768) - close = true; - else - e[i].request += l; - if (e[i].request.search("\r\n\r\n") - != -1) - close = true; - } else - close = true; - - if (close) { - /* - * Answer and close connection - */ - handle_request(e[i]); - e[i].close(); - counters_dec(e[i]); - /* - * Nice feature, we can hint the - * GC about the fact that we no - * longer refer to, or want these, - * which saves RAM since it avoids - * caching many old useless objects. - */ - delete set[e[i].index]; - delete e[i]; - } - } - } - } catch (x) { - err.put(x + "\n"); - } -} - - -/* NOTREACHED */ - -sock.close(); -err.close(); diff --git a/tests/js-test/js/sock_listen.js b/tests/js-test/js/sock_listen.js deleted file mode 100644 index 55f19e1..0000000 --- a/tests/js-test/js/sock_listen.js +++ /dev/null @@ -1,52 +0,0 @@ -/* $Id: sock_listen.js,v 1.4 2005/04/20 08:50:06 mmondor Exp $ */ - -err = new FD(); -err.set(FD.STDERR_FILENO); - -try { - sock = new FD(); - sock.socket(FD.AF_INET, FD.SOCK_STREAM, 0); - sock.bind('127.0.0.1', 1337); - sock.listen(10); -} catch (x) { - err.put(x + "\n"); -} - -var req = ''; -for (;;) { - try { - fd = sock.accept(); - try { - req = ''; - while (req.length < 32768) { - if ((l = fd.get()) == null) - break; - req += l; - if (l.search("\r\n\r\n")) - break; - } - /* - * Note: because I was asked a few times about this, - * the following is a joke :) we actually don't care - * about the client and won't traceroute, we only - * want client connections to test the program. - */ - fd.put("HTTP/1.1 200\r\nServer: js/1\r\n" + - "Connection: close\r\n" + "\r\n"); - fd.put("Detected!" + - "
\n");
-			fd.put("You are: " + fd.client_addr + ":" +
-			    fd.client_port + "\n\nYou sent:\n" + req + "\n");
-			fd.put("
\n" + "

Tracing in progress...

\n" + - "\r\n"); - } catch (y) { - err.put(y + "\n"); - } - fd.close(); - } catch (x) { - err.put(x + "\n"); - } -} - -sock.close(); -err.close(); diff --git a/tests/js-test/js/test.js b/tests/js-test/js/test.js deleted file mode 100644 index b27fc71..0000000 --- a/tests/js-test/js/test.js +++ /dev/null @@ -1,84 +0,0 @@ -/* $Id: test.js,v 1.1 2004/12/27 11:16:15 mmondor Exp $ */ - - -/* - * The following test should not succeed on API class - */ - -/* {{ */ - -/* -function test(s) -{ - API.print(s); -} - -API.test = test; -API.test("Successfully added method to API class!\n"); -API.test2 = "Successfully added property to API class!\n"; -API.test(API.test2 + "\n"); -*/ - -/* }} */ - - - -/* - * These tests should succeed, however. - */ - -API.print("API.property1 = " + API.property1 + "\n"); -API.print("API.property2 = " + API.property2 + "\n"); -API.print("API.property3 = " + API.property3 + "\n\n"); - -/* - * XXX - * These fail, even though these are permanent and read/write properties. - * JS_SealObject() seems to be converting all read/write properties to - * report an error if setProperty() method is called. However, interestingly - * enough, read/only properties report no error. However, they obviously - * are not modified despite attempts to assign them new values. - */ -API.property1 = 'Hello'; -API.property2 = 911; - -/* - * Following statement should fail, but is simply internally ignored at least - * (the setProperty() method is not called). - */ -API.property3 = 'READONLY!'; - -API.print("API.property1 = " + API.property1 + "\n"); -API.print("API.property2 = " + API.property2 + "\n"); -API.print("API.property3 = " + API.property3 + "\n\n"); - - - -/* - * Perform a test loop, during which callMe() should be called by the - * application code, via the break callback handler function. - */ -for (i = 0; i < 3; i++) { - API.print("We are the: " + Date() + "\n"); - API.print("NetBSD Kernel size is " + - (API.fileSize("/netbsd") / 1024 / 1024) + "MB\n"); - API.print("END\n"); -} -API.print("\n"); - - - -/* - * Will be called by our application if we create it - */ -function callMe(n) -{ - API.print("CallMe(" + n + ")!\n"); -} - - - -/* - * Interesting feature where we can return a value explicitely, optionally - */ -10 diff --git a/tests/js-test/js/test2.js b/tests/js-test/js/test2.js deleted file mode 100644 index 5cb105e..0000000 --- a/tests/js-test/js/test2.js +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: test2.js,v 1.4 2005/02/05 08:07:35 mmondor Exp $ */ - -var file; - -try { - file = new API.File("/etc/hosts"); - API.print("File '" + file.path + "' is loaded (" + file.size + - ") bytes.\n"); - file.release(); -} catch (x) { - API.print("Exception: " + x + "\n"); - exit(); -} - -API.print("Finishing...\n"); diff --git a/tests/js-test/js/test3.js b/tests/js-test/js/test3.js deleted file mode 100644 index c683324..0000000 --- a/tests/js-test/js/test3.js +++ /dev/null @@ -1,46 +0,0 @@ -function Employee() { - this.name = ""; - this.dept = "general"; -} - -function Manager() { - this.reports = []; -} -Manager.prototype = new Employee; - -function WorkerBee() { - this.projects = []; -} -WorkerBee.prototype = new Employee; - -function SalesPerson() { - this.dept = "sales"; - this.quota = 100; -} -SalesPerson.prototype = new WorkerBee; - -function Engineer() { - this.dept = "engineering"; - this.machine = ""; -} -Engineer.prototype = new WorkerBee; - -t = Engineer; -var eng -eng = new t(); -API.print(typeof eng + ', ' + eng.constructor.name); -API.print("\n"); - -/* Interesting test. Dynamically create properties i0 - i9 */ -list = new Object; -for (i = 0; i < 10; i++) { - c = 'list.i' + i + ' = ' + i * i; - eval(c); -} -/* And print the values of our i0 - i9 previously created properties. */ -for (i = 0; i < 10; i++) { - c = 'API.print(\'' + 'list.i' + i + ' = \' + list.i' + i + ' + "\\n")'; - eval(c); -} - -API.print("\nEND\n"); diff --git a/tests/js-test/src/GNUmakefile b/tests/js-test/src/GNUmakefile deleted file mode 100644 index 828cfae..0000000 --- a/tests/js-test/src/GNUmakefile +++ /dev/null @@ -1,29 +0,0 @@ -# $Id: GNUmakefile,v 1.9 2006/07/17 08:55:18 mmondor Exp $ - -#CFLAGS += -g -CFLAGS += -Wall - -JS_CFLAGS := $(shell spidermonkey-config -dc) -JS_LDFLAGS := $(shell spidermonkey-config -dl) - -PG_CFLAGS := $(shell pg_config --cppflags) -PG_LDFLAGS := $(shell pg_config --ldflags) -PG_LDFLAGS += -lpq - -OBJS := $(addprefix classes/,js_fd.o js_errno.o js_signal.o js_pgsql.o) -OBJS += js-server.o - -CFLAGS += $(JS_CFLAGS) $(PG_CFLAGS) -Iclasses -Wall -LDFLAGS += $(JS_LDFLAGS) $(PG_LDFLAGS) - - -all: js-server - -%.o: %.c - cc -c ${CFLAGS} -o $@ $< - -js-server: $(OBJS) - cc -o $@ -lc ${LDFLAGS} $(OBJS) - -clean: - rm -f js-server $(OBJS) diff --git a/tests/js-test/src/classes/js_errno.c b/tests/js-test/src/classes/js_errno.c deleted file mode 100644 index af58462..0000000 --- a/tests/js-test/src/classes/js_errno.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id: js_errno.c,v 1.3 2005/12/12 09:55:15 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Basic UNIX errno services for ECMAScript - */ - - - -#include - -#include -#include -#include -#include -#include - -#include - - - -/* Utility macros */ -#define QUEUE_EXCEPTION(s) do { \ - JS_SetPendingException(cx, \ - STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \ -} while (/* CONSTCOND */0) - - - -/* Prototypes */ -static JSBool errno_sm_strerror(JSContext *, JSObject *, uintN, jsval *, - jsval *); - - - -/* Actual class parameters */ -static JSClass errno_class = { - "Errno", 0, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub -}; - -/* Provided static methods */ -static JSFunctionSpec errno_smethods[] = { - { "strerror", errno_sm_strerror, 1, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - -/* - * Provided static properties. - * We use these to provide ECMAScript with the ability to use system-specific - * standard C constant macros without us having to tidiously map them - * individually, or to require other scripts to be used as headers to define - * them. Another possibility would have been to supply these parameters as - * string, but this would have required even slower remapping because of the - * parsing and string comparisions. - * We only include those which we consider necessary for now, others may be - * added easily as needed, provided that they are added in all three maps. - * I might perhaps develop macros and/or functions to map all these easily - * from a single map. - */ - -struct property_spec { - const char *name; - int value; -}; - -#define SP(n) \ - { #n, n } - -static struct property_spec errno_sprops[] = { - SP(EPERM), - SP(ENOENT), - SP(EINTR), - SP(EIO), - SP(ENXIO), - SP(EBADF), - SP(EACCES), - SP(ENOTBLK), - SP(EBUSY), - SP(EEXIST), - SP(EXDEV), - SP(ENODEV), - SP(ENOTDIR), - SP(EISDIR), - SP(EINVAL), - SP(ENFILE), - SP(EMFILE), - SP(ENOTTY), - SP(ETXTBSY), - SP(EFBIG), - SP(ENOSPC), - SP(ESPIPE), - SP(EROFS), - SP(EMLINK), - SP(EPIPE), - SP(EAGAIN), - SP(EINPROGRESS), - SP(EALREADY), - SP(ENOTSOCK), - SP(EDESTADDRREQ), - SP(EMSGSIZE), - SP(EPROTOTYPE), - SP(EPROTONOSUPPORT), - SP(EOPNOTSUPP), - SP(EPFNOSUPPORT), - SP(EAFNOSUPPORT), - SP(EADDRINUSE), - SP(EADDRNOTAVAIL), - SP(ENETDOWN), - SP(ENETUNREACH), - SP(ENETRESET), - SP(ECONNABORTED), - SP(ECONNRESET), - SP(ENOBUFS), - SP(EISCONN), - SP(ENOTCONN), - SP(ESHUTDOWN), - SP(ETIMEDOUT), - SP(ECONNREFUSED), - SP(ELOOP), - SP(ENAMETOOLONG), - SP(EHOSTDOWN), - SP(EHOSTUNREACH), - SP(ENOTEMPTY), - SP(EDQUOT), - SP(ESTALE), - SP(ENOLCK), - SP(ENOSYS), - SP(EFTYPE), - SP(ENOMSG), - SP(ENOTSUP), - SP(ECANCELED), - SP(EBADMSG), - SP(ENODATA), - SP(ETIME), - - { NULL, 0 } -}; - -#undef SP - - - -/* - * Class control functions - */ - -JSObject * -js_InitErrnoClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *ctor; - struct property_spec *sp; - - if ((proto = JS_InitClass(cx, obj, NULL, &errno_class, NULL, - 0, NULL, NULL, NULL, errno_smethods)) == NULL) { - (void) fprintf(stderr, "Error initializing Errno class\n"); - return NULL; - } - - /* Create static properties */ - if ((ctor = JS_GetConstructor(cx, proto)) == NULL) { - (void) fprintf(stderr, "Errno: JS_GetConstructor == NULL\n"); - return NULL; - } - for (sp = errno_sprops; sp->name != NULL; sp++) { - if (JS_DefineProperty(cx, ctor, sp->name, - INT_TO_JSVAL(sp->value), NULL, NULL, - JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) { - (void) fprintf(stderr, - "Errno: Error defining property %s\n", sp->name); - return NULL; - } - } - - return proto; -} - - - -/* - * Static properties functions - */ - - - -/* - * Static methods - */ - -static JSBool -errno_sm_strerror(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - int error; - JSString *string; - - *rval = OBJECT_TO_JSVAL(NULL); - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - if (!JSVAL_IS_INT(*argv)) { - QUEUE_EXCEPTION("Argument not an integer"); - return JS_FALSE; - } - error = (int)JSVAL_TO_INT(*argv); - - if ((string = JS_NewStringCopyZ(cx, strerror(error))) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - - *rval = STRING_TO_JSVAL(string); - - return JS_TRUE; -} diff --git a/tests/js-test/src/classes/js_errno.h b/tests/js-test/src/classes/js_errno.h deleted file mode 100644 index 22b69bb..0000000 --- a/tests/js-test/src/classes/js_errno.h +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: js_errno.h,v 1.2 2005/07/19 19:25:44 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSERRNO_H -#define JSERRNO_H - -extern JSObject *js_InitErrnoClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/classes/js_fd.c b/tests/js-test/src/classes/js_fd.c deleted file mode 100644 index e0f8a1a..0000000 --- a/tests/js-test/src/classes/js_fd.c +++ /dev/null @@ -1,1971 +0,0 @@ -/* $Id: js_fd.c,v 1.42 2006/07/11 10:25:51 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Basic UNIX filedescriptor and BSD sockets services for ECMAScript - */ - -/* - * XXX TODO XXX - * - Possibly create a byte buffer type - * - Add path based restrictions to open() - * - (maybe) add restrictions to bind() - * - Either add stat() or provide equivalent properties - * - Enhance exception reports. Function name should be provided, and - * errno should be displayed when wanted. Perhaps that jsfd->error could - * also be set automatically when an exception is generated which involves - * errno. - * - Check JS_ReportError(). - * - Moving finalizer freeing and close() freeing code to a common function - * might be a good idea. - * - Add getnameinfo()/getaddrinfo() ? Or should we transparently allow this - * through properties? - * - Add send()/sendto()/sendmsg(), recv()/recvfrom()/recvmsg() ... - * - It is possible that we need to verify that obj is instance of FD in all - * methods, perhaps. I.E. consider an FD method assigned on another object. - * - Add hostname to address and address to hostname resolution facilities - * - Maybe also add properties for local end address/port of socket - * - Would be nice to experiment with a fork(2) heh. If so, if we allow - * fcntl(2) close-on-exec flag, we should make sure to mark FD objects as - * closed too for an execve(2) wrapper. - * - popen(2), would probably need to use custom execve(2) wrapper above... - * - Add support to easily restrict an application's right to functions. - * Path and mode sanity checking functions should also be written and their - * parameters set on a per-application basis. - * - Maybe virtual chdir(2) - * - A stdio FILE extension object might be nice, with stuff like fdopen() to - * create one... This would be most useful for buffered lined based input - * and output. Exporting mmfd library to js might also be nice perhaps, - * either as alternative or addition. - * - mmap(2) - how could I do this without some byte class and associated - * methods? Seems way tricky. - * - lstat(2), fstat(2) - * - dup2() - * - rename(2), unlink(2) etc would be useful, but we need another class - * for this (maybe a VFS static class?) Maybe even something calling - * execve(2) and fork(2), those primitives... popen(3) also. - * - Also opendir(3) and friends wrapper... - */ - - - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - - - -/* Utility macros */ -#define QUEUE_EXCEPTION(s) do { \ - JS_SetPendingException(cx, \ - STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \ -} while (/* CONSTCOND */0) - - -/* Internal representation of FD object */ -typedef struct jsfd { - int fd; - int type; - union { - struct { - char *path; - int flags; - mode_t mode; - } file; - struct { - int domain, type, protocol; - struct sockaddr_in caddr; - } socket; - } u; - /* For polling; Interesting events, and occurred events */ - short events, revents; - /* Last error for this descriptor */ - int error; -} jsfd_t; - -enum jsfd_types { - /* Type */ - JSFD_NONE = 0, /* Initial */ - JSFD_STD = (1 << 1), - JSFD_FILE = (1 << 2), - JSFD_SOCKET = (1 << 3) -}; - -/* Used our fd_sm_poll() function */ -struct poll_fdsi { - char *name; /* Property name or NULL */ - jsval fdobj; /* Pointer to FD object */ - jsfd_t *jsfd; /* Pointer to FD object data */ -}; - -struct poll_fds { - struct pollfd *entries; /* Passed to poll(2) */ - struct poll_fdsi *info; - int count, size; -}; - -/* Functions arguments types */ -enum jsarg_types { - JSAT_INTEGER = 1, - JSAT_DOUBLE, - JSAT_STRING, - JSAT_OBJECT -}; - - -/* Prototypes */ -static JSBool fd_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static void fd_finalize(JSContext *, JSObject *); - -static JSBool fd_getProperty(JSContext *, JSObject *, jsval, jsval *); -static JSBool fd_setProperty(JSContext *, JSObject *, jsval, jsval *); - -static JSBool fd_m_open(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_set(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_close(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_truncate(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool fd_m_put(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_get(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_socket(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_connect(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_bind(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_listen(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_accept(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_shutdown(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool fd_m_setsockopt(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool fd_m_getsockopt(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool fd_m_fcntl(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_write(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_read(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_fdatasync(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool fd_m_lseek(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_fchmod(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_flock(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_m_fstat(JSContext *, JSObject *, uintN, jsval *, jsval *); - -static JSBool fd_sm_poll(JSContext *, JSObject *, uintN, jsval *, jsval *); -static JSBool fd_sm_poll_mkset(JSContext *, jsval *, jsval *, void *); - -static JSBool object_iterate(JSContext *, JSObject *, void *, - JSBool (*)(JSContext *, jsval *, jsval *, void *)); -static int fd_path_allow(const char *); -static mode_t fd_mode_allow(mode_t); -static int fd_flags_allow(int); -static jsfd_t * fd_methods_args_check(JSContext *, JSObject *, const char *, - int, int, jsval *, int); - - - -/* Actual class parameters */ -static JSClass fd_class = { - "FD", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - fd_getProperty, fd_setProperty, JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, fd_finalize -}; - -enum fd_methods_args_enum { - FDMA_SET, - FDMA_CLOSE, - FDMA_TRUNCATE, - FDMA_GET, - FDMA_SOCKET, - FDMA_CONNECT, - FDMA_BIND, - FDMA_LISTEN, - FDMA_ACCEPT, - FDMA_SHUTDOWN, - FDMA_SETSOCKOPT, - FDMA_GETSOCKOPT, - FDMA_FCNTL, - FDMA_READ, - FDMA_WRITE, - FDMA_FDATASYNC, - FDMA_LSEEK, - FDMA_FCHMOD, - FDMA_FLOCK, - FDMA_FSTAT, - FDMA_MAX -}; - -static int fd_methods_args_array[FDMA_MAX][6] = { - { 1, JSAT_INTEGER }, /* SET */ - { 0 }, /* CLOSE */ - { 1, JSAT_DOUBLE }, /* TRUNCATE */ - { 0 }, /* GET */ - { 3, JSAT_INTEGER, JSAT_INTEGER, JSAT_INTEGER },/* SOCKET */ - { 2, JSAT_STRING, JSAT_INTEGER }, /* CONNECT */ - { 2, JSAT_STRING, JSAT_INTEGER }, /* BIND */ - { 1, JSAT_INTEGER }, /* LISTEN */ - { 0 }, /* ACCEPT */ - { 1, JSAT_INTEGER }, /* SHUTDOWN */ - { 2, JSAT_INTEGER, JSAT_INTEGER }, /* SETSOCKOPT */ - { 1, JSAT_INTEGER }, /* GETSOCKOPT */ - { 2, JSAT_INTEGER, JSAT_INTEGER }, /* FCNTL */ - { 1, JSAT_INTEGER }, /* READ */ - { 1, JSAT_STRING }, /* WRITE */ - { 0 }, /* FDATASYNC */ - { 2, JSAT_DOUBLE, JSAT_INTEGER }, /* LSEEK */ - { 1, JSAT_INTEGER }, /* FCHMOD */ - { 1, JSAT_INTEGER }, /* FLOCK */ - { 0 } /* FSTAT */ -}; - -/* Provided methods/functions */ -static JSFunctionSpec fd_methods[] = { - { "open", fd_m_open, 0, 0, 0 }, /* Variable 2-3 parameters */ - { "set", fd_m_set, 1, 0, 0 }, - { "close", fd_m_close, 0, 0, 0 }, - { "truncate", fd_m_truncate, 1, 0, 0 }, - { "put", fd_m_put, 1, 0, 0 }, - { "get", fd_m_get, 0, 0, 0 }, - { "socket", fd_m_socket, 3, 0, 0 }, - { "connect", fd_m_connect, 2, 0, 0 }, - { "bind", fd_m_bind, 2, 0, 0 }, - { "listen", fd_m_listen, 1, 0, 0 }, - { "accept", fd_m_accept, 0, 0, 0 }, - { "shutdown", fd_m_shutdown, 1, 0, 0 }, - { "setsockopt", fd_m_setsockopt, 2, 0, 0 }, - { "getsockopt", fd_m_getsockopt, 1, 0, 0 }, - { "fcntl", fd_m_fcntl, 2, 0, 0 }, - { "read", fd_m_read, 1, 0, 0 }, - { "write", fd_m_write, 1, 0, 0 }, - { "fdatasync", fd_m_fdatasync, 0, 0, 0 }, - { "lseek", fd_m_lseek, 2, 0, 0 }, - { "fchmod", fd_m_fchmod, 1, 0, 0 }, - { "flock", fd_m_flock, 1, 0, 0 }, - { "fstat", fd_m_fstat, 0, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - -/* Provided static methods */ -static JSFunctionSpec fd_smethods[] = { - { "poll", fd_sm_poll, 2, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - -/* Provided properties */ -enum fd_props { - FD_P_PATH = 0, - FD_P_FD, - FD_P_MODE, - FD_P_EVENTS, - FD_P_REVENTS, - FD_P_ERRNO, - FD_P_CLIENT_ADDR, - FD_P_CLIENT_PORT, - FD_P_MAX -}; - -static JSPropertySpec fd_properties[FD_P_MAX + 1] = { - { "path", FD_P_PATH, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL }, - { "fd", FD_P_FD, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL }, - { "mode", FD_P_MODE, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL }, - { "events", FD_P_EVENTS, JSPROP_ENUMERATE, NULL, NULL }, - { "revents", FD_P_REVENTS, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, - NULL }, - { "errno", FD_P_ERRNO, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, - NULL }, - { "client_addr", FD_P_CLIENT_ADDR, JSPROP_ENUMERATE | JSPROP_READONLY, - NULL, NULL }, - { "client_port", FD_P_CLIENT_PORT, JSPROP_ENUMERATE | JSPROP_READONLY, - NULL, NULL }, - { NULL, 0, 0, NULL, NULL } -}; - -/* - * Provided static properties. - * We use these to provide ECMAScript with the ability to use system-specific - * standard C constant macros without us having to tidiously map them - * individually, or to require other scripts to be used as headers to define - * them. Another possibility would have been to supply these parameters as - * string, but this would have required even slower remapping because of the - * parsing and string comparisions. - * We only include those which we consider necessary for now, others may be - * added easily as needed, provided that they are added in all three maps. - * I might perhaps develop macros and/or functions to map all these easily - * from a single map. - */ - -struct property_spec { - const char *name; - int value; -}; - -#define SP(n) \ - { #n, n } - -static struct property_spec fd_sprops[] = { - SP(STDIN_FILENO), - SP(STDOUT_FILENO), - SP(STDERR_FILENO), - - SP(O_RDONLY), - SP(O_WRONLY), - SP(O_RDWR), - SP(O_APPEND), - SP(O_CREAT), - SP(O_TRUNC), - SP(O_NONBLOCK), - - SP(POLLIN), - SP(POLLRDNORM), - SP(POLLRDBAND), - SP(POLLPRI), - SP(POLLOUT), - SP(POLLWRNORM), - SP(POLLWRBAND), - SP(POLLERR), - SP(POLLHUP), - SP(POLLNVAL), - - SP(SHUT_RD), - SP(SHUT_WR), - SP(SHUT_RDWR), - - SP(AF_INET), - SP(SOCK_STREAM), - SP(SOCK_DGRAM), - - SP(SO_REUSEADDR), - SP(SO_REUSEPORT), - SP(SO_KEEPALIVE), - SP(SO_DONTROUTE), - SP(SO_LINGER), - SP(SO_BROADCAST), - SP(SO_OOBINLINE), - SP(SO_SNDBUF), - SP(SO_RCVBUF), - SP(SO_SNDLOWAT), - SP(SO_RCVLOWAT), - SP(SO_SNDTIMEO), - SP(SO_RCVTIMEO), - SP(SO_TIMESTAMP), - SP(SO_TYPE), - SP(SO_ERROR), - SP(TCP_NODELAY), - - SP(F_SETFL), - SP(F_GETFL), - - SP(SEEK_SET), - SP(SEEK_CUR), - SP(SEEK_END), - - SP(S_IRWXU), - SP(S_IRUSR), - SP(S_IWUSR), - SP(S_IXUSR), - SP(S_IRWXG), - SP(S_IRGRP), - SP(S_IXGRP), - SP(S_IRWXO), - SP(S_IROTH), - SP(S_IWOTH), - SP(S_IXOTH), - SP(S_ISUID), - SP(S_ISGID), - SP(S_ISVTX), - SP(S_IFMT), - SP(S_IFIFO), - SP(S_IFCHR), - SP(S_IFDIR), - SP(S_IFBLK), - SP(S_IFREG), - SP(S_IFLNK), - SP(S_IFSOCK), - SP(S_IFWHT), - SP(UF_NODUMP), - SP(UF_IMMUTABLE), - SP(UF_APPEND), - SP(UF_OPAQUE), - SP(SF_ARCHIVED), - SP(SF_IMMUTABLE), - SP(SF_APPEND), - - SP(LOCK_SH), - SP(LOCK_EX), - SP(LOCK_NB), - SP(LOCK_UN), - - { NULL, 0 } -}; - -#undef SP - - - -/* - * Miscelaneous static globals - */ - -/* XXX Should be initialized at main process startup ideally */ -static int tcp_proto = -1; -static char *read_charbuf = NULL; -static size_t read_charbuf_size = 0; - - - -/* - * Class control functions - */ - -JSObject * -js_InitFDClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *ctor; - struct property_spec *sp; - - if ((proto = JS_InitClass(cx, obj, NULL, &fd_class, fd_constructor, - 0, fd_properties, fd_methods, NULL, fd_smethods)) - == NULL) { - (void) fprintf(stderr, "Error initializing FD class\n"); - return NULL; - } - - /* Create static properties. Should probably be a function. */ - - if ((ctor = JS_GetConstructor(cx, proto)) == NULL) { - (void) fprintf(stderr, "FD: JS_GetConstructor == NULL\n"); - return NULL; - } - for (sp = fd_sprops; sp->name != NULL; sp++) { - if (JS_DefineProperty(cx, ctor, sp->name, - INT_TO_JSVAL(sp->value), NULL, NULL, - JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) { - (void) fprintf(stderr, - "FD: Error defining property %s\n", sp->name); - return NULL; - } - } - - return proto; -} - -static JSBool -fd_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd = NULL; - - if (argc != 0) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - - /* - * IMPORTANT: We must verify if the caller attempts to execute us as a - * normal function rather than as a constructor. Otherwise, the - * caller can cause the interpreter to abort(3) in an assertion in - * JS_SetPrivate()! - */ - if (!JS_IsConstructing(cx)) { - QUEUE_EXCEPTION("Constructor called as a function"); - goto err; - } - - if ((jsfd = JS_malloc(cx, sizeof(jsfd_t))) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - - jsfd->fd = -1; - jsfd->type = JSFD_NONE; - jsfd->events = jsfd->revents = 0; - jsfd->error = 0; - - if (!JS_SetPrivate(cx, obj, jsfd)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (jsfd != NULL) - JS_free(cx, jsfd); - - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; -} - -static void -fd_finalize(JSContext *cx, JSObject *obj) -{ - jsfd_t *jsfd; - - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) != NULL) { - /* Only close if not one of std descriptors */ - if (jsfd->fd != -1 && jsfd->type != JSFD_STD) { - (void) close(jsfd->fd); - jsfd->fd = -1; - jsfd->type = JSFD_NONE; - } - if (jsfd->type == JSFD_FILE && jsfd->u.file.path != NULL) { - JS_free(cx, jsfd->u.file.path); - jsfd->u.file.path = NULL; - } - JS_free(cx, jsfd); - (void) JS_SetPrivate(cx, obj, NULL); - } -} - - -/* - * Property functions - */ - -static JSBool -fd_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - jsfd_t *jsfd; - jsint p; - - if (!JSVAL_IS_INT(id)) - return JS_TRUE; - p = (int)JSVAL_TO_INT(id); - - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) == NULL) - return JS_TRUE; - if (jsfd->fd == -1) - return JS_TRUE; - - switch (p) { - case FD_P_PATH: - if (jsfd->type == JSFD_FILE) { - JSString *string; - - if ((string = JS_NewStringCopyZ(cx, - jsfd->u.file.path)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - *vp = STRING_TO_JSVAL(string); - } - break; - case FD_P_FD: - *vp = INT_TO_JSVAL(jsfd->fd); - break; - case FD_P_MODE: - if (jsfd->type == JSFD_FILE) - *vp = INT_TO_JSVAL((int)jsfd->u.file.mode); - break; - case FD_P_EVENTS: - *vp = INT_TO_JSVAL((int)jsfd->events); - break; - case FD_P_REVENTS: - *vp = INT_TO_JSVAL((int)jsfd->revents); - break; - case FD_P_ERRNO: - *vp = INT_TO_JSVAL(jsfd->error); - break; - case FD_P_CLIENT_ADDR: - if (jsfd->type == JSFD_SOCKET) { - char addr[16]; - JSString *string; - - if (inet_ntop(AF_INET, &jsfd->u.socket.caddr.sin_addr, - addr, 15) == NULL) { - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - if ((string = JS_NewStringCopyZ(cx, addr)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - *vp = STRING_TO_JSVAL(string); - } - break; - case FD_P_CLIENT_PORT: - if (jsfd->type == JSFD_SOCKET) { - *vp = INT_TO_JSVAL((int)ntohs(jsfd-> - u.socket.caddr.sin_port)); - } - break; - } - - return JS_TRUE; -} - -static JSBool -fd_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - jsfd_t *jsfd; - jsint p; - - if (!JSVAL_IS_INT(id)) - return JS_TRUE; - p = (int)JSVAL_TO_INT(id); - - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) == NULL) - return JS_TRUE; - if (jsfd->fd == -1) - return JS_TRUE; - - switch (p) { - case FD_P_EVENTS: - if (!JSVAL_IS_INT(*vp)) { - QUEUE_EXCEPTION( - "FD_P_EVENTS property requires an int"); - return JS_FALSE; - } - jsfd->events = (short)JSVAL_TO_INT(*vp); - break; - } - - return JS_TRUE; -} - - -/* - * Static properties functions - */ - - -/* - * Method functions - */ - -static JSBool -fd_m_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - int fd, flags; - mode_t mode = 0644; - char *bytes; - - *rval = OBJECT_TO_JSVAL(NULL); - - /* - * We use custom arguments checking here since we can accept both - * 2 or 3. - */ - if (argc < 2 || argc > 3) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("First argument must be a string"); - return JS_FALSE; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Second argument must be an integer"); - return JS_FALSE; - } - if (argc == 3 && !JSVAL_IS_INT(argv[2])) { - QUEUE_EXCEPTION("Third argument must be an integer"); - return JS_FALSE; - } - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) == NULL) { - QUEUE_EXCEPTION("Null private data!"); - return JS_FALSE; - } - if (jsfd->type != JSFD_NONE) { - QUEUE_EXCEPTION("Descriptor already open"); - return JS_FALSE; - } - - if (argc == 3) { - /* - * Mode, supplied as an int. - */ - mode = (mode_t)JSVAL_TO_INT(argv[2]); - if ((mode = fd_mode_allow(mode)) == (mode_t)-1) { - QUEUE_EXCEPTION("Mode not permitted"); - return JS_FALSE; - } - } - - /* - * Flags, provided as an int. - */ - flags = JSVAL_TO_INT(argv[1]); - if ((flags = fd_flags_allow(flags)) == -1) { - QUEUE_EXCEPTION("Flag not permitted"); - return JS_FALSE; - } - - /* Path, provided as a string */ - if ((bytes = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))) == NULL) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - /* Perform path sanity checking */ - if (fd_path_allow(bytes) == -1) { - QUEUE_EXCEPTION("Invalid path"); - return JS_FALSE; - } - if ((jsfd->u.file.path = JS_strdup(cx, bytes)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - - /* We can finally attempt to open(2) */ - if ((fd = open(bytes, flags, mode)) == -1) { - jsfd->error = errno; - /* - * XXX strerror() seems to always need to load up the - * nls table file, which is way silly for performance. - * This is related to locale stuff, and should be able - * to simply be disabled, even. - * Since this event occurs often in httpd.js, let's just - * output a fixed string for now. - * I should actually fix NetBSD libc on this matter. - */ -/* QUEUE_EXCEPTION(strerror(errno)); */ - QUEUE_EXCEPTION("open() error"); - JS_free(cx, jsfd->u.file.path); - return JS_FALSE; - } - - /* Success! */ - jsfd->fd = fd; - jsfd->type = JSFD_FILE; - jsfd->u.file.flags = flags; - jsfd->u.file.mode = mode; - - return JS_TRUE; -} - -static JSBool -fd_m_set(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - int32_t fd; - jsfd_t *jsfd; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "set", FDMA_SET, argc, - argv, JSFD_NONE)) == NULL) - return JS_FALSE; - - fd = JSVAL_TO_INT(*argv); - if (fd < STDIN_FILENO || fd > STDERR_FILENO) { - QUEUE_EXCEPTION("Unknown standard descriptor"); - return JS_FALSE; - } - jsfd->fd = fd; - jsfd->type = JSFD_STD; - - return JS_TRUE; -} - -static JSBool -fd_m_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - int error; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "close", FDMA_CLOSE, argc, - argv, JSFD_STD | JSFD_FILE | JSFD_SOCKET)) == NULL) - return JS_FALSE; - - if (jsfd->type == JSFD_STD) { - jsfd->fd = -1; - jsfd->type = JSFD_NONE; - return JS_TRUE; - } - - if (jsfd->type == JSFD_FILE) { - if (jsfd->u.file.path != NULL) { - JS_free(cx, jsfd->u.file.path); - jsfd->u.file.path = NULL; - } - } - - error = close(jsfd->fd); - jsfd->fd = -1; - jsfd->type = JSFD_NONE; - - if (error == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - off_t size; - jsdouble dsize; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "truncate", FDMA_TRUNCATE, - argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - if (!JS_ValueToNumber(cx, *argv, &dsize)) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - size = (off_t)dsize; - - if (ftruncate(jsfd->fd, size) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_put(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - JSString *str; - char *bytes; - ssize_t size; - - *rval = OBJECT_TO_JSVAL(NULL); - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) == NULL) { - QUEUE_EXCEPTION("Null private data!"); - return JS_FALSE; - } - - if (jsfd->fd == -1) { - QUEUE_EXCEPTION("Descriptor closed"); - return JS_FALSE; - } - - /* - * Instead of verifying if supplied value really is a JSString, and - * using JSVAL_TO_STRING(), we convert the value to a string in this - * case. - */ - if ((str = JS_ValueToString(cx, *argv)) == NULL || - (bytes = JS_GetStringBytes(str)) == NULL) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - - size = strlen(bytes); - if ((size = write(jsfd->fd, bytes, size)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - *rval = INT_TO_JSVAL((int)size); - - return JS_TRUE; -} - -static JSBool -fd_m_get(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - char bytes[4096]; - ssize_t size; - JSString *string; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "get", FDMA_GET, argc, - argv, JSFD_STD | JSFD_FILE | JSFD_SOCKET)) == NULL) - return JS_FALSE; - - if ((size = read(jsfd->fd, bytes, 4096)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - if (size == 0) - return JS_TRUE; - - if ((string = JS_NewStringCopyN(cx, bytes, size)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - *rval = STRING_TO_JSVAL(string); - - return JS_TRUE; -} - -static JSBool -fd_m_socket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - int domain, type, protocol, error; - jsfd_t *jsfd; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "socket", FDMA_SOCKET, - argc, argv, JSFD_NONE)) == NULL) - return JS_FALSE; - - domain = (int)JSVAL_TO_INT(argv[0]); - type = (int)JSVAL_TO_INT(argv[1]); - protocol = (int)JSVAL_TO_INT(argv[2]); - - /* Sanity checking on currently supported protocols */ - if (domain != AF_INET || (type != SOCK_DGRAM && type != SOCK_STREAM) - || protocol != 0) { - QUEUE_EXCEPTION("Unsupported protocol"); - return JS_FALSE; - } - - if ((error = socket(domain, type, protocol)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - jsfd->fd = error; - jsfd->type = JSFD_SOCKET; - jsfd->u.socket.domain = domain; - jsfd->u.socket.type = type; - jsfd->u.socket.protocol = protocol; - - return JS_TRUE; -} - -/* - * We currently make this rather simple; If the supplied string doesn't - * consist of a valid IPv4 address, we simply attempt to resolve it, and on - * success then attempt connection. - */ -static JSBool -fd_m_connect(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - char *address; - struct sockaddr_in sinaddr; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "connect", FDMA_CONNECT, - argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - address = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - if (inet_pton(AF_INET, address, &sinaddr.sin_addr) != 1) { - struct hostent *h; - - /* - * Not a valid IPv4 address, consider it as a hostname and - * attempt to resolve it. - * XXX Note: Not thread safe unless a global mutex/rwlock is - * used. Should use getaddrinfo(3) instead. Especially if we - * someday want to support other address families than - * AF_INET. - */ - if ((h = gethostbyname(address)) == NULL) { - jsfd->error = errno; - QUEUE_EXCEPTION("Invalid address or hostname"); - return JS_FALSE; - } - sinaddr.sin_addr.s_addr = - ((struct in_addr *)h->h_addr_list[0])->s_addr; - } - sinaddr.sin_port = htons((in_port_t)JSVAL_TO_INT(argv[1])); - - if (connect(jsfd->fd, (struct sockaddr *)&sinaddr, - sizeof(struct sockaddr_in)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_bind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - struct sockaddr_in sinaddr; - char *address; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "bind", FDMA_BIND, argc, - argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - address = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - if (inet_pton(AF_INET, address, &sinaddr.sin_addr) != 1) { - QUEUE_EXCEPTION("Invalid IP address"); - return JS_FALSE; - } - sinaddr.sin_port = htons((in_port_t)JSVAL_TO_INT(argv[1])); - - if (bind(jsfd->fd, (struct sockaddr *)&sinaddr, - sizeof(struct sockaddr_in)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_listen(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "listen", FDMA_LISTEN, - argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - if (listen(jsfd->fd, (int)JSVAL_TO_INT(*argv)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_accept(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd, *njsfd; - int sock; - struct sockaddr_in sinaddr; - socklen_t socklen; - JSObject *nobj; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "accept", FDMA_ACCEPT, - argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - socklen = sizeof(struct sockaddr_in); - if ((sock = accept(jsfd->fd, (struct sockaddr *)&sinaddr, &socklen)) - == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - /* - * Success, create new FD object, fill it and return it. - */ - if ((nobj = JS_ConstructObject(cx, &fd_class, obj, obj)) == NULL) { - (void) close(sock); - QUEUE_EXCEPTION("Out of resources"); - return JS_FALSE; - } - njsfd = JS_GetInstancePrivate(cx, nobj, &fd_class, NULL); - njsfd->fd = sock; - njsfd->type = JSFD_SOCKET; - njsfd->u.socket.domain = jsfd->u.socket.domain; - njsfd->u.socket.type = jsfd->u.socket.type; - njsfd->u.socket.protocol = jsfd->u.socket.protocol; - (void) memcpy(&njsfd->u.socket.caddr, &sinaddr, - sizeof(struct sockaddr_in)); - - *rval = OBJECT_TO_JSVAL(nobj); - - return JS_TRUE; -} - -static JSBool -fd_m_shutdown(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "shutdown", FDMA_SHUTDOWN, - argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - if (shutdown(jsfd->fd, (int)JSVAL_TO_INT(*argv)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -/* - * XXX Not thread safe ATM as it uses a static int with test-and-set operation - * to only query the protocol database once. This could be done at early - * process initialization alternatively. - * Unlike BSD/POSIX setsockopt(2), always requires a single integer value (-1 - * in the case of SO_LINGER to disable it, or the number of seconds to - * linger to enable it). - */ -static JSBool -fd_m_setsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - void *opt; - struct linger l; - int optname, level, optval; - socklen_t optlen; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "setsockopt", - FDMA_SETSOCKOPT, argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - optname = JSVAL_TO_INT(argv[0]); - optval = JSVAL_TO_INT(argv[1]); - - /* - * Work out special case for SO_LINGER - */ - if (optname == SO_LINGER) { - if (optval == -1) { - l.l_onoff = 0; - l.l_linger = 0; - } else { - l.l_onoff = 1; - l.l_linger = optval; - } - opt = &l; - optlen = sizeof(struct linger); - } else { - opt = &optval; - optlen = sizeof(int); - optval = (optval != 0 ? 1 : 0); - } - - /* - * And for TCP_NODELAY which must use tcp_proto as level - */ - if (optname == TCP_NODELAY) { - if (tcp_proto == -1) { - struct protoent *pent; - - if ((pent = getprotobyname("TCP")) != NULL) - tcp_proto = pent->p_proto; - else - tcp_proto = 4; /* Generally allright */ - } - level = tcp_proto; - } else - level = SOL_SOCKET; - - if (setsockopt(jsfd->fd, level, optname, opt, optlen) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -/* - * XXX Not thread safe ATM as it uses a static int with test-and-set operation - * to only query the protocol database once. This could be done at early - * process initialization alternatively. - * Unlike BSD/POSIX getsockopt(2), always returns a single integer value (-1 - * in the case of SO_LINGER disabled, or the number of seconds assigned to - * wait if enabled). - */ -static JSBool -fd_m_getsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - void *opt; - struct linger l; - int i, optname, level, result; - socklen_t optlen; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "getsockopt", - FDMA_GETSOCKOPT, argc, argv, JSFD_SOCKET)) == NULL) - return JS_FALSE; - - optname = JSVAL_TO_INT(*argv); - - /* - * Special case for SO_LINGER which expects a structure rather than an - * integer - */ - if (optname == SO_LINGER) { - opt = &l; - optlen = sizeof(struct linger); - } else { - opt = &i; - optlen = sizeof(int); - } - - /* - * And for TCP_NODELAY which must use TCP protocol number rather than - * SOL_SOCKET level - */ - if (optname == TCP_NODELAY) { - if (tcp_proto == -1) { - struct protoent *pent; - - if ((pent = getprotobyname("TCP")) != NULL) - tcp_proto = pent->p_proto; - else - tcp_proto = 4; /* Generally allright */ - } - level = tcp_proto; - } else - level = SOL_SOCKET; - - if (getsockopt(jsfd->fd, level, optname, opt, &optlen) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - /* - * To simplify the implementation, special case of SO_LINGER result; - * We return -1 if lingering is disabled, or otherwise return the - * number of seconds it should linger for maximum. - */ - if (optname == SO_LINGER) { - if (l.l_onoff != 0) - result = l.l_linger; - else - result = -1; - } else - /* - * These are booleans, so ensure proper return value despite - * several implementations which return a mask rather than 0/1 - */ - result = (i != 0 ? 1 : 0); - - *rval = INT_TO_JSVAL(result); - - return JS_TRUE; -} - -/* - * Unlike POSIX fcntl(2), only currently supports F_GETFL and F_SETFL along - * with O_NONBLOCK and O_APPEND. The flags argument is also mandatory, which - * will serve as a result mask for F_GETFL or to set wanted flags using - * F_SETFL. The previous flags are returned as usual (but will only ever - * include 0, O_NONBLOCK and/or O_APPEND). - */ -static JSBool -fd_m_fcntl(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - int cmd, flags, error; - - *rval = INT_TO_JSVAL(0); - - if ((jsfd = fd_methods_args_check(cx, obj, "fcntl", FDMA_FCNTL, - argc, argv, JSFD_FILE | JSFD_SOCKET)) == NULL) - return JS_FALSE; - - cmd = JSVAL_TO_INT(argv[0]); - flags = JSVAL_TO_INT(argv[1]); - - if (cmd != F_GETFL && cmd != F_SETFL) { - QUEUE_EXCEPTION("Unimplemented fcntl() command"); - return JS_FALSE; - } - flags &= (O_NONBLOCK | O_APPEND); - if ((flags & O_NONBLOCK) == 0 && (flags & O_APPEND) == 0) { - QUEUE_EXCEPTION("Unimplemented fcntl() flag"); - return JS_FALSE; - } - - if (cmd == F_GETFL) { - if ((error = fcntl(jsfd->fd, cmd, NULL)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - error &= flags; - } else { - if ((error = fcntl(jsfd->fd, cmd, flags)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - error &= (O_NONBLOCK | O_APPEND); - } - - *rval = INT_TO_JSVAL(error); - - return JS_TRUE; -} - -static JSBool -fd_m_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - size_t size; - ssize_t rsize; - JSString *string; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "read", FDMA_READ, - argc, argv, JSFD_FILE | JSFD_SOCKET)) == NULL) - return JS_FALSE; - - size = (size_t)JSVAL_TO_INT(*argv); - if (size < 1) { - QUEUE_EXCEPTION("read() requested size smaller than 1"); - return JS_FALSE; - } - - /* - * Ensure that our read buffer is ready, and of a large enough size - * to accomodate read. - */ - if (read_charbuf_size < size) { - if (read_charbuf == NULL) { - /* Never allocated yet, simply allocate */ - if ((read_charbuf = malloc(size)) == NULL) { - QUEUE_EXCEPTION("Cannot allocate read buffer"); - return JS_FALSE; - } - } else { - char *ptr; - - /* Buffer too small, attempt to increase it */ - if ((ptr = realloc(read_charbuf, size)) == NULL) { - QUEUE_EXCEPTION( - "Cannot reallocate read buffer"); - return JS_FALSE; - } - read_charbuf = ptr; - } - read_charbuf_size = size; - } - - if ((rsize = read(jsfd->fd, read_charbuf, size)) == -1) { - /* - * XXX Should we really throw an exception, or simply return - * an error? For instance, if using nonblocking mode and - * expecting EAGAIN, would using an exception clubber - * unnecessarily the code? - */ - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - if (size == 0) - return JS_TRUE; - - if ((string = JS_NewStringCopyN(cx, read_charbuf, rsize)) == NULL) { - QUEUE_EXCEPTION("Couldn't allocate read result string"); - return JS_FALSE; - } - *rval = STRING_TO_JSVAL(string); - - return JS_TRUE; -} - -static JSBool -fd_m_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - ssize_t rsize; - JSString *str; - char *bytes; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "write", FDMA_WRITE, - argc, argv, JSFD_FILE | JSFD_SOCKET)) == NULL) - return JS_FALSE; - - str = JSVAL_TO_STRING(*argv); - if ((bytes = JS_GetStringBytes(str)) == NULL) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - - if ((rsize = write(jsfd->fd, bytes, JS_GetStringLength(str))) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - *rval = INT_TO_JSVAL((int)rsize); - - return JS_TRUE; -} - -static JSBool -fd_m_fdatasync(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsfd_t *jsfd; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "fdatasync", - FDMA_FDATASYNC, argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - if (fdatasync(jsfd->fd) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_lseek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - off_t off, newoff; - int whence; - jsdouble doff; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "lseek", FDMA_LSEEK, - argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - if (!JS_ValueToNumber(cx, argv[0], &doff)) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - off = (off_t)doff; - whence = JSVAL_TO_INT(argv[1]); - - if ((newoff = lseek(jsfd->fd, off, whence)) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - if (!JS_NewDoubleValue(cx, (jsdouble)newoff, rval)) { - QUEUE_EXCEPTION("Internal error"); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_fchmod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - mode_t mode; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "fchmod", FDMA_FCHMOD, - argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - mode = (mode_t)JSVAL_TO_INT(*argv); - if ((mode = fd_mode_allow(mode)) == (mode_t)-1) { - QUEUE_EXCEPTION("Mode not permitted"); - return JS_FALSE; - } - - if (fchmod(jsfd->fd, mode) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_flock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - int op; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "flock", FDMA_FLOCK, - argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - op = JSVAL_TO_INT(*argv); - if (flock(jsfd->fd, op) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - return JS_TRUE; -} - -static JSBool -fd_m_fstat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - jsfd_t *jsfd; - struct stat st; - JSObject *array = NULL; - jsval val; - - *rval = OBJECT_TO_JSVAL(NULL); - - if ((jsfd = fd_methods_args_check(cx, obj, "fstat", FDMA_FSTAT, - argc, argv, JSFD_FILE)) == NULL) - return JS_FALSE; - - if (fstat(jsfd->fd, &st) == -1) { - jsfd->error = errno; - QUEUE_EXCEPTION(strerror(errno)); - return JS_FALSE; - } - - /* - * Note: We immediately link newly created objects to avoid GC - * problems. For the simplicity of this task we don't need an - * additional root to be created using JS_AddRoot(), since *rval - * is already rooted. Moreover, the double objects we create are - * immediately added as propery as well. - */ - - if ((array = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - *rval = OBJECT_TO_JSVAL(array); - -#define DEFINE_INT_PROP(n, i) do { \ - val = INT_TO_JSVAL((int)(i)); \ - if (!JS_DefineProperty(cx, array, (n), val, NULL, NULL, \ - JSPROP_ENUMERATE)) { \ - QUEUE_EXCEPTION("Internal error!"); \ - goto err; \ - } \ -} while (/* CONSTCOND */0) - -#define DEFINE_DOUBLE_PROP(n, d) do { \ - if (!JS_NewDoubleValue(cx, (jsdouble)(d), &val)) \ - goto err; \ - if (!JS_DefineProperty(cx, array, (n), val, NULL, NULL, \ - JSPROP_ENUMERATE)) { \ - QUEUE_EXCEPTION("Internal error!"); \ - goto err; \ - } \ -} while (/* CONSTCOND */0) - - DEFINE_INT_PROP("st_dev", st.st_dev); - DEFINE_INT_PROP("st_ino", st.st_ino); - DEFINE_INT_PROP("st_mode", st.st_mode); - DEFINE_INT_PROP("st_nlink", st.st_nlink); - DEFINE_INT_PROP("st_uid", st.st_uid); - DEFINE_INT_PROP("st_gid", st.st_gid); - DEFINE_INT_PROP("st_rdev", st.st_rdev); - DEFINE_DOUBLE_PROP("st_atime", st.st_atime); - DEFINE_DOUBLE_PROP("st_mtime", st.st_mtime); - DEFINE_DOUBLE_PROP("st_ctime", st.st_ctime); - DEFINE_DOUBLE_PROP("st_size", st.st_size); - DEFINE_DOUBLE_PROP("st_blocks", st.st_blocks); - DEFINE_INT_PROP("st_blksize", st.st_blksize); - DEFINE_INT_PROP("st_flags", st.st_flags); - DEFINE_INT_PROP("st_gen", st.st_gen); - -#undef DEFINE_INT_PROP -#undef DEFINE_DOUBLE_PROP - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - - - -/* - * Static methods - */ - -static JSBool -fd_sm_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - struct poll_fds fds; - int nfds, timeout, i; - JSObject *array = NULL; - jsint index; - - *rval = OBJECT_TO_JSVAL(NULL); - - if (argc != 2) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - - /* - * First make sure that user supplied object really consists of an - * array. - */ - if (!JSVAL_IS_OBJECT(argv[0]) || - !JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[0]))) { - QUEUE_EXCEPTION("First argument must be Array object"); - return JS_FALSE; - } - - /* - * Obtain timeout from argv[1] - */ - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Second argument must be timeout integer"); - return JS_FALSE; - } - timeout = (int)JSVAL_TO_INT(argv[1]); - - /* - * Create our pollfd array, iterating through all FD objects of the - * user-provided array object. - */ - if ((fds.entries = malloc(sizeof(struct pollfd) * 16)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - if ((fds.info = malloc(sizeof(struct poll_fdsi) * 16)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - fds.count = 0; - fds.size = 16; - if (!object_iterate(cx, JSVAL_TO_OBJECT(argv[0]), &fds, - fd_sm_poll_mkset)) - goto err; - - /* - * Finally perform actual polling - */ - if ((nfds = poll(fds.entries, fds.count, timeout)) == -1) { - QUEUE_EXCEPTION(strerror(errno)); - goto err; - } - - /* - * Now set FD objects event field and create custom array object to - * return to the caller, only holding entries for which events - * occurred. - * Link object immediately to avoid GC problems or needing - * JS_AddRoot(). - */ - if ((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - *rval = OBJECT_TO_JSVAL(array); - - for (i = 0, index = 0; i < fds.count && nfds != 0; i++) { - if (fds.entries[i].revents != 0) { - nfds--; - fds.info[i].jsfd->revents = fds.entries[i].revents; - /* - * Add an element if numeric index entry, or a - * property if name based/associative entry. - */ - if (fds.info[i].name == NULL) { - if (!JS_DefineElement(cx, array, index++, - fds.info[i].fdobj, NULL, NULL, - JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - } else { - if (!JS_DefineProperty(cx, array, - fds.info[i].name, fds.info[i].fdobj, NULL, - NULL, JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - } - } - } - - free(fds.entries); - free(fds.info); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - if (fds.entries != NULL) - free(fds.entries); - if (fds.info != NULL) - free(fds.info); - - return JS_FALSE; -} - -static JSBool -fd_sm_poll_mkset(JSContext *cx, jsval *id, jsval *val, void *udata) -{ - struct poll_fds *fds = (struct poll_fds *)udata; - JSObject *o; - jsfd_t *jsfd; - - if (!JSVAL_IS_OBJECT(*val) || - !JS_InstanceOf(cx, (o = JSVAL_TO_OBJECT(*val)), &fd_class, NULL)) { - QUEUE_EXCEPTION("Not FD object"); - return JS_FALSE; - } - if ((jsfd = JS_GetInstancePrivate(cx, o, &fd_class, NULL)) == NULL) { - QUEUE_EXCEPTION("Null private data!"); - return JS_FALSE; - } - - if (fds->count == fds->size) { - void *ptr; - - /* Need to grow entries and names */ - if ((ptr = realloc(fds->entries, - sizeof(struct pollfd) * fds->size * 2)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - fds->entries = ptr; - if ((ptr = realloc(fds->info, - sizeof(struct poll_fdsi) * fds->size * 2)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - fds->info = ptr; - fds->size *= 2; - } - - /* - * Add new entry. If it's a property (associative array entry), also - * fill in the name pointer which will be used to recreate the result - * array with those names as well. We set the name to NULL for index - * based array entries. - */ - fds->entries[fds->count].fd = jsfd->fd; - fds->entries[fds->count].events = jsfd->events; - fds->entries[fds->count].revents = 0; - if (JSVAL_IS_STRING(*id)) - fds->info[fds->count].name = - JS_GetStringBytes(JSVAL_TO_STRING(*id)); - else - fds->info[fds->count].name = NULL; - fds->info[fds->count].fdobj = *val; - fds->info[fds->count++].jsfd = jsfd; - - return JS_TRUE; -} - - -/* - * Utility functions - */ - -/* - * Was written to be able to iterate over all elements of an array object, - * despite being an associated array or not, or a mix of both. Unfortunately - * uses marked as private JSIdArray structure. - * This was needed because arrays are using indexes, while associative arrays - * are nothing more than an object with its properties. This function can - * deal with both. - */ -static JSBool -object_iterate(JSContext *cx, JSObject *obj, void *udata, - JSBool (*func)(JSContext *, jsval *, jsval *, void *)) -{ - JSIdArray *a; - jsval id, val; - char *name; - jsint i; - JSBool ret = JS_FALSE; - - if ((a = JS_Enumerate(cx, obj)) != NULL) { - for (i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JSVAL_IS_STRING(id)) { - /* - * Property id is a string, attempt to - * lookup its value by name. - */ - name = JS_GetStringBytes(JSVAL_TO_STRING(id)); - if (!JS_LookupProperty(cx, obj, name, &val)) - continue; - } else { - /* - * Property id is a number, attempt to - * lookup its array element by index. - */ - if (!JS_LookupElement(cx, obj, - JSVAL_TO_INT(id), &val)) - continue; - } - if (!JSVAL_IS_VOID(val)) { - if (!(ret = func(cx, &id, &val, udata))) - break; - } - } - JS_DestroyIdArray(cx, a); - } - - return ret; -} - -/* - * Utility function return 0 if user supplied path should be allowed, or -1 if - * it should be rejected (invalid, or permission denied). This can for - * instance be used to restrict the program in a virtual chroot(2)-like jail. - */ -/* ARGSUSED */ -static int -fd_path_allow(const char *path) -{ - /* XXX */ - - return 0; -} - -/* ARGSUSED */ -static mode_t -fd_mode_allow(mode_t mode) -{ - /* XXX */ - - return mode; -} - -/* ARGSUSED */ -static int -fd_flags_allow(int flags) -{ - /* XXX */ - - return flags; -} - -/* - * Useful to ensure that a function's arguments are as expected, and to - * retrieve the private data associated with the FD object. Implemented to - * minimize code duplication among common functions. - */ -static jsfd_t * -fd_methods_args_check(JSContext *cx, JSObject *obj, const char *fun, int id, - int argc, jsval *argv, int type) -{ - int *p = fd_methods_args_array[id], i; - char line[1024]; - jsfd_t *jsfd; - - if (*p != argc) { - (void) snprintf(line, 1023, - "%s() - Wrong number of arguments (%d), expected %d", - fun, argc, *p); - QUEUE_EXCEPTION(line); - return NULL; - } - - for (p++, i = 0; i < argc; i++) { - switch (p[i]) { - case JSAT_INTEGER: - if (!JSVAL_IS_INT(argv[i])) { - (void) snprintf(line, 1023, - "%s() - argument #%d not an integer", - fun, i + 1); - QUEUE_EXCEPTION(line); - return NULL; - } - break; - case JSAT_DOUBLE: - if (!JSVAL_IS_DOUBLE(argv[i]) && - !JSVAL_IS_INT(argv[i])) { - (void) snprintf(line, 1023, - "%s() - argument #%d not a double", - fun, i + 1); - QUEUE_EXCEPTION(line); - return NULL; - } - break; - case JSAT_STRING: - if (!JSVAL_IS_STRING(argv[i])) { - (void) snprintf(line, 1023, - "%s() - argument #%d not a string", - fun, i + 1); - QUEUE_EXCEPTION(line); - return NULL; - } - break; - default: - (void) snprintf(line, 1023, - "%s() - Unexpected argument type #%d", - fun, i + 1); - QUEUE_EXCEPTION(line); - return NULL; - } - } - - if ((jsfd = JS_GetInstancePrivate(cx, obj, &fd_class, NULL)) - == NULL) { - (void) snprintf(line, 1023, "%s() - NULL private data!", fun); - QUEUE_EXCEPTION(line); - return NULL; - } - - if (type == JSFD_NONE && jsfd->type != JSFD_NONE) { - (void) snprintf(line, 1023, - "%s() - Descriptor is already open", - fun); - QUEUE_EXCEPTION(line); - return NULL; - } else - return jsfd; - - if ((jsfd->type & type) == 0) { - (void) snprintf(line, 1023, - "%s() - Descriptor is closed or of wrong type", - fun); - QUEUE_EXCEPTION(line); - return NULL; - } - - return jsfd; -} diff --git a/tests/js-test/src/classes/js_fd.h b/tests/js-test/src/classes/js_fd.h deleted file mode 100644 index 9ef410e..0000000 --- a/tests/js-test/src/classes/js_fd.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: js_fd.h,v 1.4 2006/07/11 06:45:14 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSFD_H -#define JSFD_H - -#include - -extern JSObject *js_InitFDClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/classes/js_global.c b/tests/js-test/src/classes/js_global.c deleted file mode 100644 index c386b11..0000000 --- a/tests/js-test/src/classes/js_global.c +++ /dev/null @@ -1,150 +0,0 @@ -/* $Id: js_global.c,v 1.1 2006/07/22 03:43:09 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Provide a means to set and access global objects and global properties. - * Basically we can store hashtable objects, which each can store arbitrary - * String/String tuples, but using shared memory instead of a database. - * Internally a hash table would also be used to index hash tables by String. - * There would be a single synchronization lock around the system. - * We would need to initially work with an allocated buffer of shared memory, - * which only needed pages are used. For this, mmpool(3) could be used. - * A pool of hash tables would be necessary, as well as one for the data - * pair items. To be linked among those. - * - * I yet have to find a proper interface. We optionally could have stuff - * like: - * - * Global.getProperty(table, property); - * Global.setProperty(table, property, string); - * - * But would it also be possible to use lazy allocation such that this would - * be possible, although of course enforcing the same internal behavior: - * - * Global.table.property would be read or set as necessary. - * - * Or: - * table = new Global(tablename); - * table.prop = 'string'; - * out.put(table.prop + "\n"); - */ - - - -#include - -#include -#include -#include -#include -#include - -#include - -#include - - - -#define QUEUE_EXCEPTION(s) do { \ - JS_SetPendingException(cx, \ - STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \ -} while (/* CONSTCOND */0) - - - -/* - * Static prototypes - */ -static JSBool global_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static void global_finalize(JSContext *, JSObject *); - -static JSBool global_getProperty(JSContext *, JSObject *, jsval, jsval *); -static JSBool global_setProperty(JSContext *, JSObject *, jsval, jsval *); - - - -/* - * Static globals - */ - -/* Global class */ -static JSClass pg_class = { - "Global", JCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - global_getProperty, global_setProperty, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, global_finalize -}; - - - -/* - * Global object control - */ - -JSObject * -js_InitGlobalClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *ctor; - struct property_spec *sp; - - if ((proto = JS_InitClass(cx, obj, NULL, &global_class, - global_constructor, 0, NULL, NULL, NULL, NULL)) == NULL) { - (void) fprintf(stderr, "Error initializing Global class\n"); - goto err; - } - - /* XXX Initialize shared memory and lock */ - - return proto; - -err: - - return NULL; -} - -static JSBool -global_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - - if (!JS_IsConstructing(cx)) { - QUEUE_EXCEPTION("Constructor called as a function"); - goto err; - } - - /* XXX */ - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -global_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - - /* XXX */ - - return JS_TRUE; -} - -static JSBool -global_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) -{ - - /* XXX */ - - return JS_TRUE; -} diff --git a/tests/js-test/src/classes/js_global.h b/tests/js-test/src/classes/js_global.h deleted file mode 100644 index 725ffea..0000000 --- a/tests/js-test/src/classes/js_global.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: js_global.h,v 1.1 2006/07/22 03:43:09 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSGLOBAL_H -#define JSGLOBAL_H - -#include - -extern JSObject *js_InitGlobalClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/classes/js_mysql.c b/tests/js-test/src/classes/js_mysql.c deleted file mode 100644 index 8126f72..0000000 --- a/tests/js-test/src/classes/js_mysql.c +++ /dev/null @@ -1,6 +0,0 @@ -/* $Id: js_mysql.c,v 1.1 2006/07/09 00:30:30 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ diff --git a/tests/js-test/src/classes/js_mysql.h b/tests/js-test/src/classes/js_mysql.h deleted file mode 100644 index c04eee4..0000000 --- a/tests/js-test/src/classes/js_mysql.h +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: js_mysql.h,v 1.1 2006/07/09 00:30:30 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSMYSQL_H -#define JSMYSQL_H - -extern JSObject *js_InitMySQLClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/classes/js_pgsql.c b/tests/js-test/src/classes/js_pgsql.c deleted file mode 100644 index e697b99..0000000 --- a/tests/js-test/src/classes/js_pgsql.c +++ /dev/null @@ -1,3493 +0,0 @@ -/* $Id: js_pgsql.c,v 1.17 2006/07/22 03:22:05 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * XXX TODO XXX - * - Verify if JS_GetStringLength() really safe to continue using - * - Perhaps provide simpler replacement functions for query functions - * allowing separate parameters to be set (perhaps not necessary considering - * that we can provide null to an array). - * - All functions creating doubles or strings should check if NULL is - * returned. Verify this. - * - (maybe) make reentrant by causing optimization buffers to be part of - * generated objects instances's private data (using structures as necessary - * instead of simply wrapping around the native object's pointer - * (actually PGconn object). - * - 28.10. Notice Processing - * Either place one(s) that use syslog(3) transparently, or somehow allow - * the user to set a custom handler - * - Large objects API - * - Compare to PHP library to verify if missing any nice functions ideas - * - See what to do about the following functions: - * - PQgetssl() (returns an SSL object!) - * - PQprint() (writes to a supplied FILE *) - */ - - - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include - - - -/* - * PostgreSQL services for ECMAScript - * - * NOTES: - * We create a parent PG object which allows us to store static first-level - * methods as well as numeric properties required to work with the libpq - * library. Almost all other functionality is available through PGconn and - * PGresult objects afterwards. - * - * If supporting the asynchroneous part of the API, it should also be possible - * for us to return an FD object for a PGconn * so that polling could be used, - * etc. Or at least just return the fd int which can be used easily to create - * an FD object with afterwards by the caller. - */ - - - -#define QUEUE_EXCEPTION(s) do { \ - JS_SetPendingException(cx, \ - STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \ -} while (/* CONSTCOND */0) - - -struct property_spec { - const char *name; - int value; -}; - - - -/* - * Static prototypes - */ -static int buffer_grow(size_t); -static int param_grow(int); - -static JSBool pg_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); - -static JSBool pg_sm_PQconndefaults(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pg_sm_PQconnectdb(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pg_sm_PQconnectStart(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pg_sm_PQresStatus(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pg_sm_PQunescapeBytea(JSContext *, JSObject *, uintN, jsval *, - jsval *); - -static JSObject *js_InitPGconnClass(JSContext *, JSObject *); -static JSBool pgconn_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static void pgconn_finalize(JSContext *, JSObject *); - -static JSBool pgconn_m_PQfinish(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQconnectPoll(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQreset(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQresetStart(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQresetPoll(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQdb(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQuser(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQpass(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQhost(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQport(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQtty(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQoptions(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQstatus(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQtransactionStatus(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQparameterStatus(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQprotocolVersion(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQserverVersion(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQerrorMessage(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQsocket(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQbackendPID(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQexec(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQsendQuery(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQexecParams2(JSContext *, JSObject *, uintN, jsval *, - jsval *, int); -static JSBool pgconn_m_PQexecParams(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQsendQueryParams(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQprepare2(JSContext *, JSObject *, uintN, jsval *, - jsval *, int); -static JSBool pgconn_m_PQprepare(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQsendPrepare(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQexecPrepared2(JSContext *, JSObject *, uintN, - jsval *, jsval *, int); -static JSBool pgconn_m_PQexecPrepared(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQsendQueryPrepared(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQmakeEmptyPGresult(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQescapeStringConn(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQescapeByteaConn(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQgetCancel(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQnotifies(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQgetResult(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQconsumeInput(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQisBusy(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQsetnonblocking(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQisnonblocking(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQflush(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQsetErrorVerbosity(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgconn_m_PQtrace(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQuntrace(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQputCopyData(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQputCopyEnd(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgconn_m_PQgetCopyData(JSContext *, JSObject *, uintN, jsval *, - jsval *); - -static JSObject *js_InitPGresultClass(JSContext *, JSObject *); -static JSBool pgresult_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static void pgresult_finalize(JSContext *, JSObject *); - -static JSBool pgresult_m_PQclear(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQresultStatus(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgresult_m_PQresultErrorMessage(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgresult_m_PQresultErrorField(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgresult_m_PQntuples(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQnfields(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQfname(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQfnumber(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQftable(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQftablecol(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQfformat(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQftype(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQfmod(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQfsize(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQbinaryTuples(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgresult_m_PQgetvalue(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQgetisnull(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQgetlength(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQcmdStatus(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQcmdTuples(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static JSBool pgresult_m_PQoidValue(JSContext *, JSObject *, uintN, jsval *, - jsval *); - -static JSObject *js_InitPGcancelClass(JSContext *, JSObject *); -static JSBool pgcancel_constructor(JSContext *, JSObject *, uintN, jsval *, - jsval *); -static void pgcancel_finalize(JSContext *, JSObject *); - -static JSBool pgcancel_m_PQfreeCancel(JSContext *, JSObject *, uintN, - jsval *, jsval *); -static JSBool pgcancel_m_PQcancel(JSContext *, JSObject *, uintN, jsval *, - jsval *); - - - -/* - * Static globals - */ - -/* - * General purpose string buffer (note that this is not thread-safe). - * Allows to optimize functions such as PQescapeStringConn(). - */ -static char *buffer = NULL; -static size_t buffer_size = 0; -static Oid *param_types = NULL; -static char **param_values = NULL; -static int *param_lengths = NULL; -static int *param_formats = NULL; -static int param_entries = 0; - -/* PG class */ -static JSClass pg_class = { - "PG", 0, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, JS_FinalizeStub -}; - -/* Provided static methods */ -static JSFunctionSpec pg_smethods[] = { - { "connDefaults", pg_sm_PQconndefaults, 0, 0, 0 }, - { "connectDb", pg_sm_PQconnectdb, 1, 0, 0 }, - { "connectStart", pg_sm_PQconnectStart, 1, 0, 0 }, - { "resStatus", pg_sm_PQresStatus, 1, 0, 0 }, - { "unescapeBytea", pg_sm_PQunescapeBytea, 2, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - -/* Provided static properties */ - -#define SP(n) \ - { #n, n } - -static struct property_spec pg_sprops[] = { - SP(PGRES_POLLING_OK), - SP(PGRES_POLLING_READING), - SP(PGRES_POLLING_WRITING), - SP(PGRES_POLLING_FAILED), - SP(PGRES_EMPTY_QUERY), - SP(PGRES_COMMAND_OK), - SP(PGRES_TUPLES_OK), - SP(PGRES_COPY_OUT), - SP(PGRES_COPY_IN), - SP(PGRES_BAD_RESPONSE), - SP(PGRES_NONFATAL_ERROR), - SP(PGRES_FATAL_ERROR), - SP(PG_DIAG_SEVERITY), - SP(PG_DIAG_SQLSTATE), - SP(PG_DIAG_MESSAGE_PRIMARY), - SP(PG_DIAG_MESSAGE_DETAIL), - SP(PG_DIAG_MESSAGE_HINT), - SP(PG_DIAG_STATEMENT_POSITION), - SP(PG_DIAG_INTERNAL_POSITION), - SP(PG_DIAG_INTERNAL_QUERY), - SP(PG_DIAG_CONTEXT), - SP(PG_DIAG_SOURCE_FILE), - SP(PG_DIAG_SOURCE_LINE), - SP(PG_DIAG_SOURCE_FUNCTION), - SP(CONNECTION_OK), - SP(CONNECTION_BAD), - SP(CONNECTION_STARTED), - SP(CONNECTION_MADE), - SP(CONNECTION_AWAITING_RESPONSE), - SP(CONNECTION_AUTH_OK), - SP(CONNECTION_SSL_STARTUP), - SP(CONNECTION_SETENV), - SP(PQTRANS_IDLE), - SP(PQTRANS_ACTIVE), - SP(PQTRANS_INTRANS), - SP(PQTRANS_INERROR), - SP(PQTRANS_UNKNOWN), - SP(InvalidOid), - SP(PQERRORS_TERSE), - SP(PQERRORS_DEFAULT), - SP(PQERRORS_VERBOSE), - { NULL, 0 } -}; - -#undef SP - - -/* PGconn class */ -static JSClass pgconn_class = { - "PGConn", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, pgconn_finalize -}; - -/* Provided methods/functions */ -static JSFunctionSpec pgconn_methods[] = { - { "finish", pgconn_m_PQfinish, 0, 0, 0 }, - { "connectPoll", pgconn_m_PQconnectPoll, 0, 0, 0 }, - { "reset", pgconn_m_PQreset, 0, 0, 0 }, - { "resetStart", pgconn_m_PQresetStart, 0, 0, 0 }, - { "resetPoll", pgconn_m_PQresetPoll, 0, 0, 0 }, - { "db", pgconn_m_PQdb, 0, 0, 0 }, - { "user", pgconn_m_PQuser, 0, 0, 0 }, - { "pass", pgconn_m_PQpass, 0, 0, 0 }, - { "host", pgconn_m_PQhost, 0, 0, 0 }, - { "port", pgconn_m_PQport, 0, 0, 0 }, - { "tty", pgconn_m_PQtty, 0, 0, 0 }, - { "options", pgconn_m_PQoptions, 0, 0, 0 }, - { "status", pgconn_m_PQstatus, 0, 0, 0 }, - { "transactionStatus", pgconn_m_PQtransactionStatus, 0, 0, 0 }, - { "parameterStatus", pgconn_m_PQparameterStatus, 1, 0, 0 }, - { "protocolVersion", pgconn_m_PQprotocolVersion, 0, 0, 0 }, - { "serverVersion", pgconn_m_PQserverVersion, 0, 0, 0 }, - { "errorMessage", pgconn_m_PQerrorMessage, 0, 0, 0 }, - { "socket", pgconn_m_PQsocket, 0, 0, 0 }, - { "backendPid", pgconn_m_PQbackendPID, 0, 0, 0 }, - { "exec", pgconn_m_PQexec, 1, 0, 0 }, - { "sendQuery", pgconn_m_PQsendQuery, 1, 0, 0 }, - { "execParams", pgconn_m_PQexecParams, 7, 0, 0 }, - { "sendQueryParams", pgconn_m_PQsendQueryParams, 7, 0, 0 }, - { "prepare", pgconn_m_PQprepare, 4, 0, 0 }, - { "sendPrepare", pgconn_m_PQsendPrepare, 4, 0, 0 }, - { "execPrepared", pgconn_m_PQexecPrepared, 6, 0, 0 }, - { "sendQueryPrepared", pgconn_m_PQsendQueryPrepared, 6, 0, 0 }, - { "makeEmptyPGResult", pgconn_m_PQmakeEmptyPGresult, 1, 0, 0 }, - { "escapeStringConn", pgconn_m_PQescapeStringConn, 1, 0, 0 }, - { "escapeByteaConn", pgconn_m_PQescapeByteaConn, 1, 0, 0 }, - { "getCancel", pgconn_m_PQgetCancel, 0, 0, 0 }, - { "notifies", pgconn_m_PQnotifies, 0, 0, 0 }, - { "getResult", pgconn_m_PQgetResult, 0, 0, 0 }, - { "consumeInput", pgconn_m_PQconsumeInput, 0, 0, 0 }, - { "isBusy", pgconn_m_PQisBusy, 0, 0, 0 }, - { "setNonBlocking", pgconn_m_PQsetnonblocking, 1, 0, 0 }, - { "isNonBlocking", pgconn_m_PQisnonblocking, 0, 0, 0 }, - { "flush", pgconn_m_PQflush, 0, 0, 0 }, - { "setErrorVerbosity", pgconn_m_PQsetErrorVerbosity, 1, 0, 0 }, - { "trace", pgconn_m_PQtrace, 0, 0, 0 }, - { "untrace", pgconn_m_PQuntrace, 0, 0, 0 }, - { "putCopyData", pgconn_m_PQputCopyData, 1, 0, 0 }, - { "putCopyEnd", pgconn_m_PQputCopyEnd, 1, 0, 0 }, - { "getCopyData", pgconn_m_PQgetCopyData, 1, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - - -/* PGresult class */ -static JSClass pgresult_class = { - "PGResult", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, pgresult_finalize -}; - -/* Provided methods/functions */ -static JSFunctionSpec pgresult_methods[] = { - { "clear", pgresult_m_PQclear, 0, 0, 0 }, - { "resultStatus", pgresult_m_PQresultStatus, 0, 0, 0 }, - { "resultErrorMessage", pgresult_m_PQresultErrorMessage, 0, 0, 0 }, - { "resultErrorField", pgresult_m_PQresultErrorField, 1, 0, 0 }, - { "nTuples", pgresult_m_PQntuples, 0, 0, 0 }, - { "nFields", pgresult_m_PQnfields, 0, 0, 0 }, - { "fName", pgresult_m_PQfname, 1, 0, 0 }, - { "fNumber", pgresult_m_PQfnumber, 1, 0, 0 }, - { "fTable", pgresult_m_PQftable, 1, 0, 0 }, - { "fTableCol", pgresult_m_PQftablecol, 1, 0, 0 }, - { "fFormat", pgresult_m_PQfformat, 1, 0, 0 }, - { "fType", pgresult_m_PQftype, 1, 0, 0 }, - { "fMod", pgresult_m_PQfmod, 1, 0, 0 }, - { "fSize", pgresult_m_PQfsize, 1, 0, 0 }, - { "binaryTuples", pgresult_m_PQbinaryTuples, 1, 0, 0 }, - { "getValue", pgresult_m_PQgetvalue, 2, 0, 0 }, - { "getIsNull", pgresult_m_PQgetisnull, 2, 0, 0 }, - { "getLength", pgresult_m_PQgetlength, 2, 0, 0 }, - { "cmdStatus", pgresult_m_PQcmdStatus, 0, 0, 0 }, - { "cmdTuples", pgresult_m_PQcmdTuples, 0, 0, 0 }, - { "oidValue", pgresult_m_PQoidValue, 0, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - - -/* PGcancel class */ -static JSClass pgcancel_class = { - "PGCancel", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, pgcancel_finalize -}; - -/* Provided methods/functions */ -static JSFunctionSpec pgcancel_methods[] = { - { "freeCancel", pgcancel_m_PQfreeCancel, 0, 0, 0 }, - { "cancel", pgcancel_m_PQcancel, 1, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - - - -static int -buffer_grow(size_t required) -{ - size_t new; - void *ptr; - - if (required <= buffer_size) - return 0; - - for (new = buffer_size; new < required; new *= 2) ; - - if ((ptr = realloc(buffer, new)) == NULL) - return -1; - - buffer = ptr; - buffer_size = new; - - return 0; -} - -static int -param_grow(int required) -{ - int new; - void *types, *values, *lengths, *formats; - - if (required <= param_entries) - return 0; - - for (new = param_entries; new < required; new *= 2) ; - - if ((types = realloc(param_types, sizeof(Oid) * new)) == NULL || - (values = realloc(param_values, sizeof(char *) * new)) == NULL || - (lengths = realloc(param_lengths, sizeof(int) * new)) == NULL || - (formats = realloc(param_formats, sizeof(int) * new)) == NULL) - return -1; - - param_types = types; - param_values = values; - param_lengths = lengths; - param_formats = formats; - param_entries = new; - - return 0; -} - - -/* - * PG object control - */ - -JSObject * -js_InitPGClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *ctor; - struct property_spec *sp; - - if ((proto = JS_InitClass(cx, obj, NULL, &pg_class, pg_constructor, 0, - NULL, NULL, NULL, pg_smethods)) == NULL) { - (void) fprintf(stderr, "Error initializing PG class\n"); - goto err; - } - - /* Create static properties */ - if ((ctor = JS_GetConstructor(cx, proto)) == NULL) { - (void) fprintf(stderr, "PG: JS_GetConstructor == NULL\n"); - goto err; - } - for (sp = pg_sprops; sp->name != NULL; sp++) { - if (!JS_DefineProperty(cx, ctor, sp->name, - INT_TO_JSVAL(sp->value), NULL, NULL, - JSPROP_READONLY | JSPROP_PERMANENT)) { - (void) fprintf(stderr, - "PG: Error defining property %s\n", sp->name); - goto err; - } - } - - /* Initialize PGconn class since we'll need to instanciate it from C */ - if (js_InitPGconnClass(cx, obj) == NULL) { - (void) fprintf(stderr, "PG: InitPGconnClass()\n"); - goto err; - } - /* Same for PGresult class */ - if (js_InitPGresultClass(cx, obj) == NULL) { - (void) fprintf(stderr, "PG: InitPGresultClass()\n"); - goto err; - } - /* And PGcancel class */ - if (js_InitPGcancelClass(cx, obj) == NULL) { - (void) fprintf(stderr, "PG: InitPGcancelClass()\n"); - goto err; - } - - /* - * Note that the following buffers, although allowing optimizations, - * cause the functions using them to not be reentrant. For reentrancy - * similar buffers could be attached to the object instances instead. - * This would of course however mean a larger memory footprint. - * If doing this, we would also need a custom structure for the - * private data instead of simply wrapping around the native pointers. - */ - - /* Allocate an initial general purpose buffer */ - if ((buffer = malloc(16384)) == NULL) { - (void) fprintf(stderr, "PG: malloc()\n"); - goto err; - } - buffer_size = 16384; - - /* As well as buffers for the *Params() parameter arrays */ - if ((param_types = malloc(sizeof(Oid) * 16)) == NULL || - (param_values = malloc(sizeof(char *) * 16)) == NULL || - (param_lengths = malloc(sizeof(int) * 16)) == NULL || - (param_formats = malloc(sizeof(int) * 16)) == NULL) { - (void) fprintf(stderr, "PG: malloc()\n"); - goto err; - } - param_entries = 16; - - return proto; - -err: - if (buffer != NULL) - free(buffer); - if (param_types != NULL) - free(param_types); - if (param_values != NULL) - free(param_values); - if (param_lengths != NULL) - free(param_lengths); - if (param_formats != NULL) - free(param_formats); - - return NULL; -} - -/* Non instanciable */ -static JSBool -pg_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - QUEUE_EXCEPTION("PG class uninstanciable"); - - return JS_FALSE; -} - - -/* - * PG object static methods - */ - -/* - * Returns an array of objects which each contain the various parameters - * returned by PQconndefaults(). - * XXX Could be more useful if it returned an object of objects using the - * keyword as property in the first object level, perhaps. - */ -static JSBool -pg_sm_PQconndefaults(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PQconninfoOption *in = NULL, *p; - JSObject *array = NULL; - JSString *str; - int i; - - if (argc != 0) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - - if ((in = PQconndefaults()) == NULL) { - QUEUE_EXCEPTION("PQconndefaults() == NULL"); - goto err; - } - if ((array = JS_NewArrayObject(cx, 0, NULL)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(array); - -#define DEFINE_STRING_PROP(n, s) do { \ - if ((str = JS_NewStringCopyZ(cx, (char *)(s))) == NULL) { \ - QUEUE_EXCEPTION("Out of memory!"); \ - goto err; \ - } \ - if (!JS_DefineProperty(cx, o, (n), STRING_TO_JSVAL(str), NULL, \ - NULL, JSPROP_ENUMERATE)) { \ - QUEUE_EXCEPTION("Internal error!"); \ - goto err; \ - } \ -} while (/* CONSTCOND */0) - -#define DEFINE_STRING_PROP2(n, s, l) do { \ - if ((str = JS_NewStringCopyN(cx, (char *)(s), (l))) == NULL) { \ - QUEUE_EXCEPTION("Out of memory!"); \ - goto err; \ - } \ - if (!JS_DefineProperty(cx, o, (n), STRING_TO_JSVAL(str), NULL, \ - NULL, JSPROP_ENUMERATE)) { \ - QUEUE_EXCEPTION("Internal error!"); \ - goto err; \ - } \ -} while (/* CONSTCOND */0) - -#define DEFINE_INT_PROP(n, i) do { \ - if (!JS_DefineProperty(cx, array, (n), INT_TO_JSVAL((int)(i)), \ - NULL, NULL, JSPROP_ENUMERATE)) { \ - QUEUE_EXCEPTION("Internal error!"); \ - goto err; \ - } \ -} while (/* CONSTCOND */0) - - - /* Polulate array with objects */ - for (i = 0, p = in; p->keyword != NULL; p++, i++) { - JSObject *o; - - if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - goto err; - } - /* Root immediately by inserting object into array */ - if (!JS_DefineElement(cx, array, i, OBJECT_TO_JSVAL(o), - NULL, NULL, JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - /* Populate object with properties */ - DEFINE_STRING_PROP("keyword", p->keyword); - DEFINE_STRING_PROP("envvar", p->envvar); - DEFINE_STRING_PROP("compiled", p->compiled); - DEFINE_STRING_PROP("val", p->val); - DEFINE_STRING_PROP("label", p->label); - DEFINE_STRING_PROP2("dispchar", p->dispchar, 1); - DEFINE_INT_PROP("dispsize", p->dispsize); - } - -#undef DEFINE_STRING_PROP -#undef DEFINE_STRING_PROP2 -#undef DEFINE_INT_PROP - - PQconninfoFree(in); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - if (in != NULL) - PQconninfoFree(in); - - return JS_FALSE; -} - -static JSBool -pg_sm_PQconnectdb(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc = NULL; - char *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - str = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - if ((o = JS_NewObject(cx, &pgconn_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if ((pgc = PQconnectdb(str)) == NULL) { - QUEUE_EXCEPTION("PQconnectdb"); - goto err; - } - if (!JS_SetPrivate(cx, o, pgc)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgc != NULL) - PQfinish(pgc); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pg_sm_PQconnectStart(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc = NULL; - char *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - str = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - if ((o = JS_NewObject(cx, &pgconn_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if ((pgc = PQconnectStart(str)) == NULL) { - QUEUE_EXCEPTION("PQconnectStart"); - goto err; - } - if (!JS_SetPrivate(cx, o, pgc)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgc != NULL) - PQfinish(pgc); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pg_sm_PQresStatus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - char *res; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - res = PQresStatus(JSVAL_TO_INT(argv[0])); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, res)); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: Semantics are different from C PQunescapeBytea() in that it is - * supplied a single String and that it returns a resulting String, or null on - * error. Much easier to work with within ECMAScript this way. - */ -static JSBool -pg_sm_PQunescapeBytea(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - JSString *str; - char *from; - size_t reslen; - unsigned char *res = NULL; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - from = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - if ((res = PQunescapeBytea(from, &reslen)) == NULL) { - QUEUE_EXCEPTION("PQescapeByteaConn()"); - goto err; - } - - if ((str = JS_NewStringCopyN(cx, res, reslen)) == NULL) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - PQfreemem(res); - *rval = STRING_TO_JSVAL(str); - - return JS_TRUE; - -err: - if (res != NULL) - PQfreemem(res); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - - -/* - * PGconn object control - */ - -static JSObject * -js_InitPGconnClass(JSContext *cx, JSObject *obj) -{ - - return (JS_InitClass(cx, obj, NULL, &pgconn_class, pgconn_constructor, - 0, NULL, pgconn_methods, NULL, NULL)); -} - -/* Non instanciable */ -static JSBool -pgconn_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - QUEUE_EXCEPTION("PGconn class not user-instanciable"); - - return JS_FALSE; -} - -static void -pgconn_finalize(JSContext *cx, JSObject *obj) -{ - PGconn *pgc; - - if ((pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL)) - != NULL) { - PQfinish(pgc); - (void) JS_SetPrivate(cx, obj, NULL); - } -} - - -/* - * PGconn object methods - */ - -static JSBool -pgconn_m_PQfinish(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - if ((pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL)) - != NULL) { - PQfinish(pgc); - (void) JS_SetPrivate(cx, obj, NULL); - } - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQconnectPoll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - PostgresPollingStatusType s; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - s = PQconnectPoll(pgc); - *rval = INT_TO_JSVAL((int)s); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQreset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - PQreset(pgc); - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQresetStart(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQconnectPoll(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQresetPoll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - PostgresPollingStatusType s; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - s = PQresetPoll(pgc); - *rval = INT_TO_JSVAL((int)s); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQdb(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQdb(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQuser(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQuser(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQpass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQpass(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQhost(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQhost(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQport(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQtty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQtty(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQoptions(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQoptions(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQstatus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - ConnStatusType s = CONNECTION_BAD; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - s = PQstatus(pgc); - *rval = INT_TO_JSVAL((int)s); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQtransactionStatus(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - PGTransactionStatusType s; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - s = PQtransactionStatus(pgc); - *rval = INT_TO_JSVAL((int)s); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQparameterStatus(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - char *param; - const char *str; - - *rval = OBJECT_TO_JSVAL(NULL); - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - return JS_FALSE; - } - param = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((str = PQparameterStatus(pgc, param)) != NULL) - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQprotocolVersion(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQprotocolVersion(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQserverVersion(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQserverVersion(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQerrorMessage(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = PQerrorMessage(pgc); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQsocket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQsocket(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQbackendPID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQbackendPID(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQexec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc; - PGresult *pgr = NULL; - char *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - str = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if ((pgr = PQexec(pgc, str)) == NULL) { - QUEUE_EXCEPTION("PQexec()"); - goto err; - } - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQsendQuery(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - char *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - str = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQsendQuery(pgc, str)); - - return JS_TRUE; - -err: - *rval = INT_TO_JSVAL(0); - - return JS_FALSE; -} - -/* - * A fairly hairy function. - */ -static JSBool -pgconn_m_PQexecParams2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, int async) -{ - int nargs, i; - JSObject *arrays[4], *o; - JSIdArray *a = NULL; - Oid *types = NULL; - char **values = NULL; - int *lengths = NULL; - int *formats = NULL; - char str[256]; - PGconn *pgc; - PGresult *pgr = NULL; - - if (argc != 7) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not a String"); - goto err; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not an int"); - goto err; - } - for (i = 2; i < 6; i++) { - if (JSVAL_IS_NULL(argv[i])) { - arrays[i - 2] = NULL; - continue; - } - if (!JSVAL_IS_OBJECT(argv[i]) || - !JS_IsArrayObject(cx, - (arrays[i - 2] = JSVAL_TO_OBJECT(argv[i])))) { - (void) snprintf(str, 255, "Argument %d not an Array", - i + 1); - QUEUE_EXCEPTION(str); - goto err; - } - } - if (!JSVAL_IS_INT(argv[6])) { - QUEUE_EXCEPTION("Argument 7 not an int"); - goto err; - } - - /* Array arguments processing */ - nargs = JSVAL_TO_INT(argv[1]); - if (nargs < 0) { - QUEUE_EXCEPTION("Argument 2 negative"); - goto err; - } - - if (arrays[0] != NULL) - types = param_types; - if (arrays[1] != NULL) - values = param_values; - if (arrays[2] != NULL) - lengths = param_lengths; - if (arrays[3] != NULL) - formats = param_formats; - - for (i = 0; i < 4; i++) { - jsint len; - - if (arrays[i] == NULL) - continue; - - if (!JS_GetArrayLength(cx, arrays[i], &len) || len != nargs) { - (void) snprintf(str, 255, - "Argument %d Array not holding %d elements", - i + 2, nargs); - QUEUE_EXCEPTION(str); - goto err; - } - } - - if (param_grow(nargs) == -1) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - /* param_types */ - if (types != NULL) { - jsval id, val; - int i2; - jsdouble v; - - o = arrays[0]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_NUMBER(val)) { - (void) snprintf(str, 255, - "Argument 3 Array's element %d " - "not a number", i2); - QUEUE_EXCEPTION(str); - goto err; - } - if (!JS_ValueToNumber(cx, val, &v)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - types[i2++] = (Oid)v; - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - /* param_values */ - if (values != NULL) { - jsval id, val; - int i2; - - o = arrays[1]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (JSVAL_IS_NULL(val)) { - values[i2++] = NULL; - continue; - } - if (!JSVAL_IS_STRING(val)) { - (void) snprintf(str, 255, - "Argument 4 Array's element %d " - "not a String", i2); - QUEUE_EXCEPTION(str); - goto err; - } - values[i2++] = JS_GetStringBytes( - JSVAL_TO_STRING(val)); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - /* param_lengths */ - if (lengths != NULL) { - jsval id, val; - int i2; - - o = arrays[2]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_INT(val)) { - (void) snprintf(str, 255, - "Argument 5 Array's element %d " - "not an int", i2); - QUEUE_EXCEPTION(str); - goto err; - } - lengths[i2++] = JSVAL_TO_INT(val); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - /* param_formats */ - if (formats != NULL) { - jsval id, val; - int i2; - - o = arrays[3]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_INT(val)) { - (void) snprintf(str, 255, - "Argument 6 Array's element %d " - "not an int", i2); - QUEUE_EXCEPTION(str); - goto err; - } - formats[i2++] = JSVAL_TO_INT(val); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if (!async) { - - if ((pgr = PQexecParams(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - nargs, types, (const char * const *)values, lengths, - formats, JSVAL_TO_INT(argv[6]))) == NULL) { - QUEUE_EXCEPTION("PQexecParams()"); - goto err; - } - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) - == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - } else { - - *rval = INT_TO_JSVAL(PQsendQueryParams(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - nargs, types, (const char * const *)values, lengths, - formats, JSVAL_TO_INT(argv[6]))); - - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - if (a != NULL) - JS_DestroyIdArray(cx, a); - - if (!async) - *rval = OBJECT_TO_JSVAL(NULL); - else - *rval = INT_TO_JSVAL(0); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQexecParams(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - return pgconn_m_PQexecParams2(cx, obj, argc, argv, rval, 0); -} - -static JSBool -pgconn_m_PQsendQueryParams(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - - return pgconn_m_PQexecParams2(cx, obj, argc, argv, rval, 1); -} - -static JSBool -pgconn_m_PQprepare2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, int async) -{ - int nargs, i; - JSObject *array, *o; - JSIdArray *a = NULL; - Oid *types = NULL; - char str[256]; - PGconn *pgc; - PGresult *pgr = NULL; - - if (argc != 4) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not a String"); - goto err; - } - if (!JSVAL_IS_STRING(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not a String"); - goto err; - } - if (!JSVAL_IS_INT(argv[2])) { - QUEUE_EXCEPTION("Argument 3 not an int"); - goto err; - } - if (JSVAL_IS_NULL(argv[3])) - array = NULL; - else { - if (!JSVAL_IS_OBJECT(argv[3]) || - !JS_IsArrayObject(cx, - (array = JSVAL_TO_OBJECT(argv[3])))) { - QUEUE_EXCEPTION("Argument 4 not an Array"); - goto err; - } - } - - /* Array arguments processing */ - nargs = JSVAL_TO_INT(argv[2]); - if (nargs < 0) { - QUEUE_EXCEPTION("Argument 3 negative"); - goto err; - } - - if (array != NULL) { - jsint len; - - types = param_types; - - if (!JS_GetArrayLength(cx, array, &len) || len != nargs) { - (void) snprintf(str, 255, - "Argument 4 Array not holding %d elements", - nargs); - QUEUE_EXCEPTION(str); - goto err; - } - } - - if (param_grow(nargs) == -1) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - /* param_types */ - if (types != NULL) { - jsval id, val; - int i2; - jsdouble v; - - o = array; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_NUMBER(val)) { - (void) snprintf(str, 255, - "Argument 4 Array's element %d " - "not a number", i2); - QUEUE_EXCEPTION(str); - goto err; - } - if (!JS_ValueToNumber(cx, val, &v)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - types[i2++] = (Oid)v; - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if (!async) { - - if ((pgr = PQprepare(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - JS_GetStringBytes(JSVAL_TO_STRING(argv[1])), - nargs, types)) == NULL) { - QUEUE_EXCEPTION("PQprepare()"); - goto err; - } - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) - == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - } else { - - *rval = INT_TO_JSVAL(PQsendPrepare(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - JS_GetStringBytes(JSVAL_TO_STRING(argv[1])), - nargs, types)); - - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - - if (!async) - *rval = OBJECT_TO_JSVAL(NULL); - else - *rval = INT_TO_JSVAL(0); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQprepare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - return pgconn_m_PQprepare2(cx, obj, argc, argv, rval, 0); -} - -static JSBool -pgconn_m_PQsendPrepare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - return pgconn_m_PQprepare2(cx, obj, argc, argv, rval, 1); -} - -/* - * Also rather hairy - */ -static JSBool -pgconn_m_PQexecPrepared2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, int async) -{ - int nargs, i; - JSObject *arrays[3], *o; - JSIdArray *a = NULL; - char **values = NULL; - int *lengths = NULL; - int *formats = NULL; - char str[256]; - PGconn *pgc; - PGresult *pgr = NULL; - - if (argc != 6) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not a String"); - goto err; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not an int"); - goto err; - } - for (i = 2; i < 5; i++) { - if (JSVAL_IS_NULL(argv[i])) { - arrays[i - 2] = NULL; - continue; - } - if (!JSVAL_IS_OBJECT(argv[i]) || - !JS_IsArrayObject(cx, - (arrays[i - 2] = JSVAL_TO_OBJECT(argv[i])))) { - (void) snprintf(str, 255, "Argument %d not an Array", - i + 1); - QUEUE_EXCEPTION(str); - goto err; - } - } - if (!JSVAL_IS_INT(argv[5])) { - QUEUE_EXCEPTION("Argument 7 not an int"); - goto err; - } - - /* Array arguments processing */ - nargs = JSVAL_TO_INT(argv[1]); - if (nargs < 0) { - QUEUE_EXCEPTION("Argument 2 negative"); - goto err; - } - - if (arrays[0] != NULL) - values = param_values; - if (arrays[1] != NULL) - lengths = param_lengths; - if (arrays[2] != NULL) - formats = param_formats; - - for (i = 0; i < 3; i++) { - jsint len; - - if (arrays[i] == NULL) - continue; - - if (!JS_GetArrayLength(cx, arrays[i], &len) || len != nargs) { - (void) snprintf(str, 255, - "Argument %d Array not holding %d elements", - i + 2, nargs); - QUEUE_EXCEPTION(str); - goto err; - } - } - - if (param_grow(nargs) == -1) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - /* param_values */ - if (values != NULL) { - jsval id, val; - int i2; - - o = arrays[0]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (JSVAL_IS_NULL(val)) { - values[i2++] = NULL; - continue; - } - if (!JSVAL_IS_STRING(val)) { - (void) snprintf(str, 255, - "Argument 3 Array's element %d " - "not a String", i2); - QUEUE_EXCEPTION(str); - goto err; - } - values[i2++] = JS_GetStringBytes( - JSVAL_TO_STRING(val)); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - /* param_lengths */ - if (lengths != NULL) { - jsval id, val; - int i2; - - o = arrays[1]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_INT(val)) { - (void) snprintf(str, 255, - "Argument 4 Array's element %d " - "not an int", i2); - QUEUE_EXCEPTION(str); - goto err; - } - lengths[i2++] = JSVAL_TO_INT(val); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - /* param_formats */ - if (formats != NULL) { - jsval id, val; - int i2; - - o = arrays[2]; - if ((a = JS_Enumerate(cx, o)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - for (i2 = i = 0; i < a->length; i++) { - JS_IdToValue(cx, a->vector[i], &id); - if (JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) && - !JSVAL_IS_VOID(val)) { - if (!JSVAL_IS_INT(val)) { - (void) snprintf(str, 255, - "Argument 5 Array's element %d " - "not an int", i2); - QUEUE_EXCEPTION(str); - goto err; - } - formats[i2++] = JSVAL_TO_INT(val); - } - } - JS_DestroyIdArray(cx, a); - a = NULL; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if (!async) { - - if ((pgr = PQexecPrepared(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - nargs, (const char * const *)values, lengths, formats, - JSVAL_TO_INT(argv[5]))) == NULL) { - QUEUE_EXCEPTION("PQexecPrepared()"); - goto err; - } - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) - == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - } else { - - *rval = INT_TO_JSVAL(PQsendQueryPrepared(pgc, - JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), - nargs, (const char * const *)values, lengths, formats, - JSVAL_TO_INT(argv[5]))); - - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - if (a != NULL) - JS_DestroyIdArray(cx, a); - - if (!async) - *rval = OBJECT_TO_JSVAL(NULL); - else - *rval = INT_TO_JSVAL(0); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQexecPrepared(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - return pgconn_m_PQexecPrepared2(cx, obj, argc, argv, rval, 0); -} - -static JSBool -pgconn_m_PQsendQueryPrepared(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - - return pgconn_m_PQexecPrepared2(cx, obj, argc, argv, rval, 1); -} - -static JSBool -pgconn_m_PQmakeEmptyPGresult(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - JSObject *o; - PGconn *pgc; - PGresult *pgr = NULL; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if ((pgr = PQmakeEmptyPGresult(pgc, JSVAL_TO_INT(argv[0]))) == NULL) { - QUEUE_EXCEPTION("PQmakeEmptyPGresult()"); - goto err; - } - - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: Semantics are different from C PQescapeStringConn() in that it is - * supplied a single String and that it returns a resulting String, or null on - * error. Much easier to work with within ECMAScript this way. - */ -static JSBool -pgconn_m_PQescapeStringConn(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - JSString *str; - char *from; - size_t len; - int ret; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = JSVAL_TO_STRING(argv[0]); - from = JS_GetStringBytes(str); - len = JS_GetStringLength(str); - - if (buffer_grow((len * 2) + 2) == -1) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - len = PQescapeStringConn(pgc, buffer, from, len, &ret); - if (ret != 0) { - QUEUE_EXCEPTION("PQescapeStringConn()"); - goto err; - } - - if ((str = JS_NewStringCopyN(cx, buffer, len)) == NULL) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - *rval = STRING_TO_JSVAL(str); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* PQescapeString() deprecated in favor of PQescapeStringConn() */ - -/* - * Note: Semantics are different from C PQescapeByteaConn() in that it is - * supplied a single String and that it returns a resulting String, or null on - * error. Much easier to work with within ECMAScript this way. - */ -static JSBool -pgconn_m_PQescapeByteaConn(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - JSString *str; - char *from; - size_t fromlen, reslen; - unsigned char *res = NULL; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = JSVAL_TO_STRING(argv[0]); - from = JS_GetStringBytes(str); - fromlen = JS_GetStringLength(str); - - if ((res = PQescapeByteaConn(pgc, from, fromlen, &reslen)) == NULL) { - QUEUE_EXCEPTION("PQescapeByteaConn()"); - goto err; - } - - if ((str = JS_NewStringCopyN(cx, res, reslen)) == NULL) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - - PQfreemem(res); - *rval = STRING_TO_JSVAL(str); - - return JS_TRUE; - -err: - if (res != NULL) - PQfreemem(res); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQgetCancel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc; - PGcancel *pgcn = NULL; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((o = JS_NewObject(cx, &pgcancel_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if ((pgcn = PQgetCancel(pgc)) == NULL) { - QUEUE_EXCEPTION("PQgetCancel()"); - goto err; - } - if (!JS_SetPrivate(cx, o, pgcn)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgcn != NULL) - PQfreeCancel(pgcn); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: Unlike C native PQnotifies(), returns null or a normal object with - * the three properties set, rather than specifically a PQnotify object. - */ -static JSBool -pgconn_m_PQnotifies(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc; - PGnotify *pgn = NULL; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((pgn = PQnotifies(pgc)) == NULL) { - *rval = OBJECT_TO_JSVAL(NULL); - return JS_TRUE; - } - - if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_DefineProperty(cx, o, "relname", STRING_TO_JSVAL( - JS_NewStringCopyZ(cx, pgn->relname)), NULL, NULL, - JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - if (!JS_DefineProperty(cx, o, "be_pid", INT_TO_JSVAL(pgn->be_pid), - NULL, NULL, JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - if (!JS_DefineProperty(cx, o, "extra", STRING_TO_JSVAL( - JS_NewStringCopyZ(cx, pgn->extra)), NULL, NULL, - JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - PQfreemem(pgn); - - return JS_TRUE; - -err: - if (pgn != NULL) - PQfreemem(pgn); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQgetResult(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc; - PGresult *pgr = NULL; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - if ((pgr = PQgetResult(pgc)) == NULL) { - *rval = OBJECT_TO_JSVAL(NULL); - return JS_TRUE; - } - - if ((o = JS_NewObject(cx, &pgresult_class, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_SetPrivate(cx, o, pgr)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - if (pgr != NULL) - PQclear(pgr); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQconsumeInput(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQconsumeInput(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQisBusy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQisBusy(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQsetnonblocking(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQsetnonblocking(pgc, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQisnonblocking(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQisnonblocking(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQflush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQflush(pgc)); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQsetErrorVerbosity(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGconn *pgc; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQsetErrorVerbosity(pgc, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQtrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = OBJECT_TO_JSVAL(NULL); - PQtrace(pgc, stderr); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQuntrace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = OBJECT_TO_JSVAL(NULL); - PQuntrace(pgc); - - return JS_TRUE; -} - -static JSBool -pgconn_m_PQputCopyData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - JSString *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - str = JSVAL_TO_STRING(argv[0]); - *rval = INT_TO_JSVAL(PQputCopyData(pgc, JS_GetStringBytes(str), - JS_GetStringLength(str))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgconn_m_PQputCopyEnd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGconn *pgc; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0]) && !JSVAL_IS_NULL(argv[0])) { - QUEUE_EXCEPTION("Argument not a String or null"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - *rval = INT_TO_JSVAL(PQputCopyEnd(pgc, (JSVAL_IS_NULL(argv[0]) ? NULL : - JS_GetStringBytes(JSVAL_TO_STRING(argv[0]))))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: unlike native PQgetCopyData(), which returns an int but is supplied a - * pointer to a pointer to be set, this implementation returns an object which - * holds two elements: result (the integer) and data (null or String), to make - * it easier to use with ECMAScript. - */ -static JSBool -pgconn_m_PQgetCopyData(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - JSObject *o; - PGconn *pgc; - char *data = NULL; - int res; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgconn_class, NULL); - assert(pgc != NULL); - - res = PQgetCopyData(pgc, &data, JSVAL_TO_INT(argv[0])); - - if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - /* Root immediately */ - *rval = OBJECT_TO_JSVAL(o); - - if (!JS_DefineProperty(cx, o, "result", INT_TO_JSVAL(res), - NULL, NULL, JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - if (data != NULL && res > 0) { - if (!JS_DefineProperty(cx, o, "data", STRING_TO_JSVAL( - JS_NewStringCopyN(cx, data, res)), NULL, NULL, - JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - PQfreemem(data); - } else { - if (!JS_DefineProperty(cx, o, "data", OBJECT_TO_JSVAL(NULL), - NULL, NULL, JSPROP_ENUMERATE)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - } - - return JS_TRUE; - -err: - if (data != NULL) - PQfreemem(data); - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - - -/* - * PGresult object control - */ - -static JSObject * -js_InitPGresultClass(JSContext *cx, JSObject *obj) -{ - - return (JS_InitClass(cx, obj, NULL, &pgresult_class, - pgresult_constructor, 0, NULL, pgresult_methods, NULL, NULL)); -} - -/* Non instanciable */ -static JSBool -pgresult_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - QUEUE_EXCEPTION("PGresult class not user-instanciable"); - - return JS_FALSE; -} - -static void -pgresult_finalize(JSContext *cx, JSObject *obj) -{ - PGresult *pgr; - - if ((pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL)) - != NULL) { - PQclear(pgr); - (void) JS_SetPrivate(cx, obj, NULL); - } -} - - -/* - * PGresult object methods - */ - -static JSBool -pgresult_m_PQclear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - if ((pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL)) - != NULL) { - PQclear(pgr); - (void) JS_SetPrivate(cx, obj, NULL); - } - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_TRUE; -} - -static JSBool -pgresult_m_PQresultStatus(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGresult *pgr; - ExecStatusType s; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - s = PQresultStatus(pgr); - *rval = INT_TO_JSVAL((int)s); - - return JS_TRUE; -} - -static JSBool -pgresult_m_PQresultErrorMessage(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGresult *pgr; - char *res; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - res = PQresultErrorMessage(pgr); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, res)); - - return JS_TRUE; -} - -static JSBool -pgresult_m_PQresultErrorField(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGresult *pgr; - char *res; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - res = PQresultErrorField(pgr, JSVAL_TO_INT(argv[0])); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, res)); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQntuples(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQntuples(pgr)); - - return JS_TRUE; -} - -static JSBool -pgresult_m_PQnfields(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQnfields(pgr)); - - return JS_TRUE; -} - -static JSBool -pgresult_m_PQfname(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - char *res; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - res = PQfname(pgr, JSVAL_TO_INT(argv[0])); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, res)); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQfnumber(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - char *str; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument not a String"); - goto err; - } - str = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQfnumber(pgr, str)); - - return JS_TRUE; -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: Oid is a typedef to unsigned int. Thus, we use a double object to - * make sure that we do not loose any precision. - */ -static JSBool -pgresult_m_PQftable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - Oid oid; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - oid = PQftable(pgr, JSVAL_TO_INT(argv[0])); - - if (!JS_NewDoubleValue(cx, (jsdouble)oid, rval)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQftablecol(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQftablecol(pgr, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: we possibly could return a boolean value instead of an integer - * but the documentation says that other values are reserved for possible - * future use. I am surprised that they do not return enumerated values. - */ -static JSBool -pgresult_m_PQfformat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQfformat(pgr, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: Oid is a typedef to unsigned int. Thus, we use a double object to - * make sure that we do not loose any precision. - */ -static JSBool -pgresult_m_PQftype(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - Oid oid; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - oid = PQftype(pgr, JSVAL_TO_INT(argv[0])); - - if (!JS_NewDoubleValue(cx, (jsdouble)oid, rval)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQfmod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQfmod(pgr, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQfsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQfsize(pgr, JSVAL_TO_INT(argv[0]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQbinaryTuples(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQbinaryTuples(pgr)); - - return JS_TRUE; -} - -/* - * Note: The semantics of PGresult.PQgetvalue() is different from the actual - * libpq C function PQgetvalue() in that we return null on NULL fields, and - * that we always return either the binary or text data into the field as a - * String (since ECMAScript Strings objects allow NUL characters). - */ -static JSBool -pgresult_m_PQgetvalue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - JSString *str; - char *res; - int row, col; - - if (argc != 2) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - row = JSVAL_TO_INT(argv[0]); - col = JSVAL_TO_INT(argv[1]); - - if (PQgetisnull(pgr, row, col)) { - *rval = OBJECT_TO_JSVAL(NULL); - return JS_TRUE; - } - - if ((res = PQgetvalue(pgr, row, col)) == NULL) { - QUEUE_EXCEPTION("PQgetvalue() == NULL"); - goto err; - } - - if ((str = JS_NewStringCopyN(cx, res, PQgetlength(pgr, row, col))) - == NULL) { - QUEUE_EXCEPTION("Out of memory!"); - goto err; - } - *rval = STRING_TO_JSVAL(str); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -/* - * Note: unlike the C PQgetisnull() function, which returns 0 or 1, we return - * true or false, since ECMAScript supports booleans. - * Moreover, one no longer needs to call this function in JS if it is to - * subsequently use PQgetvalue(), since ours can return null. - * May still be useful in some situations. - */ -static JSBool -pgresult_m_PQgetisnull(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 2) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = BOOLEAN_TO_JSVAL(PQgetisnull(pgr, JSVAL_TO_INT(argv[0]), - JSVAL_TO_INT(argv[1]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQgetlength(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 2) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_INT(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not an int"); - goto err; - } - if (!JSVAL_IS_INT(argv[1])) { - QUEUE_EXCEPTION("Argument 2 not an int"); - goto err; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = INT_TO_JSVAL(PQgetlength(pgr, JSVAL_TO_INT(argv[0]), - JSVAL_TO_INT(argv[1]))); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - -static JSBool -pgresult_m_PQcmdStatus(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, PQcmdStatus(pgr))); - - return JS_TRUE; -} - -/* - * We could return a double easily, but like the C API are returning a string - */ -static JSBool -pgresult_m_PQcmdTuples(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, PQcmdTuples(pgr))); - - return JS_TRUE; -} - -/* - * Note: Oid is a typedef to unsigned int. Thus, we use a double object to - * make sure that we do not loose any precision. - */ -static JSBool -pgresult_m_PQoidValue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGresult *pgr; - Oid oid; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - pgr = JS_GetInstancePrivate(cx, obj, &pgresult_class, NULL); - assert(pgr != NULL); - - oid = PQoidValue(pgr); - - if (!JS_NewDoubleValue(cx, (jsdouble)oid, rval)) { - QUEUE_EXCEPTION("Internal error!"); - goto err; - } - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} - - - -/* - * PGcancel object control - */ - -static JSObject * -js_InitPGcancelClass(JSContext *cx, JSObject *obj) -{ - - return (JS_InitClass(cx, obj, NULL, &pgcancel_class, - pgcancel_constructor, 0, NULL, pgcancel_methods, NULL, NULL)); -} - -/* Non instanciable */ -static JSBool -pgcancel_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - - QUEUE_EXCEPTION("PGcancel class not user-instanciable"); - - return JS_FALSE; -} - -static void -pgcancel_finalize(JSContext *cx, JSObject *obj) -{ - PGcancel *pgc; - - if ((pgc = JS_GetInstancePrivate(cx, obj, &pgcancel_class, NULL)) - != NULL) { - PQfreeCancel(pgc); - (void) JS_SetPrivate(cx, obj, NULL); - } -} - - -/* - * PGcancel object methods - */ - -static JSBool -pgcancel_m_PQfreeCancel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGcancel *pgc; - - if (argc != 0) { - QUEUE_EXCEPTION("Function allows no arguments"); - *rval = OBJECT_TO_JSVAL(NULL); - return JS_FALSE; - } - - if ((pgc = JS_GetInstancePrivate(cx, obj, &pgcancel_class, NULL)) - != NULL) { - PQfreeCancel(pgc); - (void) JS_SetPrivate(cx, obj, NULL); - } - - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_TRUE; -} - -static JSBool -pgcancel_m_PQcancel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - PGcancel *pgc; - char *str; - size_t len; - JSString *s; - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - goto err; - } - if (!JSVAL_IS_STRING(argv[0])) { - QUEUE_EXCEPTION("Argument 1 not a String"); - goto err; - } - - pgc = JS_GetInstancePrivate(cx, obj, &pgcancel_class, NULL); - assert(pgc != NULL); - - s = JSVAL_TO_STRING(argv[0]); - str = JS_GetStringBytes(s); - len = JS_GetStringLength(s); - - *rval = INT_TO_JSVAL(PQcancel(pgc, str, len)); - - return JS_TRUE; - -err: - *rval = OBJECT_TO_JSVAL(NULL); - - return JS_FALSE; -} diff --git a/tests/js-test/src/classes/js_pgsql.h b/tests/js-test/src/classes/js_pgsql.h deleted file mode 100644 index 935b85c..0000000 --- a/tests/js-test/src/classes/js_pgsql.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: js_pgsql.h,v 1.3 2006/07/11 10:25:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSPGSQL_H -#define JSPGSQL_H - -#include - -extern JSObject *js_InitPGClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/classes/js_signal.c b/tests/js-test/src/classes/js_signal.c deleted file mode 100644 index c93cc69..0000000 --- a/tests/js-test/src/classes/js_signal.c +++ /dev/null @@ -1,231 +0,0 @@ -/* $Id: js_signal.c,v 1.3 2005/12/12 18:34:46 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Basic UNIX signal services for ECMAScript - * - * XXX - * I have to see what interface I want to export. There are several - * possibilities we could use: - * - Have the shell register signal handlers fore interesting events at - * startup and allow scripts to provide a handler function, which if - * exists upon reception of a signal, gets executed. We might then - * need to add extra custom checks in the shell for special signals - * which if the script doesn't end, might still end the process - * i.e. function would be expected to cause the script to exit upon - * reception of a SIGTERM signal... - * - Provide a sigaction-style interface so that the script would be - * able to define functions to execute upon reception of certain - * signals, or null or such for the signal to be ignored. - * This solution might allow better application customization. - * If assuming this interface, the following would be exported: - * - Signal class, through which static signal properties could be - * accessed for signal numbers I.E. Signal.SIGTERM. - * - A static method to create/set/unset/ignore a signal/handler - * Signal.sigaction()? - * It could be provided with the parameters: - * Signal.sigaction(FD.SIG*, obj); - * Where obj would contain fields sa_handler, sa_mask, sa_flags? - * Signal.kill(pid, sig); - * Signal.sigaltstack(...) ? - * Signal.sigprocmask(...) - * Signal.sigsuspend(mask) - * And maybe provide the sigsetops(3)? We possibly could just allow an - * array or such instead of sigset_t though if wanted. - * I'm not sure I want to provide sigsetjmp()/siglongjmp(). JavaScript has - * exceptions anyways. If allowing sigaltstack(), C would need to allocate - * the stacks, so a stack object would need to be exported or such. I - * don't think I want to support this as it's probably not needed by any of - * the applications I'll write, I don't want to write a threading library - * in JS. - * - I wonder if it would be safe to invoke a JS function in a signal handler. - * If it wasn't, I could simply queue the signal events and then call the - * functions for the queue in normal process context. - * If doing this, sigaction has to be called to catch any signal the - * application wishes, and we would be rolling our own signal handling, - * so if wanted we could potentially provide another interface than - * sigaction to ECMAScript... - */ - - - -#include - -#include -#include -#include -#include -#include - -#include - - - -/* Utility macros */ -#define QUEUE_EXCEPTION(s) do { \ - JS_SetPendingException(cx, \ - STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s)))); \ -} while (/* CONSTCOND */0) - - - -/* Prototypes */ -static JSBool signal_sm_strerror(JSContext *, JSObject *, uintN, jsval *, - jsval *); - - - -/* Actual class parameters */ -static JSClass signal_class = { - "Signal", 0, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub -}; - -/* Provided static methods */ -static JSFunctionSpec signal_smethods[] = { - { "strerror", signal_sm_strerror, 1, 0, 0 }, - { NULL, NULL, 0, 0, 0 } -}; - -/* - * Provided static properties. - * We use these to provide ECMAScript with the ability to use system-specific - * standard C constant macros without us having to tidiously map them - * individually, or to require other scripts to be used as headers to define - * them. Another possibility would have been to supply these parameters as - * string, but this would have required even slower remapping because of the - * parsing and string comparisions. - * We only include those which we consider necessary for now, others may be - * added easily as needed, provided that they are added in all three maps. - * I might perhaps develop macros and/or functions to map all these easily - * from a single map. - */ - -struct property_spec { - const char *name; - int value; -}; - -#define SP(n) \ - { #n, n } - -static struct property_spec signal_sprops[] = { - SP(SIGHUP), - SP(SIGINT), - SP(SIGQUIT), - SP(SIGILL), - SP(SIGTRAP), - SP(SIGABRT), - SP(SIGEMT), - SP(SIGFPE), - SP(SIGKILL), - SP(SIGBUS), - SP(SIGSEGV), - SP(SIGSYS), - SP(SIGPIPE), - SP(SIGALRM), - SP(SIGTERM), - SP(SIGURG), - SP(SIGSTOP), - SP(SIGTSTP), - SP(SIGCONT), - SP(SIGCHLD), - SP(SIGTTIN), - SP(SIGTTOU), - SP(SIGIO), - SP(SIGXCPU), - SP(SIGXFSZ), - SP(SIGVTALRM), - SP(SIGPROF), - SP(SIGWINCH), - SP(SIGINFO), - SP(SIGUSR1), - SP(SIGUSR2), - SP(SIGPWR), - - { NULL, 0 } -}; - -#undef SP - - - -/* - * Class control functions - */ - -JSObject * -js_InitSignalClass(JSContext *cx, JSObject *obj) -{ - JSObject *proto, *ctor; - struct property_spec *sp; - - if ((proto = JS_InitClass(cx, obj, NULL, &signal_class, NULL, - 0, NULL, NULL, NULL, signal_smethods)) == NULL) { - (void) fprintf(stderr, "Error initializing Signal class\n"); - return NULL; - } - - /* Create static properties */ - if ((ctor = JS_GetConstructor(cx, proto)) == NULL) { - (void) fprintf(stderr, "Signal: JS_GetConstructor == NULL\n"); - return NULL; - } - for (sp = signal_sprops; sp->name != NULL; sp++) { - if (JS_DefineProperty(cx, ctor, sp->name, - INT_TO_JSVAL(sp->value), NULL, NULL, - JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) { - (void) fprintf(stderr, - "Signal: Error defining property %s\n", sp->name); - return NULL; - } - } - - return proto; -} - - - -/* - * Static properties functions - */ - - - -/* - * Static methods - */ - -static JSBool -signal_sm_strerror(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - int error; - JSString *string; - - *rval = OBJECT_TO_JSVAL(NULL); - - if (argc != 1) { - QUEUE_EXCEPTION("Wrong number of arguments"); - return JS_FALSE; - } - if (!JSVAL_IS_INT(*argv)) { - QUEUE_EXCEPTION("Argument not an integer"); - return JS_FALSE; - } - error = (int)JSVAL_TO_INT(*argv); - - if ((string = JS_NewStringCopyZ(cx, "testXXX")) == NULL) { - QUEUE_EXCEPTION("Out of memory"); - return JS_FALSE; - } - - *rval = STRING_TO_JSVAL(string); - - return JS_TRUE; -} diff --git a/tests/js-test/src/classes/js_signal.h b/tests/js-test/src/classes/js_signal.h deleted file mode 100644 index 3690d12..0000000 --- a/tests/js-test/src/classes/js_signal.h +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: js_signal.h,v 1.1 2005/07/19 19:27:28 mmondor Exp $ */ - -/* - * Copyright (c) 2005, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#ifndef JSSIGNAL_H -#define JSSIGNAL_H - -extern JSObject *js_InitSignalClass(JSContext *, JSObject *); - -#endif diff --git a/tests/js-test/src/js-server.c b/tests/js-test/src/js-server.c deleted file mode 100644 index f0bfe38..0000000 --- a/tests/js-test/src/js-server.c +++ /dev/null @@ -1,328 +0,0 @@ -/* $Id: js-server.c,v 1.7 2006/07/12 13:47:14 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2005, Matthew Mondor - */ - -/* - * TODO: - * - * - Verify with Brendan Eich: - * - If reusing the context to execute several other scripts, it is - * important that they not be able to add global properties or methods. - * This seems to currently work using a custom api_class_property_add(). - * This however also required standard properties to be shared - * (JS_PROP_SHARED), otherwise api_class_property_add() would be called - * and even setting values to existing API system properties would fail in - * user scripts. Scealing was also too strict. - * I assumed that JS_AddNamedRoot() was required for the API class to - * never be freed, so that it can be reused after a call to - * js_context_reset(). Perhaps this is not necessary. - */ - - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - - - -/* - * DEFINITIONS - */ - -/* Size runtime objects must take to run the GC */ -#define GCBYTES 1048576 /* 1MB */ - -/* Size of stack to allocate for every context */ -#define STACKBYTES 8192 /* 8KB */ - -/* - * Structure used to link a context with custom objects we need to perform - * some cleanup from before destroying the context. Ideally managed via - * mmpool(3) in a real world application for slap management and recycling. - * We'll have one of these per process in our pool of processes. - */ -typedef struct { - JSRuntime *rt; - JSContext *ctx; - JSObject *global, *class_fd, *class_errno, *class_signal, - *class_pgsql; -} js_context_t; - -/* - * To hold loaded file objects (actually mmap(2)ed) - */ -typedef struct { - void *data; - size_t size; -} file_t; - -/* - * Defaults for the global class - */ -static JSClass global_class = { - "global", 0, JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, - JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub -}; - - - -/* - * PROTOTYPES - */ - -int main(int, char **); -static JSBool branch_callback(JSContext *, JSScript *); - -static file_t *file_load(const char *); -static void file_free(file_t *); - -/* Could be an exported API later on */ -static js_context_t *js_context_init(size_t, size_t); -static void js_context_destroy(js_context_t *); -/* XXX static void js_context_reset(js_context_t *);*/ - - - - - -int -main(int argc, char **argv) -{ - file_t *file; - js_context_t *cctx; - - if (argc != 2) { - (void) fprintf(stderr, "Usage: test \n"); - exit(EXIT_FAILURE); - } - if ((file = file_load(argv[1])) == NULL) { - (void) fprintf(stderr, "Error loading '%s'\n", argv[1]); - exit(EXIT_FAILURE); - } - - /* - * We always need at least one runtime per process, at least one - * context per thread and at least a global object per context - * (standard classes, like Date). - */ - if ((cctx = js_context_init(GCBYTES, STACKBYTES)) == NULL) { - file_free(file); - (void) fprintf(stderr, "js_context_init()\n"); - exit(EXIT_FAILURE); - } - - /* - * This is a very useful and important feature, enable our callback - * function which will get called whenever the script branches - * backwards, returns from a function or exits. It allows us to - * even maintain control in cases where the script loops endlessly. - */ - (void) JS_SetBranchCallback(cctx->ctx, branch_callback); - - /* - * Now enable addProperty() protection for all classes using our - * custom api_class_property_add() function. This will prevent user - * code from adding properties or methods to the API class for - * instance. - * This however requires that properties use the JSPROP_SHARED flag - * since addProperty() method would internally get called to create - * shadow copies for the runtime otherwise. - */ - /* - api_class_protect = JS_TRUE; - */ - - /* - * Now execute script loaded into our file_t. - * We simplify this process by calling JS_EvaluateScript() which - * will first tokenize/compile the result, and then interpret/run it. - * Moreover, it allows the script to optionally return a value - * directly like if it was a function. - * Alternatively, we could use JS_CompileFile() or JS_CompileScript() - * to pre-tokenize the script, and JS_ExecuteScript() to interpret it. - */ - { - jsval rval, pval; - JSString *str; - int i; - - if (JS_EvaluateScript(cctx->ctx, cctx->global, file->data, - file->size, argv[1], 1, &rval)) { - str = JS_ValueToString(cctx->ctx, rval); - (void) printf("Script result: %s\n", - JS_GetStringBytes(str)); - /* - * Attempt to call JS function "callMe" if the script - * created it. - */ - for (i = 0; i < 10; i++) { - pval = INT_TO_JSVAL(i); - if (!JS_CallFunctionName(cctx->ctx, - cctx->global, "callMe", 1, &pval, &rval)) - break; - } - } else { - /* XXX how to obtain error and stack backtrace? */ - } - } - - /* Cleanup */ - file_free(file); - js_context_destroy(cctx); - - exit(EXIT_SUCCESS); -} - -/* - * This function is called during the execution of the script so that we can - * remain in control of the application. If we only allow the scripts to - * define functions for callbacks, we can use the first instance if this event - * to abort the script if wanted, as well. We can then set an alternative - * callback function and execute the script provided functions at specific - * events. Of course, it also would be possible to use setitimer(2) to have - * a SIGALRM signal trigger a function at regular set intervals. - */ -/* ARGSUSED */ -static JSBool -branch_callback(JSContext *ctx, JSScript *script) -{ - static int count = 0; - - if (++count > 1000) { - count = 0; - JS_MaybeGC(ctx); - } - - /* Returning JS_FALSE here aborts the script */ - return JS_TRUE; -} - - - -/* - * Could be an exported API - */ - -static js_context_t * -js_context_init(size_t gc_size, size_t stack_size) -{ - js_context_t *cctx; - - if ((cctx = malloc(sizeof(js_context_t))) == NULL || - (cctx->rt = JS_NewRuntime(gc_size)) == NULL || - (cctx->ctx = JS_NewContext(cctx->rt, stack_size)) == NULL || - (cctx->global = JS_NewObject(cctx->ctx, &global_class, NULL, - NULL)) == NULL || - !JS_InitStandardClasses(cctx->ctx, cctx->global) || - (cctx->class_fd = js_InitFDClass(cctx->ctx, cctx->global)) - == NULL || - (cctx->class_errno = js_InitErrnoClass(cctx->ctx, cctx->global)) - == NULL || - (cctx->class_signal = js_InitSignalClass(cctx->ctx, cctx->global)) - == NULL || - (cctx->class_pgsql = js_InitPGClass(cctx->ctx, cctx->global)) - == NULL) { - /* An error, free any partially allocated resources */ - if (cctx != NULL) - js_context_destroy(cctx); - - return NULL; - } - - return cctx; -} - -static void -js_context_destroy(js_context_t *cctx) -{ - - assert(cctx != NULL); - - if (cctx->ctx != NULL) - JS_DestroyContext(cctx->ctx); - if (cctx->rt != NULL) - JS_DestroyRuntime(cctx->rt); - - free(cctx); -} - -/* - * This function should permit to restore the context to a consistent, known - * state before a new script can be executed using the same context instead of - * having to destroy and recreate contexts everytime. - */ -/* ARGSUSED */ -/* XXX -static void -js_context_reset(js_context_t *cctx) -{ - -} -*/ - - -/* - * Loads specified file and returns a file_t pointer. Note that we only - * internally keep the memory map for read access to the file, rather than an - * open filedescriptor. - */ -static file_t * -file_load(const char *filename) -{ - int fd; - struct stat st; - file_t *file; - - assert(filename != NULL); - - if ((fd = open(filename, O_RDONLY)) != -1) { - if (fstat(fd, &st) == 0) { - if ((file = malloc(sizeof(file_t))) != NULL) { - file->size = (size_t)st.st_size; - - if ((file->data = mmap(NULL, file->size, - PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) - != MAP_FAILED) { - (void) close(fd); - return file; - } - - free(file); - } - } - (void) close(fd); - } - - return NULL; -} - -/* - * Frees a file_t which was returned by a previous file_load() call. - */ -static void -file_free(file_t *file) -{ - - assert(file != NULL); - - (void) munmap(file->data, file->size); - free(file); -} diff --git a/tests/js-test/util/spidermonkey-config b/tests/js-test/util/spidermonkey-config deleted file mode 100755 index 6a3cc76..0000000 --- a/tests/js-test/util/spidermonkey-config +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# Configure script to help build scripts -# by Matthew Mondor - -CFLAGS='-I/usr/local/spidermonkey/include -DXP_UNIX' -LDFLAGS='-Wl,-R/usr/local/spidermonkey/lib -L/usr/local/spidermonkey/lib -ljs' - -DLDFLAGS='-Wl,-R/usr/local/spidermonkey/lib -L/usr/local/spidermonkey/lib -ljs_dbg' - -VERSION='SpiderMonkey 1.5-rc6A' - -usage() -{ - echo - echo 'Usage: spidermonkey-config [-v] [-c] [-l] [-d]' - echo - echo ' -v : Shows SpiderMonkey version' - echo ' -c : Shows flags suitable to append to $CFLAGS' - echo ' -l : Shows flags suitable to append to $LDFLAGS' - echo ' -d : Shows debugging versions of the flags' - echo -} - -if [ -z $@ ]; then - usage - exit 0 -fi - -while getopts dclv c; do - case $c in - d) - LDFLAGS="$DLDFLAGS" - ;; - c) - echo $CFLAGS - ;; - l) - echo $LDFLAGS - ;; - v) - echo $VERSION - ;; - *) - usage - exit 0 - ;; - esac -done diff --git a/tests/kqueue/GNUmakefile b/tests/kqueue/GNUmakefile deleted file mode 100644 index 4ae0616..0000000 --- a/tests/kqueue/GNUmakefile +++ /dev/null @@ -1,22 +0,0 @@ -# $Id: GNUmakefile,v 1.7 2006/04/23 04:40:14 mmondor Exp $ - -MMLIB_PATH := ../../mmlib - -MMLIBS := $(addprefix ${MMLIB_PATH}/,mmpool.o mmstring.o mmarch.o) -LIBS := -lc -OBJS := main.o net.o kqueue.o sendq.o recvq.o packets.o daemon.o client.o -CFLAGS += -Wall -BINS := daemon - -all: $(BINS) - -%.o: %.c - cc -c ${CFLAGS} -I. -I${MMLIB_PATH} -o $@ $< - - -daemon: $(MMLIBS) $(LIBS) $(OBJS) - cc -o $@ $(MMLIBS) $(OBJS) $(LIBS) - - -clean: - rm -f $(BINS) $(OBJS) $(MMLIBS) $(LIBS) diff --git a/tests/kqueue/README b/tests/kqueue/README deleted file mode 100644 index 3d58fc4..0000000 --- a/tests/kqueue/README +++ /dev/null @@ -1,48 +0,0 @@ -$Id: README,v 1.3 2006/04/23 04:40:14 mmondor Exp $ - -If this all works fine, it might be the basis of a multiplayer -networking game. However, this is primarily a test to learn kqueue -and observe its efficiency, as well as to experiment using TCP for -such massive multiplayer games on today's networks and internet. - -Many games that used TCP for LAN use a while back had to develop -UDP based protocols to be efficient enough for dialup users or -other internet users. We will determine if this is still necessary -on today's average internet latencies. - -We probably still want to prioritize some packets over others. -For instance, we might drop outgoing position update packets which -cannot be sent immediately instead of queueing them, allowing less -frequent updates to slow connections while not needing to provide -multiple independent game heart rates. - -We do not expect to have to port the server part of the game, wich -is intended to run on BSD systems supporting the kqueue(2) system -only. We could have used an event library, however we wanted to -avoid including non-BSD licensed components. Although there is a -BSD licensed libevent as part of NetBSD, using kqueue directly -allows a few fancy optimization tricks which would require a new -portable events library to be designed to allow to achieve the full -advantages of kqueue using an abstracted library. - -The client code, however, will be portable and should be able to -run on Win32 without needing the cygwin runtime libraries. The -SDL dependency is reasonable, and can be provided separately, so -mingw will be used to create those executables. The client will -however primarily be developped on NetBSD. Like SDL, OpenGL -libraries shouldn't be a problem either. - -To avoid using cygwin, and because Win32 winsock does not conform -to BSD sockets API standards, we expect to have to write a simple -portable networking layer for use in the client. - - -TODO - -- At this point to advance further a client needs to be written. -- We probably don't need to align packets, we only need to make sure - that their size is 32-bit aligned, and that their 16-bit fields are - 16-bit aligned, their 32-bit ones 32-bit aligned. Packet type field - can be 8-bit. If we allowed arbitrary offsets when buffering packets, - we would need to copy each packet to an aligned buffer as we process them. - Evaluate which is more advantageous. diff --git a/tests/kqueue/client.c b/tests/kqueue/client.c deleted file mode 100644 index 7fa0caa..0000000 --- a/tests/kqueue/client.c +++ /dev/null @@ -1,152 +0,0 @@ -/* $Id: client.c,v 1.9 2006/04/23 04:40:14 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include -#include - -#include "client.h" -#include "kqueue.h" -#include "conf.h" - - - -list_t clients_list; -static list_t clients_gc_list; -static pool_t clients_pool; - - - -void -client_init(void) -{ - DLIST_INIT(&clients_list); - DLIST_INIT(&clients_gc_list); - - if (!pool_init(&clients_pool, "clients_pool", malloc, free, NULL, - NULL, sizeof(client_t), MAX_CLIENTS + 1, 1, 1)) { - syslog(LOG_NOTICE, "pool_init() - %s", strerror(errno)); - exit(EXIT_FAILURE); - } - -} - -/* - * Enables the write polling filter for the specified client. - */ -void -client_enable_write_polling(void *args) -{ - client_t *c = (client_t *)args; - - if (c->writepolling) - return; - - kqueue_sev_alloc(1); - kqueue_sev_add(c->fd, EVFILT_WRITE, EV_ENABLE, 0, 0, (intptr_t)c); - - c->writepolling = 1; -} - -inline int -client_write(client_t *c, uint8_t *buf, size_t size, int buffer) -{ - - if (sendq_write(&c->sendq, buf, size, client_enable_write_polling, c, - buffer) == -1) { - syslog(LOG_NOTICE, "sendq_write(%u) - %s", size, - strerror(errno)); - return -1; - } - - return 0; -} - -/* - * XXX We should do connection rate/concurrency checking on address here. - */ -client_t * -client_create(int fd, struct sockaddr *saddr) -{ - client_t *c; - - if (DLIST_NODES(&clients_list) > MAX_CLIENTS) { - syslog(LOG_NOTICE, "client_create() - MAX_CLIENTS reached"); - return NULL; - } - - if ((c = (client_t *)pool_alloc(&clients_pool, FALSE)) != NULL) { - if (sendq_init(&c->sendq, fd, SENDQ_SIZE) != -1) { - if (recvq_init(&c->recvq, fd, RECVQ_SIZE) != -1) { - c->fd = fd; - (void) memcpy(&c->saddr, saddr, - sizeof(struct sockaddr)); - - c->object.x = random() % WORLD_X_MAX; - c->object.y = random() % WORLD_Y_MAX; - c->object.direction = c->object.i_direction = - random() % 1000; - c->object.thrust = c->object.i_thrust = - random() % 20; - - c->authenticated = c->todestroy = - c->toclose = 0; - c->writepolling = 1; - c->askedping = 0; - - DLIST_APPEND(&clients_list, &c->node); - - return c; - } - syslog(LOG_NOTICE, - "client_create() - recvq_init() - %s", - strerror(errno)); - sendq_destroy(&c->sendq); - } - syslog(LOG_NOTICE, - "client_create() - sendq_init() - %s", strerror(errno)); - pool_free((pnode_t *)c); - } - syslog(LOG_NOTICE, "client_create() - pool_alloc() - %s", - strerror(errno)); - - return NULL; -} - -void -client_destroy_mark(client_t *c) -{ - - if (c->todestroy) - return; - - c->todestroy = 1; - DLIST_SWAP(&clients_gc_list, &clients_list, &c->node, FALSE); -} - -void -client_destroy_marked(void) -{ - node_t *i, *n; - client_t *c; - - for (i = DLIST_TOP(&clients_gc_list); i != NULL; i = n) { - n = DLIST_NEXT(i); - - c = (client_t *)i; - /* Closing descriptor automatically deletes its kevents */ - (void) close(c->fd); - recvq_destroy(&c->recvq); - sendq_destroy(&c->sendq); - pool_free((pnode_t *)c); - } - DLIST_INIT(&clients_gc_list); -} diff --git a/tests/kqueue/client.h b/tests/kqueue/client.h deleted file mode 100644 index a9575fc..0000000 --- a/tests/kqueue/client.h +++ /dev/null @@ -1,59 +0,0 @@ -/* $Id: client.h,v 1.7 2006/04/03 08:56:45 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _CLIENT_H_ -#define _CLIENT_H_ - - - -#include -#include - -#include -#include - -#include "sendq.h" -#include "recvq.h" - - - -typedef struct object { - node_t region; - int32_t direction, thrust; - int32_t i_direction, i_thrust; - int32_t x, y; -} object_t; - -typedef struct client { - node_t node; - object_t object; - sendq_t sendq; - recvq_t recvq; - int fd; - struct sockaddr saddr; - int authenticated, todestroy, toclose, writepolling, - askedping; -} client_t; - - - -extern list_t clients_list; - - -void client_init(void); -void client_enable_write_polling(void *); -inline int client_write(client_t *, u_int8_t *, size_t, int); - -client_t *client_create(int, struct sockaddr *); -void client_destroy_mark(client_t *); -void client_destroy_marked(void); - - - -#endif diff --git a/tests/kqueue/conf.h b/tests/kqueue/conf.h deleted file mode 100644 index 5720c1a..0000000 --- a/tests/kqueue/conf.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id: conf.h,v 1.9 2006/04/23 04:40:14 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _CONF_H_ -#define _CONF_H_ - - - -#define SERVER_VERSION 1 -#define SERVER_STRING "daemon/mmondor\n" - -#define FPS 10 -#define FPS_MS (1000 / FPS) - -#define WORLD_X_MAX 640 -#define WORLD_Y_MAX 480 - -#define MAX_CLIENTS 128 -#define R_EVENTS (MAX_CLIENTS * 2) -#define S_EVENTS (MAX_CLIENTS * 2) - -#define SENDQ_SIZE 16384 -#define RECVQ_SIZE 1024 - -/* In seconds */ -#define INPUT_TIMEOUT 30 -#define PING_TIMEOUT 5 - -#define PIDFILE "/tmp/daemon.pid" - - - -#endif diff --git a/tests/kqueue/daemon.c b/tests/kqueue/daemon.c deleted file mode 100644 index bd38e65..0000000 --- a/tests/kqueue/daemon.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id: daemon.c,v 1.3 2006/04/23 04:40:14 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Procedure for becoming an detached daemon, as well as to prepare process - * signal handling. Since we'll be catching signal events through kqueue(2), - * We simply ignore all signals for which we don't want the default behavior. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - - - -static int signal_init(void); -static void pidfile_write(const char *); - - - -static int -signal_init(void) -{ - struct sigaction act; - int i; - int sigs[] = { - SIGHUP, - SIGINT, - SIGPIPE, - SIGALRM, - SIGTERM, - SIGTTIN, - SIGTTOU, - SIGIO, - SIGXCPU, - SIGXFSZ, - SIGVTALRM, - SIGPROF, - SIGUSR1, - SIGUSR2 - }; - - act.sa_handler = SIG_IGN; - act.sa_flags = SA_NOCLDSTOP; - (void) sigemptyset(&act.sa_mask); - - for (i = 0; i < (sizeof(sigs) / sizeof(int)); i++) { - if (sigaction(sigs[i], &act, NULL) != 0) { - syslog(LOG_NOTICE, - "signal_init() - sigaction(%d) - %s", - sigs[i], strerror(errno)); - return -1; - } - } - - return 0; -} - -/* - * Writes our process ID number to specified file. To be called before - * chroot(2) or dropping privileges. - */ -static void -pidfile_write(const char *file) -{ - char str[16]; - int fd; - - if ((fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0600)) != -1) { - (void) snprintf(str, 15, "%d\n", getpid()); - (void) write(fd, str, mm_strlen(str)); - (void) close(fd); - } else - syslog(LOG_NOTICE, "pidfile_write() - open(%s) - %s", - file, strerror(errno)); -} - -int -daemon_init(void) -{ - pid_t pid; - int fd; - - /* Create new process */ - if ((pid = fork()) == -1) { - syslog(LOG_NOTICE, "fork() - %s", strerror(errno)); - return -1; - } - if (pid != 0) - exit(EXIT_SUCCESS); - - pidfile_write(PIDFILE); - - /* Create new process group and detach */ - (void) setsid(); - (void) chdir("/"); - if ((fd = open("/dev/null", O_RDWR)) != -1) { - (void) dup2(fd, STDIN_FILENO); - (void) dup2(fd, STDOUT_FILENO); - (void) dup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - (void) close(fd); - } else - syslog(LOG_NOTICE, "daemon_init() - open(/dev/null) - %s", - strerror(errno)); - - if (signal_init() != 0) - return -1; - - return 0; -} diff --git a/tests/kqueue/daemon.h b/tests/kqueue/daemon.h deleted file mode 100644 index 32ec407..0000000 --- a/tests/kqueue/daemon.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: daemon.h,v 1.2 2006/03/31 20:57:08 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _DAEMON_H_ -#define _DAEMON_H_ - - - -int daemon_init(void); - - - -#endif diff --git a/tests/kqueue/kqueue.c b/tests/kqueue/kqueue.c deleted file mode 100644 index a5a8628..0000000 --- a/tests/kqueue/kqueue.c +++ /dev/null @@ -1,329 +0,0 @@ -/* $Id: kqueue.c,v 1.11 2006/04/03 21:06:08 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include -#include -#include - -#include - -#include "kqueue.h" -#include "client.h" -#include "packets.h" -#include "net.h" -#include "conf.h" - - - -static struct kevent rev[R_EVENTS], sev[S_EVENTS]; -static int kqid, rev_cnt, sev_cnt; - - - -/* The following functions simply exit on failure, because they are critical */ - -void -kqueue_init(void) -{ - - if ((kqid = kqueue()) == -1) { - syslog(LOG_NOTICE, "kqueue_init() - kqueue() - %s", - strerror(errno)); - exit(EXIT_FAILURE); - } - - sev_cnt = 0; -} - -void -kqueue_addlisten(int fd) -{ - - EV_SET(sev, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, (intptr_t)NULL); - if (kevent(kqid, sev, 1, NULL, 0, NULL) == -1) { - syslog(LOG_NOTICE, "kqueue_addlisten() - kevent(%d) - %s", - fd, strerror(errno)); - exit(EXIT_FAILURE); - } - -} - -void -kqueue_addsignal(int sig) -{ - - EV_SET(sev, sig, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, - (intptr_t)NULL); - if (kevent(kqid, sev, 1, NULL, 0, NULL) == -1) { - syslog(LOG_NOTICE, "kqueue_addsignal() - kevent(%d) - %s", - sig, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -void -kqueue_addtimer0(int64_t ms) -{ - - EV_SET(sev, 0, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, ms, - (intptr_t)NULL); - if (kevent(kqid, sev, 1, NULL, 0, NULL) == -1) { - syslog(LOG_NOTICE, "kevent_addtimer0() - kevent(%lld) - %s", - ms, strerror(errno)); - exit(EXIT_FAILURE); - } -} - -void -kqueue_main(void) -{ - - for (;;) { - int e, i; - struct kevent *kev; - client_t *c; - - /* - * Fusion to only require one kevent(2) call if there are - * events to send. Wait for events to occur. - * This also allows us to catch error events. - */ - if ((rev_cnt = kevent(kqid, sev, sev_cnt, rev, R_EVENTS, NULL)) - == -1) { - syslog(LOG_NOTICE, "kevent(1) - %s", strerror(errno)); - continue; - } - sev_cnt = 0; - - /* Run through received events and process them */ - for (e = 0; e < rev_cnt; e++) { - kev = &rev[e]; - - /* Report errors if any */ - if ((kev->flags & EV_ERROR) != 0) { - syslog(LOG_NOTICE, - "EV_ERROR: ident=%d filter=%d flags=%d " - "fflags=%d data=%lld udata=%p", - kev->ident, kev->filter, kev->flags, - kev->fflags, kev->data, - (void *)kev->udata); - continue; - } - - /* Process signals if any */ - if (kev->filter == EVFILT_SIGNAL) { - switch (kev->ident) { - case SIGTERM: - syslog(LOG_NOTICE, - "Received SIGTERM, exiting"); - exit(EXIT_SUCCESS); - break; - } - continue; - } - - /* Process timeouts if any */ - if (kev->filter == EVFILT_TIMER) { - if (kev->ident == 0) { - /* Main heartrate timer */ - update(); - continue; - } - /* - * XXX input timeout timers? - * We'll need an input timer per socket, - * which gets canceled whenever input arrives, - * but once expires launches a server ping - * request which then should trigger another - * timer, which if pong occurs gets restarted, - * but if it exceeds client gets dropped. - * We'll also need to match timer events with - * filedescriptors, as well as reason for - * timeout... And we'll need to make sure to - * clean out any pending timers when marking a - * client to be destroyed (or when destroying - * them, at least). - */ - } - - if (kev->ident == listen_fd) { - int t; - - /* - * Accept new connections, create clients and - * add new descriptors to the kqueue set, - * buffering them to minimize syscalls. - */ - for (i = 0, t = kev->data; i < t; i++) { - struct sockaddr saddr; - socklen_t saddrl; - client_t *c; - int fd; - - saddrl = sizeof(struct sockaddr); - if ((fd = accept(listen_fd, &saddr, - &saddrl)) == -1) - continue; - - if ((c = client_create(fd, &saddr)) - == NULL) { - (void) close(fd); - continue; - } - - kqueue_sev_alloc(2); - kqueue_sev_add(fd, EVFILT_READ, - EV_ADD | EV_EOF | EV_ENABLE, 0, 0, - (intptr_t)c); - kqueue_sev_add(fd, EVFILT_WRITE, - EV_ADD | EV_EOF | EV_ENABLE, 0, 0, - (intptr_t)c); - - /* Send auth request packet */ - if (spacket_auth_send(c) == -1) { - client_destroy_mark(c); - continue; - } - } - continue; - } - - /* - * Don't process any more events for marked to be - * destroyed clients, or those without an associated - * udata. When client descriptor must be closed and - * client structure freed, we make sure to first mark - * it as to destroy within this loop, since it's - * possible for more than one event to occur for a - * single descriptor. We use client_destroy_mark() - * for this purpose. - */ - if ((c = (client_t *)kev->udata) == NULL) { - /* XXX */ - syslog(LOG_NOTICE, "udata == NULL"); - continue; - } - if (c->todestroy) - continue; - - if ((kev->flags & EV_EOF) != 0) { - client_destroy_mark(c); - continue; - } - - if (kev->filter == EVFILT_WRITE) { - int f; - - /* - * If there's a sendq for the client, - * attempt to flush it. If there's an error, - * drop client. - * If client was marked to be closed, and we - * finished flusing data, also mark it to be - * destroyed, since were done with it. - */ - if ((f = sendq_flush(&c->sendq, kev->data)) - == -1 || (f == 0 && c->toclose)) - client_destroy_mark(c); - else if (f == 0) { - /* - * No more data to send, we can thus - * temporarily disable write events - * for this descriptor. client_write() - * will re-enable it as necessary. - */ - kqueue_sev_alloc(1); - kqueue_sev_add(c->fd, EVFILT_WRITE, - EV_DISABLE, 0, 0, (intptr_t)c); - c->writepolling = 0; - } - continue; - } - - if (kev->filter == EVFILT_READ) { - int16_t *buf; - size_t size; - - /* - * Data to read from client. Simply read it - * into a queue to process it at the next - * server heartbeat event. - * XXX We should be able to process ping - * requests immediately. This means that - * we need recvq_read() to report more - * information. - */ - if (recvq_read(&c->recvq, &buf, &size) == -1) { - client_destroy_mark(c); - continue; - } - - /* Convert packet_type to host endian */ - *buf = BYTEORDER_HOST16(*buf); - - /* - * If ping packet, process immediately - * and discard packet from recvq. - * We only allow ping if c->askedping - * is unset, and we set it. It will be unset - * at the next server heart beat. This way, - * we only allow clients to ping once per - * frame at most. - */ - if (*buf == CPACKET_PING && - size == sizeof(struct cpacket_ping)) { - if (!c->authenticated || - c->askedping || - spacket_pong_send(c) == -1) { - client_destroy_mark(c); - continue; - } - recvq_rewind(&c->recvq, size); - } - - continue; - } - - } - /* Destroy marked to be destroyed clients */ - client_destroy_marked(); - } - /* NOTREACHED */ -} - - -/* Utility functions */ - -inline void -kqueue_sev_alloc(int n) -{ - - if (sev_cnt > S_EVENTS - n) { - if (kevent(kqid, sev, sev_cnt, NULL, 0, NULL) == -1) - syslog(LOG_NOTICE, - "kqueue_sev_alloc() - kevent() - %s", - strerror(errno)); - sev_cnt = 0; - } -} - -inline void -kqueue_sev_add(uintptr_t ident, uint32_t filter, uint32_t flags, - uint32_t fflags, int64_t data, intptr_t udata) -{ - - /* - * Be careful to avoid macro side effects, do not use &sev[sev_cnt++] - */ - EV_SET(&sev[sev_cnt], ident, filter, flags, fflags, data, udata); - sev_cnt++; -} diff --git a/tests/kqueue/kqueue.h b/tests/kqueue/kqueue.h deleted file mode 100644 index 700e063..0000000 --- a/tests/kqueue/kqueue.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $Id: kqueue.h,v 1.4 2006/04/01 00:46:24 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _KQUEUE_H_ -#define _KQUEUE_H_ - - - -#include -#include - - - -void kqueue_init(void); -void kqueue_addlisten(int); -void kqueue_addsignal(int); -void kqueue_addtimer0(int64_t); -void kqueue_main(void); -inline void kqueue_sev_alloc(int); -inline void kqueue_sev_add(uintptr_t, uint32_t, uint32_t, uint32_t, - int64_t, intptr_t); - - - -#endif diff --git a/tests/kqueue/main.c b/tests/kqueue/main.c deleted file mode 100644 index 24611a0..0000000 --- a/tests/kqueue/main.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $Id: main.c,v 1.10 2006/04/01 00:46:24 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "daemon.h" -#include "net.h" -#include "sendq.h" -#include "packets.h" -#include "client.h" -#include "conf.h" -#include "kqueue.h" - - - -int main(int, char **); - - - -int -main(int argc, char **argv) -{ - - (void) openlog("daemon", LOG_NDELAY | LOG_PID, LOG_USER); - - if (daemon_init() != 0) - exit(EXIT_FAILURE); - syslog(LOG_NOTICE, "Started"); - - /* - * The following funtions exit whenever there's a problem, because - * they set up critical things. - */ - client_init(); - kqueue_init(); - net_init(); - kqueue_addlisten(listen_fd); - kqueue_addsignal(SIGTERM); - kqueue_addtimer0(FPS_MS); - - kqueue_main(); - /* NOTREACHED */ - - return EXIT_SUCCESS; -} diff --git a/tests/kqueue/net.c b/tests/kqueue/net.c deleted file mode 100644 index 6202c98..0000000 --- a/tests/kqueue/net.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id: net.c,v 1.2 2006/04/01 00:46:24 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "net.h" -#include "conf.h" - - - -static int net_listen(const char *, int, int); - - - -int listen_fd; - - - -void -net_init(void) -{ - - if ((listen_fd = net_listen("0.0.0.0", 7777, MAX_CLIENTS)) == -1) { - syslog(LOG_NOTICE, "net_listen() - %s", strerror(errno)); - exit(EXIT_FAILURE); - } -} - -static int -net_listen(const char *addr, int port, int backlog) -{ - int fd, opt; - struct linger linger; - struct protoent *pent; - struct sockaddr_in server; - - fd = -1; - - mm_memclr(&server, sizeof(struct sockaddr_in)); - server.sin_family = AF_INET; - if (inet_pton(AF_INET, addr, &server.sin_addr) != 1) { - syslog(LOG_NOTICE, "inet_pton(%s) - %s", addr, - strerror(errno)); - goto err; - } - server.sin_port = htons((short)port); - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - syslog(LOG_NOTICE, "socket() - %s", strerror(errno)); - goto err; - } - - opt = 1; - if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int))) - == -1) - syslog(LOG_NOTICE, "setsockopt(SO_REUSEADDR) - %s", - strerror(errno)); - if ((setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(int))) - == -1) - syslog(LOG_NOTICE, "setsockopt(SO_KEEPALIVE) - %s", - strerror(errno)); - - linger.l_onoff = 0; - linger.l_linger = 0; - if ((setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, - sizeof(struct linger))) == -1) - syslog(LOG_NOTICE, "setsockopt(SO_LINGER) - %s", - strerror(errno)); - - /* XXX Set buffer sizes? */ - - if ((pent = getprotobyname("TCP")) != NULL) { - opt = 1; - if ((setsockopt(fd, pent->p_proto, TCP_NODELAY, &opt, - sizeof(int))) == -1) - syslog(LOG_NOTICE, "setsockopt(TCP_NODELAY) - %s", - strerror(errno)); - } else - syslog(LOG_NOTICE, "getprotobyname(TCP) - %s", - strerror(errno)); - - if ((opt = fcntl(fd, F_GETFL, NULL)) != -1) { - if (fcntl(fd, F_SETFL, opt | O_NONBLOCK) == -1) { - syslog(LOG_NOTICE, "fcntl(F_SETFL) - %s", - strerror(errno)); - goto err; - } - } else - syslog(LOG_NOTICE, "fcntl(F_GETFL) - %s", strerror(errno)); - - if ((bind(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in))) - != 0) { - syslog(LOG_NOTICE, "bind(%s:%d) - %s", addr, port, - strerror(errno)); - goto err; - } - - if (listen(fd, backlog) == -1) { - syslog(LOG_NOTICE, "listen(%s:%d) - %s", addr, port, - strerror(errno)); - goto err; - } - - return fd; - -err: - if (fd != -1) - (void) close(fd); - - return -1; -} diff --git a/tests/kqueue/net.h b/tests/kqueue/net.h deleted file mode 100644 index 3607cc9..0000000 --- a/tests/kqueue/net.h +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: net.h,v 1.2 2006/04/01 00:46:24 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _NET_H_ -#define _NET_H_ - - - -void net_init(void); - - - -extern int listen_fd; - - - -#endif diff --git a/tests/kqueue/packets.c b/tests/kqueue/packets.c deleted file mode 100644 index 83da958..0000000 --- a/tests/kqueue/packets.c +++ /dev/null @@ -1,327 +0,0 @@ -/* $Id: packets.c,v 1.14 2006/04/03 20:38:43 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * To validate a received packet, we'll make sure that it's larger than - * sizeof(int), and that the first integer consists of a valid expected packet - * type ID within range. If so, we verify if packet length really corresponds - * to the packet type, and then can interpret the packet information. - * An actual network packet may contain a number of these packets. - * We thus must be able to efficiently determine each packet's length. - * Since we're using TCP, it should be enough. However, on the server side - * especially, proper sanity checking on input must be done to avoid crashing - * the server because of unexpected data processing. - */ - - - -#include - -#include -#include - -#include "packets.h" -#include "client.h" -#include "sendq.h" -#include "conf.h" - - - -static int cpacket_auth_handler(client_t *, uint16_t *); -static int cpacket_ping_handler(client_t *, uint16_t *); -static int cpacket_pong_handler(client_t *, uint16_t *); -static int cpacket_direction_handler(client_t *, uint16_t *); -static int cpacket_thrust_handler(client_t *, uint16_t *); -static int cpacket_torp_handler(client_t *, uint16_t *); -static int cpacket_quit_handler(client_t *, uint16_t *); - - - -static struct packet_index cpacket_index[CPACKET_MAX] = { - {sizeof(struct cpacket_auth), cpacket_auth_handler}, - {sizeof(struct cpacket_ping), cpacket_ping_handler}, - {sizeof(struct cpacket_pong), cpacket_pong_handler}, - {sizeof(struct cpacket_direction), cpacket_direction_handler}, - {sizeof(struct cpacket_thrust), cpacket_thrust_handler}, - {sizeof(struct cpacket_torp), cpacket_torp_handler}, - {sizeof(struct cpacket_quit), cpacket_quit_handler} -}; - - - -void -update(void) -{ - node_t *nod, *next; - client_t *c; - uint8_t *data; - size_t size, off; - - for (nod = DLIST_TOP(&clients_list); nod != NULL; nod = next) { - next = DLIST_NEXT(nod); - c = (client_t *)nod; - - if (c->todestroy || c->toclose) - continue; - - /* Reset ping request throttling flag */ - c->askedping = 0; - - /* First process incomming packets */ - recvq_content(&c->recvq, &data, &size); - for (off = 0; off < size; ) { - int16_t *id; - - /* - * Verify packet type ID. It already has been - * converted to host endian byte order, unlike other - * packet fields. - */ - id = (int16_t *)&data[off]; - *id = BYTEORDER_HOST16(*id); - if (*id < 0 || *id > CPACKET_MAX) { - client_destroy_mark(c); - break; - } - - /* There must be enough data for packet size */ - if (size - off < cpacket_index[*id].size) { - /* - * Kill authentucated client if other packets - * than CPACKET_AUTH - */ - if (!c->authenticated && *id != CPACKET_AUTH) - goto k; - - /* - * XXX We'll need to also do special - * processing for chat packets, since they'll - * have arbitrary length. They'll still need - * to be 16-bit aligned, too. - */ - - /* Kill client on packet processing error */ - if (cpacket_index[*id].handler(c, - (uint16_t *)off) == -1) - goto k; - } else - goto k; - - /* Process next packet if any */ - off += cpacket_index[*id].size; - continue; - -k: - client_destroy_mark(c); - break; - } - - /* - * XXX I don't like having to run the clients list all over, - * to then run through all objects (including clients) to - * update them, and then yet again through all objects to send - * updates to all clients. - */ - - /* Run game frame on all objects */ - DLIST_FOREACH(&clients_list, nod) { - client_t *c = (client_t *)nod; - - /* - if (!c->authenticated) - continue; - */ - - /* - * First update direction and thrust. - * XXX I could do a small function or macro to deal - * with similar situations, i.e. - * change_update(int goal, int *current, int steps); - */ - if (c->object.direction < c->object.i_direction) - c->object.direction++; - else if (c->object.direction > c->object.i_direction) - c->object.direction--; - if (c->object.thrust < c->object.i_thrust) - c->object.thrust++; - else if (c->object.thrust > c->object.i_thrust) - c->object.thrust--; - - /* - * Translate object x/y position according to - * trust/direction. When reaching borders we simply - * bounce for now. - * (I need to review my trigonometry a bit again :) - */ - /* XXX */ - c->object.x += 1 - (random() & 2); - if (c->object.x < 0) - c->object.x = 0; - else if (c->object.x > WORLD_X_MAX - 1) - c->object.x = WORLD_X_MAX - 1; - c->object.y += 1 - (random() & 2); - if (c->object.y < 0) - c->object.y = 0; - else if (c->object.y > WORLD_Y_MAX - 1) - c->object.y = WORLD_Y_MAX - 1; - } - - /* Send update frame information packets */ - DLIST_FOREACH(&clients_list, nod) { - client_t *c = (client_t *)nod; - node_t *nod2; - - /* - if (!c->authenticated) - continue; - */ - - DLIST_FOREACH(&clients_list, nod2) { - if (spacket_position_send(c, - &((client_t *)nod2)->object) == -1) - break; - } - (void) sendq_flush(&c->sendq, -1); - } - } -} - - -int -spacket_auth_send(client_t *c) -{ - struct spacket_auth p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_AUTH); - mm_memclr(p.string, 32); - mm_strncpy(p.string, SERVER_STRING, 31); - p.protocol_version = BYTEORDER_NETWORK16(SERVER_VERSION); - /* XXX */ - - return client_write(c, (uint8_t *)&p, sizeof(p), 0); -} - -int -spacket_pong_send(client_t *c) -{ - struct spacket_pong p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_PONG); - - return client_write(c, (uint8_t *)&p, sizeof(p), 0); -} - -int -spacket_position_send(client_t *c, object_t *o) -{ - struct spacket_position p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_POSITION); - p.object_id = p.object_type = BYTEORDER_NETWORK16(0); /* XXX */ - p.x = BYTEORDER_NETWORK16(o->x); - p.y = BYTEORDER_NETWORK16(o->y); - p.direction - BYTEORDER_NETWORK16(o->direction); - - return client_write(c, (uint8_t *)&p, sizeof(p), 1); -} - - -/* Note that only the packet_type field is endian converted yet. */ - -static int -cpacket_auth_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_auth *p = (struct cpacket_auth *)ptr; - - p->protocol_version = BYTEORDER_HOST16(p->protocol_version); - - if (c->authenticated || p->protocol_version < SERVER_VERSION) - return -1; - - /* - * XXX For now. Eventually also check user/password - * We could use APOP-like authentication where server sends random - * data as part of the authentication greeting/request, and expect - * client to append password to random data and send hashed result. - * We also should do user concurrency checking here. - */ - c->authenticated = 1; - - return 0; -} - -/* - * Note: Following function is never used, since pings are handled in the - * kqueue main loop code. - */ -/* ARGSUSED */ -static int -cpacket_ping_handler(client_t *c, uint16_t *ptr) -{ - /* NOOP */ - - return 0; -} - -static int -cpacket_pong_handler(client_t *c, uint16_t *ptr) -{ -/* struct cpacket_pong *p = (struct cpacket_pong *)ptr;*/ - - /* XXX */ - - return 0; -} - -static int -cpacket_direction_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_direction *p = (struct cpacket_direction *)ptr; - - p->direction = BYTEORDER_HOST16(p->direction); - - /* Radians */ - if (p->direction < 0 || p->direction > 1000) - return -1; - - c->object.i_direction = p->direction; - - return 0; -} - -static int -cpacket_thrust_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_thrust *p = (struct cpacket_thrust *)ptr; - - p->thrust = BYTEORDER_HOST16(p->thrust); - - if (p->thrust < 0 || p->thrust > 20) - return -1; - - c->object.i_thrust = p->thrust; - - return 0; -} - -static int -cpacket_torp_handler(client_t *c, uint16_t *ptr) -{ -/* struct cpacket_torp *p = (struct cpacket_torp *)ptr;*/ - - /* XXX */ - - return 0; -} - -/* ARGSUSED */ -static int -cpacket_quit_handler(client_t *c, uint16_t *ptr) -{ - - return -1; -} diff --git a/tests/kqueue/packets.h b/tests/kqueue/packets.h deleted file mode 100644 index ea668d1..0000000 --- a/tests/kqueue/packets.h +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id: packets.h,v 1.9 2006/04/03 20:37:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * All packets must begin with an int16_t packet_type. All fields of a packet - * must either be [u]int8_t, [u]int16_t, [u]int32+t or [u]int64_t. Moreover, - * all fields will be passed in network/big endian byte order when sent over - * the network. We could have used a union, but this would have resulted in - * larger, fixed sized packets wasting bandwidth. Since a server to client - * update will generally involve sending more than one such packet in a row, - * it is important to minimize their size. - * Note: If using 32-bit fields within a packet, make sure that they are - * 32-bit aligned. - */ - - - -#ifndef _PACKETS_H_ -#define _PACKETS_H_ - - - -#include - -#include "client.h" - - - -/* - * For every server packet type we support, an index array will be used - * with this structure to call the associated handler function, which will - * perform sanity checking and process the packet, returning 0 on success or - * -1 on error. The size field will allow to perform sanity checking on - * data size prior to calling the handler function, as well as to increase the - * buffer pointer. - */ -struct packet_index { - size_t size; - int (*handler)(client_t *, uint16_t *); -}; - - - -/* - * Server to client packets - */ - -enum spacket_types { - SPACKET_AUTH = 0, - SPACKET_PING, - SPACKET_PONG, - SPACKET_POSITION, - SPACKET_COLLISION, - SPACKET_MAX -}; - -/* Used to request client authentication and respond success/failure */ -struct spacket_auth { - int16_t packet_type; - int16_t protocol_version; - char string[32]; - /* XXX */ -} __attribute__((__packed__)); - -/* And for server to test idle connections */ -struct spacket_ping { - int16_t packet_type; -} __attribute__((__packed__)); - -/* And clients to test latency */ -struct spacket_pong { - int16_t packet_type; -} __attribute__((__packed__)); - -/* Object position/direction update to client */ -struct spacket_position { - int16_t packet_type; - int16_t object_id, object_type; - int16_t x, y, direction; -} __attribute__((__packed__)); - -/* Collision/detonation update to client */ -struct spacket_collision { - int16_t packet_type; - int16_t collision_type; - int16_t object1_id, object2_id; -} __attribute__((__packed__)); - - - -/* - * Client to server packets - */ - -enum cpacket_tyoes { - CPACKET_AUTH = 0, - CPACKET_PING, - CPACKET_PONG, - CPACKET_DIRECTION, - CPACKET_THRUST, - CPACKET_TORP, - CPACKET_QUIT, - CPACKET_MAX -}; - -/* Used to respond to server authentication request */ -struct cpacket_auth { - int16_t packet_type; - int16_t protocol_version; - char string[32]; - /* XXX */ -} __attribute__((__packed__)); - -/* To ping server for latency mesurement */ -struct cpacket_ping { - int16_t packet_type; -} __attribute__((__packed__)); - -/* To respond to server ping requests */ -struct cpacket_pong { - int16_t packet_type; -} __attribute__((__packed__)); - -/* Angle/direction change request */ -struct cpacket_direction { - int16_t packet_type; - int16_t direction; -} __attribute__((__packed__)); - -/* Speed change request */ -struct cpacket_thrust { - int16_t packet_type; - int16_t thrust; -} __attribute__((__packed__)); - -/* Torpedo fire request */ -struct cpacket_torp { - int16_t packet_type; - int16_t direction; -} __attribute__((__packed__)); - -/* Game quit request */ -struct cpacket_quit { - int16_t packet_type; -} __attribute__((__packed__)); - - - -void update(void); -int spacket_auth_send(client_t *); -int spacket_pong_send(client_t *); -int spacket_position_send(client_t *, object_t *); - - - -#endif diff --git a/tests/kqueue/recvq.c b/tests/kqueue/recvq.c deleted file mode 100644 index 663ecba..0000000 --- a/tests/kqueue/recvq.c +++ /dev/null @@ -1,84 +0,0 @@ -/* $Id: recvq.c,v 1.5 2006/04/05 09:19:16 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -#include -#include -#include -#include - -#include "recvq.h" - - - -int -recvq_init(recvq_t *q, int fd, size_t size) -{ - - if ((q->buffer = malloc(size)) == NULL) - return -1; - - q->fd = fd; - q->size = size; - q->tail = 0; - - return 0; -} - -void -recvq_destroy(recvq_t *q) -{ - - free(q->buffer); -} - -int -recvq_read(recvq_t *q, int16_t **buf, size_t *size) -{ - ssize_t s; - - if (q->tail == q->size) - return -1; - - if (((s = read(q->fd, &q->buffer[q->tail], q->size - q->tail)) == -1 && - errno != EAGAIN) || s == 0) - return -1; - - /* - * Verify that s is a multiple of 2 before accepting it. This will - * allow all packets and their fields to be 16-bit aligned. - */ - if (((uint16_t)s & 1) != 0) { - syslog(LOG_NOTICE, "Uneven packet from %d", q->fd); - return -1; - } - - *buf = (int16_t *)&q->buffer[q->tail]; - *size = s; - q->tail += s; - - return 0; -} - -/* - * Useful to discard ping packets which we process on the fly - */ -void -recvq_rewind(recvq_t *q, size_t size) -{ - - if (q->tail >= size) - q->tail -= size; -} - -void -recvq_content(recvq_t *q, uint8_t **buf, size_t *size) -{ - - *buf = (uint8_t *)q->buffer; - *size = q->tail; - q->tail = 0; -} diff --git a/tests/kqueue/recvq.h b/tests/kqueue/recvq.h deleted file mode 100644 index 54e6eee..0000000 --- a/tests/kqueue/recvq.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: recvq.h,v 1.4 2006/04/03 20:37:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _RECVQ_H_ -#define _RECVQ_H_ - - - -#include - - - -typedef struct recvq { - int fd; - uint8_t *buffer; - size_t size, tail; -} recvq_t; - - - -int recvq_init(recvq_t *, int, size_t); -void recvq_destroy(recvq_t *); -int recvq_read(recvq_t *, int16_t **, size_t *); -void recvq_rewind(recvq_t *, size_t); -void recvq_content(recvq_t *, uint8_t **, size_t *); - - - -#endif diff --git a/tests/kqueue/sendq.c b/tests/kqueue/sendq.c deleted file mode 100644 index 7ea0052..0000000 --- a/tests/kqueue/sendq.c +++ /dev/null @@ -1,148 +0,0 @@ -/* $Id: sendq.c,v 1.5 2006/04/03 20:37:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "sendq.h" - - - -/* - * Initializes a sendq object, allocating the queue buffer - */ -int -sendq_init(sendq_t *q, int fd, size_t size) -{ - - if ((q->buffer = malloc(size)) == NULL) - return -1; - - q->fd = fd; - q->size = size; - q->head = q->tail = 0; - - return 0; -} - -/* - * Destroys a sendq object, freeing the queue buffer - */ -void -sendq_destroy(sendq_t *q) -{ - - free(q->buffer); -} - -/* - * Attempts to write to the non-blocking socket. In the case of a partial - * write, queue the remaining of the buffer. In case where the buffer is - * full, return an error (-1), in which case the sendq has been exceeded and - * client should be dropped. We only write(2) if there is no pending buffers - * already, of course. If bfunc is not NULL, it will be called with passed - * argument bfuncarg whenever data that couldn't be written immediately is - * buffered. If buffer is true, no attempt will be made at a real write; Data - * will simply be buffered if possible. - * - * XXX There is a potential problem where if the client is lagged enough to - * have filled the buffer, although not enough to exceed the queue but that - * the client cannot recoup, we could consider the queue filled and drop the - * client. This because we aren't really using a real FIFO buffer. This code - * should probably use the mmfifo(3) library after the multiple bytes buffer - * functions in it have been debugged and tested properly. - * However, since if the user was this behind this would in practice mean that - * his commands would take a while to be reflected, this is probably okay for - * the time being. - */ -int -sendq_write(sendq_t *q, uint8_t *buf, size_t size, - void (*bfunc)(void *), void *bfuncarg, int buffer) -{ - - /* Sendq empty? Attempt to write(2) immediately */ - if (!buffer && q->head == q->tail) { - ssize_t s; - - /* Only allow EAGAIN */ - if ((s = write(q->fd, buf, size)) == -1 && errno != EAGAIN) - return -1; - - /* - * If we wrote everything, simply return successfuly. - * Otherwise, fix our arguments to the unwritten buffer. - */ - if (s == size) - return 0; - else { - size -= s; - buf += s; - } - } - - /* - * If the sendq buffer wasn't empty, or that there remains bytes - * after a partial write(2), queue the buffer if there's enough room. - * If there isn't enough room, return error. If a function was - * supplied with an argument, also call this function if we buffer - * data. This may allow our caller to enable back write polling - * events for this descriptor. - */ - if (size > 0) { - if (q->tail + size > q->size) - return -1; - - (void) mm_memcpy(&q->buffer[q->tail], buf, size); - q->tail += size; - if (bfunc != NULL) - bfunc(bfuncarg); - } - - return 0; -} - -/* - * If any pending buffers exist, attempts to write them. In the case of an - * error, returns -1, in which case the client should be dropped. If there - * still remains unflushed data, 1 is returned. Otherwise, 0 is. - */ -int -sendq_flush(sendq_t *q, size_t room) -{ - - if (q->head != q->tail) { - ssize_t ns; - size_t os = q->tail - q->head; - - /* Only attempt write(2) syscall if there is room */ - if (room == 0) - return 1; - - if ((ns = write(q->fd, &q->buffer[q->head], os)) == -1) { - if (errno == EAGAIN) - return 1; - else - return -1; - } - - if ((q->head += ns) == q->tail) - q->head = q->tail = 0; - else - return 1; - } - - return 0; -} diff --git a/tests/kqueue/sendq.h b/tests/kqueue/sendq.h deleted file mode 100644 index 022543f..0000000 --- a/tests/kqueue/sendq.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id: sendq.h,v 1.5 2006/04/03 20:37:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef _SENDQ_H_ -#define _SENDQ_H_ - - - -#include - -#include - - - -typedef struct sendq { - int fd; - uint8_t *buffer; - size_t size, head, tail; -} sendq_t; - - - -int sendq_init(sendq_t *, int, size_t); -void sendq_destroy(sendq_t *); -int sendq_write(sendq_t *, uint8_t *, size_t, void (*)(void *), void *, - int); -int sendq_flush(sendq_t *, size_t); - - - -#endif diff --git a/tests/memory/README b/tests/memory/README deleted file mode 100644 index 52e022f..0000000 --- a/tests/memory/README +++ /dev/null @@ -1,42 +0,0 @@ -$Id: README,v 1.1 2005/11/14 01:55:20 mmondor Exp $ - -The goal of this project is to create new memory allocation functions -which can work on arbitrary pools of memory, while making sure to always -favor low, already used pages. - -For instance, let's consider the case where multiple processes need to -use a fair amount of shared memory. The master process can allocate a -region of memory using mmap(2) with MAP_ANON, making sure to use a large -enough block that'll ever be used by the application. This region can -be shared. - -UVM lazily allocates pages which need to be accessed on-the-fly. This -means that we must use a system similar to brk(2)/sbrk(2) and favor reusing -already allocated memory in order to avoid the application growing too much. -The process stack is for instance allocated this way; A single very large -region is mapped, and the actual memory in use increases with the process' -requirements for more stack space. In the case of stacks, since they are -indeed stacks, the growing problem is not critical and easily determined. - -In the case of a general purpose memory allocator, this is more complex. -mmpool(3) library allows to allocate fixed sized objects efficiently and -makes sure to favor recently used pages in the allocations, which is okay. -However, mmpool(3) must also be given allocation/freeing functions which -it must use to allocate more pages as needed, or to free pages which haven't -been used for some time. This is where the general purpose allocators -are used. - -In the case where a whole fixed large region can be used to allocate a single -type of objects, we can simply use mmpool(3) and let it manage the large -memory page. However, needing to allocate a new memory segment per memory -pool or object type appears problematic in some situations. Moreover, being -able to use a single large region for shared memory, another one for -process-specific or shared mlocked memory per application, makes things -easier. It also allows server administrators to more easily modify various -parameters relating to application scalibility. - -So this general purpose memory allocator should work on arbitrary regions -of memory, and should automatically perform any necessary locking for -synchronization. This is quite similar to the libmm library in use by the -Apache server. This however should be released under BSD license, and -especially favor reusing of previously allocated pages. diff --git a/tests/pthread/README b/tests/pthread/README deleted file mode 100644 index 3e70865..0000000 --- a/tests/pthread/README +++ /dev/null @@ -1,113 +0,0 @@ -$Id: README,v 1.2 2007/03/04 08:32:31 mmondor Exp $ - vim:tw=66:ai: - -Copyright (c) 2007, Matthew Mondor -ALL RIGHTS RESERVED. - - -The status of POSIX threads on the NetBSD operating system -========================================================== - -For a long while (until 2.0 release) NetBSD had no native POSIX -threading interface. It had support for kernel threads and -processes only, and required external user 1:N thread library -packages to support the pthread interface (using sigaltstack(2) or -equivalent and a polling scheduler around select(2) or equivalent, -nor providing pre-emptive threads). This means that special care -had to be taken by the programmer not to starve other threads -performing number crunching without yielding explicitely, or block -the whole process by using unwrapped blocking syscalls. -Unproven-threads, and GNU Pth could be used, which would provide -non-blocking wrappers around the blocking I/O syscalls. - -Starting from 2.0, NetBSD shipped with a native M:N POSIX threads -implementation using Scheduler Activations. This implementation, -still used in a more mature form in NetBSD 4.x, works with an -impressive performance on uniprocessor systems. It also conforms -very well to the standard on various tricky aspects on which -LinuxThreads failed to comply (one of the reasons LPTL replaced -them on Linux). However, the multiprocessor support or adjustable -PTHREAD_CONCURRENCY still has stability issues on v4. - -That M:N model relied on a userland library making use of -Scheduler Activations in order to only spawn as many Light Weight -Processes (actual real kernel supported threads in the same -process) as required, such that non-blocking I/O operations and -such done by many threads may be done more efficiently with fewer -CPU/kernel context switches. - -On NetBSD -current (4.99.x), it was considered that the Scheduler -Activations system on which the previous M:N model was implemented -had scalibility issues as well as major problems to adapt to -multi-processor systems. Since the SA author and other developers -did not put efforts into re-writing or major rehauling SA, the -threading model was changed to a 1:1 model. - -This occurred as major work was being done on better locking (in -an effort to eliminate the big lock). To prevent M:N from hindering -SMP enhancements a migration was made from M:N to a 1:1 model, -that-is, one LWP per thread such as is the case for Linux, Solaris -(which used to support an M:N model but dropped it at some point, -apparently because of complexity issues), and other BSDs. - - -M:N could scale in all situations -================================= - -Although the current 1:1 model is all good for SMP, the performance -on uniprocessors was still unprecendented by the M:N model. -Moreover, if SA was re-written, or that another M:N threading model -was developped, it could still benefit both uniprocessor and -multiprocessor ones while scaling potentially even better than 1:1 -with SMP. - -Therefore while thinking about the problem here and then and -through various tests, notes will be taken here on various ideas -through which a new M:N model could be developped. If I am -eventually able to dedicate enough time and resources, an -alternative pthread library might be written here as well, which -could potentially be submitted for testing and review to NetBSD -developers for eventual inclusion in v5 or v6 release. - - -Various challenges and ideas -============================ - -- A kqueue userland thread scheduler could be written, although it - would probably need some support similar to AIO for disk I/O - operations which could be blocking. - -- A function can be called by libc prior to main() call to setup - the threading library. However, a non-threading process is - considered to be a process with one single thread but which must - behave like traditionally. - Perhaps that the thread scheduler could be launched when the - first pthread_init() call is made. The main LWP could become - the thread scheduler LWP. - -- Special minimal kernel support might be necessary for the - scheduler to detect efficiently when to spawn a new LWP in its - queue. - -- The scheduler should be able to automatically permanently bind - to a LWP a number-crunching thread which requires pre-emptive - yielding. - It is possible that we simply need to delegate to another LWP - any pre-empted operation done in the first LWP (which is also - the userland scheduler). - -- Actually, as long as pthread_create() was at least called once, - as soon as a all LWPs are preempted or blocked, a new LWP must - become available... - -- If the main LWP scheduler could perform all operations in a - non-blocking manner, only threads requireing pre-emption would - need to be mapped to a new LWP especially created for them... - However there may also be non-I/O blocking system and libc - calls. - -- The current LWP system doesn't have provision for asynchroneous - _lwp_wait() which would be needed for M:N pthread_join() - implementation. - -- It would also be nice to have configurable per-LWP CPU afinity. diff --git a/tests/pthread_utils/GNUmakefile b/tests/pthread_utils/GNUmakefile deleted file mode 100644 index dd75e9c..0000000 --- a/tests/pthread_utils/GNUmakefile +++ /dev/null @@ -1,35 +0,0 @@ -# $Id: GNUmakefile,v 1.5 2005/11/22 09:24:42 mmondor Exp $ - -MMLIB_PATH := ../../mmlib -MMLIBS := $(addprefix ${MMLIB_PATH}/,mmlog.o mmpool.o mmstring.o) -OBJS := mm_pthread_msg.o mm_pthread_sleep.o mm_pthread_pool.o mm_pthread_poll.o -BINS := tests/msg_test tests/poll_test - -CFLAGS += -Wall -#CFLAGS += -DDEBUG -DPTHREAD_DEBUG -g3 - -LDFLAGS += -lc -lpthread -#LDFLAGS += -lpthread_dbg - - -all: $(BINS) - - -%.o: %.c - cc -c ${CFLAGS} -I. -I$(MMLIB_PATH) -o $@ $< - - -tests/msg_test: tests/msg_test.o $(MMLIBS) $(OBJS) - cc ${CFLAGS} -o $@ $@.c $(OBJS) -I. -I$(MMLIB_PATH) ${LDFLAGS} \ - $(MMLIBS) - -tests/poll_test: tests/poll_test.o $(MMLIBS) $(OBJS) - cc ${CFLAGS} -o $@ $@.c $(OBJS) -I. -I$(MMLIB_PATH) ${LDFLAGS} \ - $(MMLIBS) - - -install: all - - -clean: - rm -f tests/msg_test.o tests/poll_test.o $(BINS) $(OBJS) $(MMLIBS) diff --git a/tests/pthread_utils/README b/tests/pthread_utils/README deleted file mode 100644 index 8054ac7..0000000 --- a/tests/pthread_utils/README +++ /dev/null @@ -1,197 +0,0 @@ -This library is an attempt to provide pth library like API to NetBSD SA -threads and kqueue. - -What we find are missing from the POSIX standard are added here: - -- Implementation of efficient messages to communicate among threads. These - messages are queued using an efficient pointer linking mechanism. It must be - possible for a thread to wait for messages while sleeping and to be awaken - when a message is available. It also must be possible to observe a maximum - timeout to wait for. -- Implementation of filedescriptors and above mentionned thread messages - notification multiplexing, with support for timer. An example of this is - pth library's pth_poll_ev(). A timer event can interrupt thread-safe - filedescriptor polling, as well as thread messages arriving on a port. - -We beleive that it is possible to implement this using the kqueue(2)/kevent(2) -system. The new call would be similar to: - -pthread_poll(struct pollfd *fds, int nfds, - struct pthread_port *ports, int nports, - struct pthread_sigs *sigs, int nsigs, - struct pthread_timers *timers, int ntimers) - -or similar system. This would allow multiplexing of various events into a -single application loop. - - -pthread_cond_timedwait() seems especially useful, either with a signal handler -or perhaps using kqueue concurrently... pthread_cond_timedwait() will allow -processes to wait for message arrival though a port, while -pthread_cond_signal() or pthread_cond_broadcast() will be able to awaken them -as messages are queued to the message port. However, we would ideally want to -only signal a wanted thread waiting for a port... But, normally only one -thread should be listening for messages on any given port. I have to see what -I'll do for a thread listening for messages on multiple ports at a time... -Perhaps that multiple ports could use the same conditional wait variable so -that the process would only wait on that one, and then verify the message -queue for each before going back in waiting mode. - - -TODO: -==== -- Replace mutex and conditonal variable initializers, as well as attributes, - with static initializers. -- Provide similar static intializer macros as part of our API where possible. -- I have a working message passing implementation, with possibility of a - waiter on as many ports as wanted. I however still have a challenge: - Multiplex system calls such as select(2), poll(2), connect(2) and accept(2) - with the messaging capability. One must be able to cause the other to - return. This could be tricky to properly implement. Maybe think about the - following ideas: - - Dedicate a thread to serve a syscall, with which communication is solely - done using messages. This however implies that only a single syscall at a - time can be processed by such a thread. This probably means that a pool of - such threads would become necessary. This also assumes that the syscall in - question do not block the whole process, but only the intended thread. - Alot of assumptions, but this would now work properly on all BSDs and - on Linux. Possibly also on Solaris. - - Use a mix of signals and syscalls, since signals can interrupt syscalls. - However, this implies adding capability in our message system to trigger - signals rather than only using a conditional variable to notify of message - arrival. This also probably means that the same signal handler must be - shared by the whole process, that is, all the threads. - - Use kqueue in a thread-safe manner with thread-specific signals (if - possible). kqueue can be used to track signals without the need for an - actual signal handler. It would also track filedescriptor changes at the - same time. This also probably means that we need to use kqueue user - events if possible, triggered from the message passing system. It also - means non-portable code outside of the realm of BSD systems. - - - -RECENT REVIEW AFTER SOME REFLECTION -=================================== - -Currently, pth_accept_ev() and pth_connect_ev() are the only two cases of -special PTh functions which my software uses, notably mmftpd(8). These could -easily be implemented using a random thread in the pool whenever necessary, -with which communication would entirely use messages only. This thread could -be told: Perform syscall in non-blocking mode using the supplied -filedescriptor and notify me weither it succeeded, failed because of a timeout, -if any, or was interrupted by a message event occuring on the specified ring, -if any. The application however has to know that if it was interrupted by -an event, the connection still occurs asynchroneously within the system. -We should verify what could be done to cancel a not yet completed connection, -if possible. This call could also report if the call was interrupted by a -signal arrival (EINTR), optionally. If the socket was supplied in blocking -mode, it would have to be switched to non-blocking mode by the system and -then back into blocking mode. The caller could ensure to set it into -non-blocking mode for enhanced performance if no blocking mode is required. -The challenge would be finding a both efficient and portable solution to -have select()/poll() awake upon reception of notification events on a ring. -Perhaps that a global filedescriptor could be used for this, SOCK_DGRAM and -one byte sent, or that a signal handler with a signal generation should be -used... Both methods would probably awake the whole process, however. -pthread_sigmask() could be used perhaps... I wouldn't want to have a special -fd required for each ready thread of the pool, ideally. - -Implement: -mm_pthread_io pthread_poll_ev(), pthread_accept_ev(), - pthread_connect_ev() -mm_pthread_alarm pthread_sleep(), etc. - -or maybe: - -mm_pthread_misc For all of them - -Perhaps reimplement the system I worked on in mmserver(3) as well. This might -be necessary for operations which really should be dedicated to a non-threaded -process at occasions, and the subsystem should be available. It should probably -use a pool using mmpool(3) as well, just like we are doing with threads. - -It would be interesting to implement better GC for mmpool(3)'s. Currently, -pool_free() will discard pages which are no longer in use since some time, -but the time cannot be linear, since it only accounts a certain number of -calls made to it. It should instead be possible to use time intervals, and -to let the application invoke the GC at wanted fixed intervals. This would -allow to use time based average statistics rather than function call times -based ones, without clobbering process or thread timers which the application -might need. It simply has to provide its own and to call the GC function -regularily. - -Hmm also, would be nice to be able to store the port_t pointer of the port -which triggered notification on a ring_t, so that callers don't need to -run through several ports attached on a ring... Maybe that it would be -problematic however, since we can't guarantee atomicity between messages and -messages processing, unless we kludged the whole thing with locks and lost -efficiency. And because we only trigger notification to wakeup a waiting -thread when a message is queued on an empty port, it's possible that the -applicaton sleeps forever on a port if it didn't totally empty it, unless -there was a way for the sleep function to immediately return if called on -non-empty ports (as it's only alled on rings, and that rings don't have -access to a list of ports in current implementation (only the ports can -know which ring they are tied to)... I could implement something to have -rings see their attached ports with a list, however. But this again means -looping among ports to see if they're non-empty, heh, so why not let the -application do it as they do now. - - - -IMPORTANT -========= - -I did a test where multiple threads were polling on a single filedescriptor -consisting of a socketpair, which other side was used to wake them up. -Only one random thread would wake up. - -Using a signal to cause all threads to wake would not work either, because -then again only a random thread will awake. - -It appears that the only way to ensure to wake wanted threads is using -conditional variables and for them to only sleep on these. - -SIGIO possibility... threads would be sleeping on a conditional wait variable -corresponding to the filedescriptor. For polling, the fd would be made in -non-blocking I/O, with SIGIO sent to process. The fd and associated cond var -would be added to a table. The SIGIO signal handler would need to check all -fds in the set for possible I/O and awake corresponding threads waiting on -cond var. A problem exists: How to check a filedescriptor for pending event? -How to know if event is read or write, or hup, etc? Maybe using more ore less -standard FION ioctls? poll/select with 0 timeout maybe, but that is still -troublesome in terms of performance I beleive. - -fd cond interesting_events occured_events? - -Hmm and what if a thread was allocated to start polling, and another wrapper -thread wait for it sleeping on a cond var? Would it be sane to do this? -When a timeout or message occurs however detected by the wrapper thread, -how would we stop the other thread polling? We still have a problem. -If we left pending polling threads, how would a future thread with successful -polling on the same descriptor ever wake up, a random one would. -Why does POSIX threads suck so much as to not provide any decent way to -work with filedescriptors!? If at least I had pthread_signal() it would -help. I could send a signal to interrupt the wanted thread when it was polling. -Or if only there was a way to set the wanted signal mask for wanted processes -as necessary, so that I would only have the wanted one process a particular -signal I could send to interrupt it and then restore the masks, and do this -somehow atomically. If POSIX had any of these requirements in mind while -developing the standard, pthread_poll_condwait() or pthread_signal() would -already exist anyways! - - -HMM -=== - -A thread reserved for polling would seem best. We need to be able to interrupt -that thread whenever needed using a signal, which all other processes must -be blocking. We could use SIGIO, or SIGUSR2 for instance. That thread would -process thread messages and go back to polling. It probably could handle -timeouts as well, but this is probably not necessary. If it did, would -probably free other threads from calling gettimeofday() too often. The thread -has to remove the fd from the polling list when an event returned on it -anyways, and so it could also send a reply message for timeout. It has to -be interrupted anyways when a new fd is to be added, and this means that -it could fix the poll timer before calling it each time to fit the soonest -to expire fd... I could probably use kqueue too, or libevent in that thread -to make it high performance as possible. diff --git a/tests/pthread_utils/mm_pthread_debug.h b/tests/pthread_utils/mm_pthread_debug.h deleted file mode 100644 index 2db67bc..0000000 --- a/tests/pthread_utils/mm_pthread_debug.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id: mm_pthread_debug.h,v 1.2 2006/02/05 13:00:48 mmondor Exp $ */ - -/* - * Copyright (C) 2004-2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef MM_PTHREAD_DEBUG_H -#define MM_PTHREAD_DEBUG_H - - - -#include -#include - - - -#ifdef PTHREAD_DEBUG - -#define DEBUG_PTHREAD_ENTRY() \ - syslog(LOG_NOTICE, "> TID=%p FN=%s", pthread_self(), __func__) - -#define DEBUG_PTHREAD_EXIT() \ - syslog(LOG_NOTICE, "< TID=%p FN=%s", pthread_self(), __func__) - -#else -#define DEBUG_PTHREAD_ENTRY() -#define DEBUG_PTHREAD_EXIT() -#endif - - - -#endif diff --git a/tests/pthread_utils/mm_pthread_msg.c b/tests/pthread_utils/mm_pthread_msg.c deleted file mode 100644 index d1fc7f0..0000000 --- a/tests/pthread_utils/mm_pthread_msg.c +++ /dev/null @@ -1,466 +0,0 @@ -/* $Id: mm_pthread_msg.c,v 1.14 2006/02/05 13:00:48 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * It is almost a shame that POSIX did not define a standard API for - * inter-thread asynchroneous and synchroneous messaging. So, here is my - * implementation. Note that for asynchroneous operation it is recommended to - * use a memory pool such as mmpool(3) to allocate and free messages in an - * efficient way, in cases where messages will need to be sent to the other - * end without expecting a response back before the current function ends - * (in which case a message obviously can't be on the stack). - */ - - - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -/*#include */ - - - -MMCOPYRIGHT("@(#) Copyright (c) 2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: mm_pthread_msg.c,v 1.14 2006/02/05 13:00:48 mmondor Exp $"); - - - -/* - * Allows to initialize a polling notification handle. When attached to a - * port, a message arriving on an empty port causes the associated ring to - * wake the thread from pthread_ring_wait(). - */ -int -pthread_ring_init(pthread_ring_t *ring) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(ring != NULL && ring->magic != PRING_MAGIC); - - if ((error = pthread_cond_init(&ring->cond, NULL)) == 0) { - if ((error = pthread_mutex_init(&ring->mutex, NULL)) == 0) { - ring->magic = PRING_MAGIC; - ring->event = ring->mevent = 0; - DEBUG_PTHREAD_EXIT(); - return 0; - } - (void) pthread_cond_destroy(&ring->cond); - } - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Returns TRUE if the supplied ring is a valid/usable one, or FALSE - * otherwise. Useful to conditionally destroy it. - */ -int -pthread_ring_valid(pthread_ring_t *ring) -{ - - DEBUG_PTHREAD_ENTRY(); - - DEBUG_PTHREAD_EXIT(); - return (ring != NULL && ring->magic == PRING_MAGIC); -} - -/* - * Destroys a ring. Note that all message ports attached to this ring should - * first be detached or destroyed. - */ -int -pthread_ring_destroy(pthread_ring_t *ring) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - if ((error = pthread_mutex_destroy(&ring->mutex)) == 0) - error = pthread_cond_destroy(&ring->cond); - ring->magic = 0; - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Causes the current thread to sleep until a message arrives on an empty port - * associated with this ring. In normal operation, a thread only goes in wait - * mode after it processed all queued messages on all interesting ports. - * However, provision is made so that a the function returns immediately if - * messages already were received on a port attached to this ring since the - * last call to pthread_ring_wait(). - * Although using such an absolute time timespec might be disadvantageous for - * the API compared to a timeout in milliseconds for instance, this was chosen - * to remain API-compatible with pthread_cond_timedwait(), and upwards - * compatible with systems where nanosecond precision can be achieved. - */ -int -pthread_ring_wait(pthread_ring_t *ring, const struct timespec *abstime) -{ - int error = 0; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - /* We must hold the condition variable's mutex */ - if (pthread_mutex_lock(&ring->mutex) != 0) { - error = -1; - goto err; - } - - /* As long as we don't have confirmation that we must stop waiting */ - for (ring->event = 0; ring->mevent == 0 && - !ring->event && error == 0; ) { - /* - * Wait on conditional variable, which will automatically - * and atomically release the mutex and return with the mutex - * locked again, as soon as the conditional variable gets - * signaled. - */ - if (abstime != NULL) { - error = pthread_cond_timedwait(&ring->cond, - &ring->mutex, abstime); - } else - error = pthread_cond_wait(&ring->cond, &ring->mutex); - } - ring->mevent = 0; - - /* - * And we know that conditional waiting functions returned with mutex - * locked, so now release it back. - */ - (void) pthread_mutex_unlock(&ring->mutex); - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Allows to wake up waiter(s) on the specified ring, which are sleeping - * threads within pthread_ring_wait(). This can be used to simulate the - * arrival of a message on an empty port. Also useful to use rings as a - * notification system only when no message passing is needed. - */ -int -pthread_ring_notify(pthread_ring_t *ring) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - if ((error = pthread_mutex_lock(&ring->mutex)) == 0) { - ring->mevent++; - ring->event = 1; - (void) pthread_cond_signal(&ring->cond); - (void) pthread_mutex_unlock(&ring->mutex); - } - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Allows to initialize/create a message port. - */ -int -pthread_port_init(pthread_port_t *port) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic != PPORT_MAGIC); - - if ((error = pthread_mutex_init(&port->lock, NULL)) != 0) - goto err; - - port->magic = PPORT_MAGIC; - port->ring = NULL; - DLIST_INIT(&port->messages); - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Returns TRUE if the supplied port is valid/usable, or FALSE otherwise. - * Useful to conditionally destroy a port, for instance. - */ -int -pthread_port_valid(pthread_port_t *port) -{ - - DEBUG_PTHREAD_ENTRY(); - - DEBUG_PTHREAD_EXIT(); - return (port != NULL && port->magic == PPORT_MAGIC); -} - -/* - * Destroys the specified port, previously created using pthread_port_init(). - */ -int -pthread_port_destroy(pthread_port_t *port) -{ - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - port->magic = 0; - - DEBUG_PTHREAD_EXIT(); - return pthread_mutex_destroy(&port->lock); -} - -/* - * Attaches a port to a ring. Multiple ports may be attached to a ring. A - * message arriving on an empty port will cause the attached ring to be - * notified, if any, and as such to cause a thread waiting on the ring to - * be awakened. - */ -int -pthread_port_set_ring(pthread_port_t *port, pthread_ring_t *ring) -{ - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic == PPORT_MAGIC && - (ring == NULL || ring->magic == PRING_MAGIC)); - - port->ring = ring; - - DEBUG_PTHREAD_EXIT(); - return 0; -} - -/* - * Allows to initialize a message before it can be sent over a port. The - * message only needs to be initialized once in general, even if it will be - * used for bidirectional transmission for synchronous operation. If the - * reply port needs to be changed, however, this function should be used again - * to set the new reply port. - */ -int -pthread_msg_init(pthread_msg_t *msg, pthread_port_t *rport) -{ - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(msg != NULL && msg->magic != PMESG_MAGIC && - (rport == NULL || rport->magic == PPORT_MAGIC)); - - msg->magic = PMESG_MAGIC; - msg->reply = rport; - msg->size = 0; - msg->message = NULL; - - DEBUG_PTHREAD_EXIT(); - return 0; -} - -/* - * Returns TRUE if supplied message is valid/usable or FALSE otherwise. - */ -int -pthread_msg_valid(pthread_msg_t *msg) -{ - - DEBUG_PTHREAD_ENTRY(); - - DEBUG_PTHREAD_EXIT(); - return (msg != NULL && msg->magic == PMESG_MAGIC); -} - -/* - * Invalidates a message, so that it can no longer be sent over ports. - */ -int -pthread_msg_destroy(pthread_msg_t *msg) -{ - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(msg != NULL && msg->magic == PMESG_MAGIC); - - msg->magic = 0; - - DEBUG_PTHREAD_EXIT(); - return 0; -} - -/* - * If any message exists in the queue of the specified port, unqueues it and - * returns it. Otherwise, NULL is returned. In normal operation, all messages - * queued to a port are processed before putting the thread back into sleep, - * mainly for efficiency, but also because it eases synchronization. - */ -pthread_msg_t * -pthread_msg_get(pthread_port_t *port) -{ - pthread_msg_t *msg = NULL; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - if (pthread_mutex_lock(&port->lock) != 0) - goto err; - - if ((msg = DLIST_TOP(&port->messages)) != NULL) { - DEBUG_ASSERT(msg->magic == PMESG_MAGIC); - DLIST_UNLINK(&port->messages, (node_t *)msg); - } - - (void) pthread_mutex_unlock(&port->lock); - -err: - DEBUG_PTHREAD_EXIT(); - return (pthread_msg_t *)msg; -} - -/* - * Queues the specified message to the specified port, returning 0 on success. - * Note that the message data is not copied or moved, but that a pointer - * system is used to queue the message. Thus, the message's shared memory - * region is leased temporarily to the other end. One has to be careful to - * not allocate this message space on the stack when asynchroneous operation - * is needed. In synchroneous operation mode, it is not a problem, since the - * sender does not have to modify the data until the other end replies back - * with the same message after modifying the message if necessary. In - * synchroneous mode, we simply delegate that message memory region to the - * other end until it notifies us with a reply that it is done working with - * it. Returns 0 on success, or an error number. - */ -int -pthread_msg_put(pthread_port_t *port, pthread_msg_t *msg) -{ - int error = 0; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic == PPORT_MAGIC && - msg != NULL && msg->magic == PMESG_MAGIC); - - if ((error = pthread_mutex_lock(&port->lock)) != 0) - goto err; - - DLIST_APPEND(&port->messages, (node_t *)msg); - if (port->ring != NULL) { - if (DLIST_NODES(&port->messages) == 1) { - /* - * We know that there previously were no messages, - * and that the reading thread then waits for any - * message to be available. Signal it that there at - * least is one message ready. The other end should - * normally process all available messages before - * going back into waiting. - */ - if ((error = pthread_mutex_lock(&port->ring->mutex)) - == 0) { - port->ring->event = 1; - (void) pthread_cond_signal(&port->ring->cond); - (void) pthread_mutex_unlock( - &port->ring->mutex); - } - } - /* - * If the other end, however, is already locked - * waiting for the ring to be notified while - * there already are messages, we still trigger mevent - * to cause it to unlock, however. This behavior is - * useful in the polling system code, for instance. - */ - /* XXX We don't use a mutex for now... */ - port->ring->mevent++; - } - - (void) pthread_mutex_unlock(&port->lock); - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Meant to be used in synchroneous message transfer mode. The initial sender - * sends a message to the other end, which then uses this function to notify - * back the initial sender that it is done, often with a success/failure - * result as part of the message. Returns 0 on success, or an error number. - */ -int -pthread_msg_reply(pthread_msg_t *msg) -{ - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(msg != NULL && msg->magic == PMESG_MAGIC && - msg->reply != NULL); - - DEBUG_PTHREAD_EXIT(); - return pthread_msg_put(msg->reply, msg); -} - -/* - * Returns the number of pending messages tied to the port, if any, or -1 - * on error. - */ -int -pthread_port_pending(pthread_port_t *port) -{ - int pending = -1; - - DEBUG_PTHREAD_ENTRY(); - DEBUG_ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - if (pthread_mutex_lock(&port->lock) != 0) - goto err; - - pending = (int)DLIST_NODES(&port->messages); - - (void) pthread_mutex_unlock(&port->lock); - -err: - DEBUG_PTHREAD_EXIT(); - return pending; -} diff --git a/tests/pthread_utils/mm_pthread_msg.h b/tests/pthread_utils/mm_pthread_msg.h deleted file mode 100644 index 287bc2e..0000000 --- a/tests/pthread_utils/mm_pthread_msg.h +++ /dev/null @@ -1,110 +0,0 @@ -/* $Id: mm_pthread_msg.h,v 1.3 2005/09/15 11:46:58 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef MM_PTHREAD_MSG_H -#define MM_PTHREAD_MSG_H - - - -#include - -#include -#include - - - -#define PRING_MAGIC 0x50524e47 -#define PPORT_MAGIC 0x50505254 -#define PMESG_MAGIC 0x504d5347 - -typedef struct { - u_int32_t magic; - pthread_cond_t cond; - pthread_mutex_t mutex; - int mode; - int event; - int mevent; -} pthread_ring_t; - -enum pthread_ring_modes { - PTHREAD_RMOD_NOWAIT, - PTHREAD_RMOD_CONDWAIT, - PTHREAD_RMOD_FDWAIT -}; - -typedef struct { - u_int32_t magic; - pthread_ring_t *ring; - pthread_mutex_t lock; - list_t messages; -} pthread_port_t; - -typedef struct { - node_t node; - u_int32_t magic; - pthread_port_t *reply; - size_t size; - void *message; -} pthread_msg_t; - - - -extern int pthread_ring_init(pthread_ring_t *); -extern int pthread_ring_valid(pthread_ring_t *); -extern int pthread_ring_destroy(pthread_ring_t *); -extern int pthread_ring_wait(pthread_ring_t *, - const struct timespec *); -extern int pthread_ring_notify(pthread_ring_t *); - -extern int pthread_port_init(pthread_port_t *); -extern int pthread_port_valid(pthread_port_t *); -extern int pthread_port_destroy(pthread_port_t *); -extern int pthread_port_set_ring(pthread_port_t *, - pthread_ring_t *); -extern int pthread_msg_init(pthread_msg_t *, - pthread_port_t *); -extern int pthread_msg_valid(pthread_msg_t *); -extern int pthread_msg_destroy(pthread_msg_t *); -extern pthread_msg_t *pthread_msg_get(pthread_port_t *); -extern int pthread_msg_put(pthread_port_t *, - pthread_msg_t *); -extern int pthread_msg_reply(pthread_msg_t *); -extern int pthread_port_pending(pthread_port_t *); - - - -#endif diff --git a/tests/pthread_utils/mm_pthread_poll.c b/tests/pthread_utils/mm_pthread_poll.c deleted file mode 100644 index 36508b4..0000000 --- a/tests/pthread_utils/mm_pthread_poll.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* $Id: mm_pthread_poll.c,v 1.15 2006/02/05 13:00:48 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * I consider this code to be a major hack around the inherent problems unix - * systems face because of the lack of support for filedescriptor polling in - * the POSIX threads API. Although pthread defines methods for thread - * synchronization and polling waiting for events (using conditionnal - * variables), and that unix provides polling on filedescriptors using - * select(2), poll(2), kqueue(2) and other mechanisms, both are totally - * distinct entities which can be considered to either conflict with - * eachother or to not be related enough in a unified way. The current - * situation makes it almost impossible for a thread to both be polling for - * interthread efficient messages implementations built upon pthread, and - * filedescriptor events, concurrently. - * - * The GNU PTH library implements non-standard functions which allow to - * multiplex interthread messages and filedescriptor events, using for - * instance pth_poll_ev(), pth_select_ev(), pth_accept_ev(), pth_connect_ev(), - * etc. However, this is internally implemented using a single large select(2) - * based loop along with a slow large loop looking for non-fd events based on - * the principles of libevent. This threading library has other disadventages, - * such as not providing a preemptive scheduler (being a fully userspace - * implementation) and not allowing to scale to multiple processors on SMP - * systems. This interface however shows how good the POSIX threads API could - * have been, if it was better designed with unix systems in mind. This - * library also being the most portable threads library alternative for quite - * some time, because of the fact that Operating Systems implemented POSIX - * threads inconsistently, or not at all, caused us to use PTH during some - * time to develop software in cases where a pool of processes was not ideal - * because of the frequency of shared memory synchronization needs. - * - * With the advent of POSIX threads implementations on more unix and unix-like - * systems and of modern implementations behaving more consistently, which can - * scale on SMP systems and provide preemptive scheduling, it was considered - * worthwhile for us to adapt our software again to use the standard POSIX - * API. Especially considering that NetBSD which had no OS provided threads - * implementation for applications now has an awesome pthreads implementation - * starting with version 2.0. However, we encountered difficulties with some - * software which used the complex multiplexing of thread events and - * filedescriptor ones. This module provides a solution to port this software. - * It however is somewhat a hack. - * - * The downsides of this implementation are as follows. We originally intended - * to develop a system which would scale among an increasing number of threads - * in a ready pool of threads, scaling with concurrency of the polling calls. - * This however proved difficult, or impossible to achieve, the main reasons - * being that 1) A signal delivered to a process is only received by a random - * thread that is not blocking it. 2) In the case where multiple threads are - * polling on a common file descriptor, similarily only one random thread - * is awaken. 3) pthread_cond_signal() and pthread_cond_broadcast() cannot - * wake threads waiting in filedescriptor polling. 4) to achieve what we - * needed, two descriptors would have been necessary per notification ring. - * this was considered an aweful solution and was promptly rejected. 5) The - * POSIX API does not define a way for a process to set or change the signal - * blocking masks of other threads on the fly. - * - * Our solution then had to rely on a main descriptor polling manager thread - * which would be used to poll file descriptors, and would as a device serve - * client threads via efficient interthread messages. An issue still arises - * when a client thread sends a message to the polling thread to add new - * descriptors for polling or to cancel polling and remove descriptors. - * The polling thread must be able to immediately process these events - * awaking from filedescriptor polling. Two possible hacks could be used for - * this. 1) Use an AF_LOCAL SOCK_DGRAM socketpair(), which one side would - * be used to trigger an event writing some data, and the other side always - * included by the polling thread within the set of descriptors. 2) Send a - * signal to the process which only the polling thread is not blocking, - * to ensure that it be the one catching it, as such to awake from polling - * with an EINTR error code. This second solution was considered more elegant - * and is used as the basis of this implementation. We currently are - * clubbering the SIGUSR2 signal to achieve this. - */ - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - - - -MMCOPYRIGHT("@(#) Copyright (c) 2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: mm_pthread_poll.c,v 1.15 2006/02/05 13:00:48 mmondor Exp $"); - - - -/* - * Synchroneous communications message between arbitrary threads and the - * polling thread. Since communication is synchroneous, we only need to - * allocate one such message per thread. We are always expecting a reply - * back after sending a query before reusing the buffer. In fact, the - * message passing system only serves as a means for synchronization around - * the message, which is a shared memory object. - */ -struct poll_msg { - pthread_msg_t msgnode; - /* Passed as parameters */ - bool cancel; - struct pollfd *fds; - nfds_t nfds; - int timeout; - /* Returned as result */ - int ready, error; - /* Internally used */ - struct timeval expires; -}; - -/* - * An index is maintained of descriptor number -> poll_msg_index - * structures. Each of wich has information on the message the descriptor - * belongs to, and the index into the pollfd array so that it be easy to - * efficiently do per-fd work. - */ -struct poll_idx { - int idx; - struct poll_msg *msg; -}; - -/* - * Thread specific needed resources to use our special polling - */ -struct poll_data { - pthread_port_t port; - struct poll_msg msg; -}; - - - -#define POLLWAKE() do { \ - pollingevents++; \ - if (polling != 0) \ - (void) kill(process_id, SIGUSR2); \ -} while (/* CONSTCOND */0) - - - -/* - * Static functions prototypes - */ -static int pthread_poll_proc_init(void); -static void pthread_poll_proc_init2(void); -static int pthread_poll_thread_init(struct poll_data **); -static void pthread_poll_thread_exit(void *); -static void *poll_thread(void *); -static int poll_thread_attach_fds(struct poll_msg *); -static void poll_thread_detach_fds(struct poll_msg *); -static void poll_thread_sighandler(int); - -/* - * Static process specific storage - */ -static bool pthread_poll_initialized = FALSE; -static pthread_once_t pthread_poll_proc_initialized = PTHREAD_ONCE_INIT; -static pthread_key_t pthread_poll_proc_key; -static pthread_ring_t pthread_poll_thread_started_ring; -static pthread_port_t pthread_poll_thread_port; -static pid_t process_id; -static int polling = 0; -static int pollingevents = 0; - -/* - * Static global poll_thread storage. No synhronization is necessary when - * using these, since only the polling thread does. - */ -static struct poll_idx *poll_idx; -static nfds_t poll_idx_size; -static struct pollfd *poll_fds; -static nfds_t poll_fds_size; -static nfds_t poll_nfds; - - - -/* - * Static internal functions - */ - -static int -pthread_poll_proc_init(void) -{ - int error; - struct sigaction act; - - DEBUG_PTHREAD_ENTRY(); - - if ((error = pthread_key_create(&pthread_poll_proc_key, - pthread_poll_thread_exit)) != 0) - goto err; - - act.sa_handler = poll_thread_sighandler; - act.sa_flags = 0; - (void) sigemptyset(&act.sa_mask); - (void) sigaddset(&act.sa_mask, SIGUSR2); - if (sigaction(SIGUSR2, &act, NULL) != 0) { - error = errno; - goto err; - } - - process_id = getpid(); - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -static void -pthread_poll_proc_init2(void) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - - if ((error = pthread_poll_proc_init()) != 0) { - (void) fprintf(stderr, "pthread_poll_proc_init() - %s\n", - strerror(error)); - DEBUG_PTHREAD_EXIT(); - exit(EXIT_FAILURE); - } - - DEBUG_PTHREAD_EXIT(); -} - -static int -pthread_poll_thread_init(struct poll_data **res) -{ - int error; - struct poll_data *data; - sigset_t set; - - DEBUG_PTHREAD_ENTRY(); - - (void) sigemptyset(&set); - (void) sigaddset(&set, SIGUSR2); - (void) pthread_sigmask(SIG_BLOCK, &set, NULL); - - if ((data = malloc(sizeof(struct poll_data))) == NULL) { - error = ENOMEM; - goto err; - } - - if ((error = pthread_port_init(&data->port)) != 0) - goto err; - if ((error = pthread_msg_init(&data->msg.msgnode, &data->port)) != 0) - goto err; - - if ((error = pthread_setspecific(pthread_poll_proc_key, data)) != 0) - goto err; - - *res = data; - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - if (data != NULL) { - (void) pthread_port_destroy(&data->port); - free(data); - } - - DEBUG_PTHREAD_EXIT(); - return error; -} - -static void -pthread_poll_thread_exit(void *specific) -{ - struct poll_data *data = (struct poll_data *)specific; - - DEBUG_PTHREAD_ENTRY(); - - (void) pthread_port_destroy(&data->port); - (void) pthread_msg_destroy(&data->msg.msgnode); - free(data); - - /* - * Some implementations need this - */ - (void) pthread_setspecific(pthread_poll_proc_key, NULL); - - DEBUG_PTHREAD_EXIT(); -} - - -/* - * Actual polling thread, with which we communicate using messages polling on - * pthread_port_t and pthread_ring_t. This is the only thread that should be - * catching SIGUSR2 signals (used to wake us up and reiterate our main loop. - * Note: Although less efficient than using kqueue(2) or libevent(3), after - * discussion with 3s4i we settled to using poll(2) for now, which minimizes - * OS dependencies as well as third party software dependencies. Because - * pthread_poll_ring(2) is only sparsely used by our software (migrating from - * using PTH library which provided pth_poll_ev()), and that we only provide - * it small pollfd arrays, this implementation was considered to meet our - * needs using poll(2). This also met the requirements for Tact group. - */ -/* ARGSUSED */ -static void * -poll_thread(void *args) -{ - sigset_t set; - pthread_ring_t ring; - list_t msg_list; - register int i; - - DEBUG_PTHREAD_ENTRY(); - - /* - * This initialization shouldn't fail. If it did, it would be nice to - * be able to simply panic eventually. XXX - */ - - /* - * Create set for SIGUSR2 which we'll unblock/block - */ - (void) sigemptyset(&set); - (void) sigaddset(&set, SIGUSR2); - - /* - * Allocate an initial buffer size for our pollfd array as well as for - * our descriptor based index. We'll double these buffers as - * necessary at runtime. - */ - poll_fds_size = 64; - poll_fds = malloc(sizeof(struct pollfd) * poll_fds_size); - poll_nfds = 0; - poll_idx_size = 64; - poll_idx = malloc(sizeof(struct poll_msg) * poll_idx_size); - for (i = 0; i < poll_idx_size; i++) - poll_idx[i].msg = NULL; - DLIST_INIT(&msg_list); - - /* - * Initialize message port and associated ring. The message port is - * module global, so that it be public to pthread_poll_ring(). - */ - (void) pthread_port_init(&pthread_poll_thread_port); - (void) pthread_ring_init(&ring); - (void) pthread_port_set_ring(&pthread_poll_thread_port, &ring); - - /* - * Notify parent that we're ready. - */ - (void) pthread_ring_notify(&pthread_poll_thread_started_ring); - - /* - * Main loop from which we never exit - */ - for (;;) { - register int n; - int timeout; - struct timeval tv, ttv; - struct poll_msg *msg, *nextmsg; - - /* - * Get time of day in a rather high resolution. We need to - * do this to be able to evaluate timeouts later on. We - * attempt to only require one time syscall per loop. - */ - (void) gettimeofday(&tv, NULL); - - pollingevents = 0; - - /* - * Process any messages. We need to add the descriptors if - * they aren't already added. Also store yet unsatisfied - * request messages into a list. - */ - while ((msg = (struct poll_msg *)pthread_msg_get( - &pthread_poll_thread_port)) != NULL) { - if (msg->cancel) { - /* - * Immediately satisfy request on demand - */ - msg->error = ECANCELED; - DLIST_UNLINK(&msg_list, (node_t *)msg); - poll_thread_detach_fds(msg); - (void) pthread_msg_reply(&msg->msgnode); - continue; - } - if (poll_thread_attach_fds(msg) == 0) { - msg->ready = msg->error = 0; - if (msg->timeout != -1) { - /* - * Convert millisecond timeout to an - * absolute time timeval - */ - msg->expires.tv_sec = tv.tv_sec; - msg->expires.tv_usec = tv.tv_usec; - ttv.tv_sec = msg->timeout / 1000; - ttv.tv_usec = (msg->timeout % 1000) - * 1000; - timeradd(&msg->expires, &ttv, - &msg->expires); - } - DLIST_APPEND(&msg_list, (node_t *)msg); - } else { - msg->ready = 0; - msg->error = EINVAL; - (void) pthread_msg_reply(&msg->msgnode); - } - } - - /* - * Process timeouts. For request messages which timed out, - * satisfy them immediately using ETIMEDOUT error. - * This also allows to evaluate which is the soonest to expire - * entry, which poll(2) will have to use as timeout. - */ - ttv.tv_sec = ttv.tv_usec = 99999; - for (msg = DLIST_TOP(&msg_list); msg != NULL; msg = nextmsg) { - nextmsg = DLIST_NEXT(msg); - - if (msg->timeout == -1) - continue; - if (timercmp(&msg->expires, &tv, <)) { - msg->error = ETIMEDOUT; - DLIST_UNLINK(&msg_list, (node_t *)msg); - poll_thread_detach_fds(msg); - (void) pthread_msg_reply(&msg->msgnode); - } else if (timercmp(&msg->expires, &ttv, <)) { - ttv.tv_sec = msg->expires.tv_sec; - ttv.tv_usec = msg->expires.tv_usec; - } - } - - /* - * If there are no registered descriptors to poll for, wait - * using the thread friendly ring until messages occur, and - * reiterate. - */ - if (poll_nfds == 0) { - (void) pthread_ring_wait(&ring, NULL); - continue; - } - - /* - * Perform polling. poll(2) for as much time as possible, - * although making sure to allow the soonest to expire query - * to stop polling. Next to expire entry time is in ttv and - * current time in tv. Calculate difference and convert to - * milliseconds. - */ - if (ttv.tv_sec == 99999 && ttv.tv_usec == 99999) - timeout = -1; - else { - timersub(&ttv, &tv, &ttv); - timeout = (ttv.tv_sec * 1000) + (ttv.tv_usec / 1000); - } - - /* - * Unblock the SIGUSR2 signal, which we should be the only - * thread to receive, all other threads blocking it. - * Only leave it unblocked for the duration of the poll(2) - * syscall. We cause our loop to reiterate in any case of - * error, EINTR or no file descriptor with pending event. - */ - (void) pthread_sigmask(SIG_UNBLOCK, &set, NULL); - polling++; - - n = 0; - if (pollingevents != 0) - goto unblock; - - n = poll(poll_fds, poll_nfds, timeout); - -unblock: - polling--; - (void) pthread_sigmask(SIG_BLOCK, &set, NULL); - if (pollingevents != 0 || n < 1) - continue; - - /* - * Verify which descriptors have interesting events set, - * increasing events counter of corresponding requests. - */ - for (i = 0; n != 0 && i < poll_nfds; i++) { - if (poll_fds[i].revents != 0) { - (poll_idx[poll_fds[i].fd].msg->ready)++; - n--; - } - } - /* - * Now verify pending request messages for events, and satisfy - * the requests of those who do. - */ - for (msg = DLIST_TOP(&msg_list); msg != NULL; msg = nextmsg) { - nextmsg = DLIST_NEXT(msg); - - if (msg->ready != 0) { - /* - * ready and error fields are already set - */ - DLIST_UNLINK(&msg_list, (node_t *)msg); - poll_thread_detach_fds(msg); - (void) pthread_msg_reply(&msg->msgnode); - } - } - } - - /* NOTREACHED */ - DEBUG_PTHREAD_EXIT(); - pthread_exit(NULL); - return NULL; -} - -/* - * Permits to merge supplied pollfd set with the main set - */ -static int -poll_thread_attach_fds(struct poll_msg *msg) -{ - register int i, fd, idx; - - DEBUG_PTHREAD_ENTRY(); - - for (i = 0; i < msg->nfds; i++) { - fd = msg->fds[i].fd; - - /* - * Ignore unset descriptors - */ - if (fd == -1) - continue; - - /* - * Grow index buffer if necessary. Either grow by doubling - * size, or even more if necessary to hold index to fd. - * If we only grew to hold fd, we might need to realloc(3) too - * often. Take care to also NULL msg field of new entries. - */ - if (poll_idx_size <= fd) { - struct poll_idx *idx; - int size, i2; - - size = poll_idx_size * 2; - if (fd > size) - size = fd; - if ((idx = realloc(poll_idx, - sizeof(struct poll_idx) * size)) == NULL) - goto err; - poll_idx = idx; - for (i2 = poll_idx_size; i2 < size; i2++) - poll_idx[i2].msg = NULL; - poll_idx_size = size; - } - - /* - * Error if descriptor not unique before adding to set. - * We do not allow multiple threads polling on the same - * descriptor at the same time in our system. We would - * otherwise need to gracefully handle duplicates, - * multiplexing them, which isn't required at all by our - * applications. So let's keep things simple. - */ - if (poll_idx[fd].msg != NULL) - goto err; - - /* - * Resize pollfd array if needed. Grow by doubling. - * This should happen very rarely. - * XXX We could check this condition only once at the - * top of this fonction and take in consideration the - * number of descriptors to add, if wanted for optimization. - */ - if (poll_fds_size <= poll_nfds) { - struct pollfd *ptr; - - if ((ptr = realloc(poll_fds, - sizeof(struct pollfd) * (poll_fds_size * 2))) - == NULL) - goto err; - poll_fds = ptr; - poll_fds_size *= 2; - } - - /* - * Finally add descriptor to set and register it for indexing. - * We simply need to append it to the existing entries in our - * global polling set array. - */ - idx = poll_nfds; - poll_fds[idx].fd = fd; - poll_fds[idx].events = msg->fds[i].events; - poll_fds[idx].revents = 0; - poll_idx[fd].msg = msg; - poll_idx[fd].idx = idx; - poll_nfds = ++idx; - } - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - (void) poll_thread_detach_fds(msg); - - DEBUG_PTHREAD_EXIT(); - return -1; -} - -/* - * Permits to disunite supplied pollfd set from the main set. Also sets the - * revents fields of the supplied set to the ones of the main set. - */ -static void -poll_thread_detach_fds(struct poll_msg *msg) -{ - register int i, fd, idx; - - DEBUG_PTHREAD_ENTRY(); - - for (i = 0; i < msg->nfds; i++) { - fd = msg->fds[i].fd; - - /* - * Make sure fd was properly registered - */ - if (poll_idx[fd].msg != msg) - continue; - - /* - * Find index in global pollfd set for this fd - */ - idx = poll_idx[fd].idx; - - /* - * Update pollfd entry according to global one - */ - msg->fds[i].revents = poll_fds[idx].revents; - - /* - * Unlink fd from the global set. The removal method is - * simple; Take the last entry of the global set and move it - * over the current entry, updating index links, and lower - * the gobal nfds by one. If we're the last entry, simply - * remove it invalidating its index entry lowering the global - * nfds. - */ - - if (--poll_nfds != idx) { - /* - * Not last entry, move last entry over entry to - * delete. - */ - register struct pollfd *deleted, *last; - int deleted_fd, deleted_idx; - - last = &poll_fds[poll_nfds]; - deleted = &poll_fds[idx]; - deleted_fd = deleted->fd; - deleted_idx = poll_idx[deleted_fd].idx; - - /* Copy last entry over deleted one */ - deleted->fd = last->fd; - deleted->events = last->events; - deleted->revents = last->revents; - - /* - * Reindex last entry which was moved, don't touch - * the msg pointer though. - */ - poll_idx[last->fd].idx = deleted_idx; - - /* And finally invalidate last entry */ - poll_idx[deleted_fd].msg = NULL; - } else { - /* Invalidate last entry */ - poll_idx[poll_fds[poll_nfds].fd].msg = NULL; - } - } - - DEBUG_PTHREAD_EXIT(); -} - -/* - * Called upon reception of SIGUSR2 - */ -/* ARGSUSED */ -static void -poll_thread_sighandler(int sig) -{ - - DEBUG_PTHREAD_ENTRY(); - - pollingevents++; - - DEBUG_PTHREAD_EXIT(); -} - - - -/* - * Public API exported functions - */ - -/* - * Must be called before launching any thread. Sets up the signal mask and - * launches the dedicated poll slave thread. Important note: this system - * clobbers the SIGUSR2 signal, which the application can no longer use for - * other purposes. The only solution to wake the thread manager thread from - * poll(2) is either to trigger an event through a dedicated filedescriptor, - * or to send a signal to the process which only the polling thread allows. - */ -int -pthread_poll_init(void) -{ - int error; - sigset_t set; - pthread_attr_t attr; - pthread_t thread; - - DEBUG_PTHREAD_ENTRY(); - - if (pthread_poll_initialized) { - error = 0; - goto err; - } - - /* - * First block SIGUSR2 signal in the parent. The reason why this must - * be called before the application launches any thread is that - * threads inherit the sigmask of their parent, and that all threads, - * but the polling thread, must block the signal. This ensures that - * only the wanted thread wakes up when a SIGUSR2 signal is received. - * This way, we can interrupt the polling thread in poll(2), for - * instance, and cause it to reiterate its main loop. - */ - (void) sigemptyset(&set); - (void) sigaddset(&set, SIGUSR2); - if ((error = pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0) - goto err; - - /* - * We'll use this pthread_ring_t to get notification from child that - * it is ready to process requests before proceeding. - */ - if ((error = pthread_ring_init(&pthread_poll_thread_started_ring)) - != 0) - goto err; - - /* - * We may now launch the poll thread and wait for notification from it - * that it is ready to serve requests. We won't need to exit this - * thread, so it can be launched in detached state. - */ - if ((error = pthread_attr_init(&attr)) != 0) - goto err; - if ((error = pthread_attr_setdetachstate(&attr, TRUE)) != 0) - goto err; - if ((error = pthread_create(&thread, &attr, poll_thread, NULL)) != 0) - goto err; - - /* - * Wait until thread is ready to serve requests - */ - (void) pthread_ring_wait(&pthread_poll_thread_started_ring, NULL); - - pthread_poll_initialized = TRUE; - - return 0; - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * poll(2) replacement which can also be awakened by a notification happening - * on the specified ring. This for instance allows to process thread messages - * as well as descriptor events. Like poll(2), returns the number of - * descriptors with events on success (can be 0), or returns -1 with the - * specified error set in errno. Unlike poll, the error ETIMEDOUT will occur - * if the timeout expires before an event existed, or ECANCELLED if a ring - * notification event occurred instead of a filedescriptor one. Can also - * return errors such as EINVAL. - * XXX Check for ETIMEDOUT! We probably don't do this yet. Also, we could - * return 0 in this case like poll(2). - */ -int -pthread_poll_ring(struct pollfd *fds, nfds_t nfds, int timeout, - pthread_ring_t *ring) -{ - int error; - struct poll_data *data; - pthread_ring_t *oring; - - DEBUG_PTHREAD_ENTRY(); - - if (!pthread_poll_initialized) { - error = EINVAL; - goto err; - } - - /* - * Implicit process and thread specific initializations - */ - if ((error = pthread_once(&pthread_poll_proc_initialized, - pthread_poll_proc_init2)) != 0) - goto err; - /* - * XXX Use a mutex or pthread_once() equivalent here too? - */ - if ((data = pthread_getspecific(pthread_poll_proc_key)) == NULL) { - if ((error = pthread_poll_thread_init(&data)) != 0) - goto err; - } - - /* - * Perform some sanity checking on supplied arguments - */ - if (fds == NULL || nfds < 1 || ring == NULL || ring->magic != - PRING_MAGIC) { - error = EINVAL; - goto err; - } - - /* - * Ensure that our message port's ring uses the same ring which - * the user supplies us. If we didn't do this we would need to - * be able to wait for events on more than one ring simultaneously. - * Because we don't have a ring multiplexer object yet (which would - * be needed since a ring maps to a conditional variable among other - * things), we need to do process this way. - * XXX Could there be a race condition here? It needs to be stressed. - */ - { - int mevent; - - mevent = (data->port.ring != NULL ? - data->port.ring->mevent : 0); - oring = data->port.ring; - (void) pthread_port_set_ring(&data->port, ring); - data->port.ring->mevent = mevent; - } - - /* - * Send query to polling thread. It is safe to simply reuse our - * message since we then expect a reply back and synchronize it. - */ - data->msg.cancel = FALSE; - data->msg.fds = fds; - data->msg.nfds = nfds; - data->msg.timeout = timeout; - if ((error = pthread_msg_put(&pthread_poll_thread_port, - &data->msg.msgnode)) != 0) - goto err; - - /* - * Interrupt polling thread which may still be waiting in poll(2). - * We do this by sending SIGUSR2 to the process, which only the - * polling thread is not blocking. This causes the thread to reiterate - * its main loop, thus processing this message and going back to - * sleep in poll(2). - */ - POLLWAKE(); - - /* - * Wait until en event occurs and notifies our ring. An event could - * either be triggered by the poll request ending or by another - * interrupting event on the supplied ring. If a message is queued - * on the port between pthread_port_set_ring() and - * pthread_ring_wait(), the latter immediately returns. - */ - if ((error = pthread_ring_wait(ring, NULL)) != 0) - goto err; - if (pthread_msg_get(&data->port) == NULL) { - /* - * No message replied back from poll thread yet, this means - * that our ring was notified by another event. Cancel request - * by sending event back with the cancel flag, and wait for - * reply message to occur (which will be the original request - * results we were waiting for). error field will be set to - * ECANCELED by the poll thread. - */ - data->msg.cancel = TRUE; - (void) pthread_msg_put(&pthread_poll_thread_port, - &data->msg.msgnode); - POLLWAKE(); - while (pthread_msg_get(&data->port) == NULL) - (void) pthread_ring_wait(ring, NULL); - } - /* Unclobber user supplied ring from our port events */ - (void) pthread_port_set_ring(&data->port, oring); - - /* - * Error, return error number. - */ - if (data->msg.error != 0) { - error = data->msg.error; - goto err; - } - - /* - * Success, return number of descriptors with detected events. - */ - DEBUG_PTHREAD_EXIT(); - return data->msg.ready; - -err: - errno = error; - - DEBUG_PTHREAD_EXIT(); - return -1; -} - -/* - * accept(2) replacement which can both observe a timeout and be interrupted - * via pthread_ring_t events. Internally implemented using - * pthread_poll_ring(). Will internally set the descriptor in non-blocking - * mode if necessary, then reverting it to the mode it was supplied in. - * Returns a new descriptor on success, or -1 on error, in which case errno - * is set. errno can then be EINVAL, ETIMEDOUT, ECANCELED, or others. - * Timeout is in milliseconds, like for poll(2) and can be -1. - */ -int -pthread_accept_ring(int s, struct sockaddr *addr, socklen_t *addrlen, - int timeout, pthread_ring_t *ring) -{ - int oflags, nflags, d, error = 0; - struct pollfd fd; - - DEBUG_PTHREAD_ENTRY(); - - if (!pthread_poll_initialized) { - errno = EINVAL; - goto err; - } - - /* - * First get current fcntl status flags, and set descriptor to - * non-blocking mode if necessary. - */ - if ((oflags = nflags = fcntl(s, F_GETFL)) == -1) - goto err; - if ((oflags & O_NONBLOCK) == 0) { - nflags |= O_NONBLOCK; - if (fcntl(s, F_SETFL, nflags) == -1) - goto err; - } - - if ((d = accept(s, addr, addrlen)) == -1) { - if (errno != EAGAIN) /* XXX Add others? */ - goto end; - } else - goto end; - - /* - * EAGAIN, poll until completion, timeout or ring event. - */ - fd.fd = d; - fd.events = POLLIN; - if ((error = pthread_poll_ring(&fd, 1, timeout, ring)) == 1 && - (fd.revents & POLLIN) != 0) - error = 0; - else - error = errno; - -end: - /* - * Restore supplied descriptor fcntl status flags if necessary - */ - if (nflags != oflags) - (void) fcntl(s, F_SETFL, oflags); - - if (error != 0) { - if (d != -1) { - (void) close(d); - d = -1; - } - errno = error; - goto err; - } - - DEBUG_PTHREAD_EXIT(); - return d; - -err: - DEBUG_PTHREAD_EXIT(); - return -1; -} - -/* - * connect(2) replacement which can both observe a timeout and be interrupted - * via pthread_ring_t events. Internally implemented using - * pthread_poll_ring(). Will internally set the descriptor in non-blocking - * mode if necessary, then reverting it back to the mode it was supplied in. - * Returns 0 on success, or -1, in which case errno is set. errno can be - * EINVAL, ETIMEDOUT, ECANCELED or others. - * Timeout is in milliseconds, like for poll(2) and can be -1. - * For the application to know the actual connection status result, it should - * poll until completion and verify the status using getsockopt(2) with - * SOL_SOCKET level and SO_ERROR option. It can alternatively continue to call - * this function in a loop until completion. Calling the function on an - * already connected socket will result in EISCONN. - */ -int -pthread_connect_ring(int s, const struct sockaddr *name, socklen_t namelen, - int timeout, pthread_ring_t *ring) -{ - int oflags, nflags, error = 0; - struct pollfd fd; - - DEBUG_PTHREAD_ENTRY(); - - if (!pthread_poll_initialized) { - errno = EINVAL; - goto err; - } - - /* - * First get current fcntl status flags, and set descriptor to - * non-blocking mode if necessary. - */ - if ((oflags = nflags = fcntl(s, F_GETFL)) == -1) - goto err; - if ((oflags & O_NONBLOCK) == 0) { - nflags |= O_NONBLOCK; - if (fcntl(s, F_SETFL, nflags) == -1) - goto err; - } - - if ((error = connect(s, name, namelen)) == -1) { - if (errno != EINPROGRESS && errno != EALREADY) { - error = errno; - goto end; - } - } else - goto end; - - /* - * EINPROGRESS or EALREADY, poll until completion, timeout or ring - * event. - */ - fd.fd = s; - fd.events = POLLOUT; - if (pthread_poll_ring(&fd, 1, timeout, ring) == 1 && - (fd.revents & POLLOUT) != 0) { - socklen_t l; - - /* - * connect(2) completed, return result - */ - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &l) == -1) - error = errno; - } - -end: - /* - * Restore supplied descriptor fcntl status flags if necessary - */ - if (nflags != oflags) - (void) fcntl(s, F_SETFL, oflags); - - if (error != 0) { - errno = error; - goto err; - } - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - DEBUG_PTHREAD_EXIT(); - return -1; -} diff --git a/tests/pthread_utils/mm_pthread_poll.h b/tests/pthread_utils/mm_pthread_poll.h deleted file mode 100644 index 77af18a..0000000 --- a/tests/pthread_utils/mm_pthread_poll.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id: mm_pthread_poll.h,v 1.6 2005/11/22 18:03:48 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef MM_PTHREAD_POLL_H -#define MM_PTHREAD_POLL_H - - - -#include -#include -#include -#include -#include - -#include - - - -extern int pthread_poll_init(void); -extern int pthread_poll_ring(struct pollfd *, nfds_t, int, - pthread_ring_t *); -extern int pthread_accept_ring(int, struct sockaddr *, socklen_t *, int, - pthread_ring_t *); -extern int pthread_connect_ring(int, const struct sockaddr *, socklen_t, - int, pthread_ring_t *); - - - -#endif diff --git a/tests/pthread_utils/mm_pthread_pool.c b/tests/pthread_utils/mm_pthread_pool.c deleted file mode 100644 index 80ba5fb..0000000 --- a/tests/pthread_utils/mm_pthread_pool.c +++ /dev/null @@ -1,504 +0,0 @@ -/* $Id: mm_pthread_pool.c,v 1.7 2006/02/05 13:00:48 mmondor Exp $ */ - -/* - * Copyright (C) 2004-2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Implementation of a pool of ready threads which adapts with concurrency - * needs. These ready threads can serve requests passed through efficient - * inter-thread messaging. mmpool(3) is used for the pool functionality. - */ - - - -#include -#include -#include - -#include -#include - - - -MMCOPYRIGHT("@(#) Copyright (c) 2004-2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: mm_pthread_pool.c,v 1.7 2006/02/05 13:00:48 mmondor Exp $"); - - - -/* - * STATIC FUNCTIONS PROTOTYPES - */ - -inline static pthread_object_t *thread_object_alloc(void); -inline static void thread_object_free(pthread_object_t *); -static bool thread_object_constructor(pnode_t *); -static void thread_object_destructor(pnode_t *); -static void *thread_object_main(void *); - - - -/* - * GLOBALS - */ - -static bool thread_object_initialized = FALSE; -static pthread_attr_t thread_object_attr; -static pool_t thread_object_pool; -static pool_t thread_object_msg_pool; -static pthread_mutex_t thread_object_pool_mutex = - PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t thread_object_msg_pool_mutex = - PTHREAD_MUTEX_INITIALIZER; -static pthread_ring_t thread_started_ring; - - - -/* - * EXPORTED PUBLIC FUNCTIONS - */ - -/* - * Must be called to initialize the pthreads pool subsystem, before calling - * any other function of this API. Returns 0 on success, or an error number. - * threads are launched, and more will be launched in increments - * of whenever necessary. These will also only be destroyed in - * decrements of whenever that many threads have not been in use for - * some time, and a minimum of threads will always be kept. - * Setting to high values may actually degrade performance with some - * unefficient threading implementations. It is not recommended to use more - * than 8 using the pth(3) library. Using NetBSD 2.0+ SA threads, a high - * number does not reduce performance. We current do not observe any limit - * whatsoever according to the number of threads launched over time. It is the - * application's responsibility to ensure to observe decent concurrency limits - * before calling pthread_object_call(). - */ -int -pthread_object_init(int initial) -{ - int error = 0; - - DEBUG_PTHREAD_ENTRY(); - - if (thread_object_initialized) { - error = EINVAL; - goto err; - } - - /* - * Create attributes which will be used for threads of the pool. - * We want them to be joinable. - */ - if ((error = pthread_attr_init(&thread_object_attr)) != 0) - goto err; - if ((error = pthread_attr_setdetachstate(&thread_object_attr, 0)) - != 0) - goto err; - - /* - * We use this ring to obtain notification of ready children when - * launching them. This is required for proper synchronization to - * avoid aweful race conditions. - */ - if ((error = pthread_ring_init(&thread_started_ring)) != 0) - goto err; - - /* - * First initialize the message subsystem pool - */ - if (!pool_init(&thread_object_msg_pool, "thread_object_msg_pool", - malloc, free, NULL, NULL, sizeof(pthread_object_msg_t), - 32768 / sizeof(pthread_object_msg_t), 1, 0)) { - error = ENOMEM; - goto err; - } - - /* - * Now initialize the threads pool. This creates threads, uses - * synchronization with thread_started_ring, and uses the message - * subsystem, which all must be initialized and ready. - */ - if (!pool_init(&thread_object_pool, "thread_object_pool", - malloc, free, thread_object_constructor, thread_object_destructor, - sizeof(pthread_object_t), initial, 1, 0)) { - error = ENOMEM; - goto err; - } - - thread_object_initialized = TRUE; - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - if (POOL_VALID(&thread_object_msg_pool)) - pool_destroy(&thread_object_msg_pool); - if (POOL_VALID(&thread_object_pool)) - pool_destroy(&thread_object_pool); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Allows allocation/creation of a message suitable for asynchronous requests - * with the threads via their main message port provided by this system. - * Returns new message, or NULL on error. - */ -inline pthread_object_msg_t * -pthread_object_msg_alloc(void) -{ - pthread_object_msg_t *msg = NULL; - - DEBUG_PTHREAD_ENTRY(); - - if (pthread_mutex_lock(&thread_object_msg_pool_mutex) != 0) - goto err; - msg = (pthread_object_msg_t *)pool_alloc(&thread_object_msg_pool, - FALSE); - (void) pthread_mutex_unlock(&thread_object_msg_pool_mutex); - - (void) pthread_msg_init(&msg->message, NULL); - -err: - DEBUG_PTHREAD_EXIT(); - return msg; -} - -/* - * Permits to free/destroy a message which was allocated using - * pthread_object_msg_alloc() and sent asynchroneously. - */ -inline int -pthread_object_msg_free(pthread_object_msg_t *msg) -{ - int error = 0; - - DEBUG_PTHREAD_ENTRY(); - - (void) pthread_msg_destroy(&msg->message); - - if ((error = pthread_mutex_lock(&thread_object_msg_pool_mutex)) != 0) - goto err; - (void) pool_free((pnode_t *)msg); - (void) pthread_mutex_unlock(&thread_object_msg_pool_mutex); - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Allows to invoke a thread of the pool to perform execution of the wanted - * function. This is very efficient since the threads are already created and - * are waiting for requests. There is no maximum concurrency limit enforced by - * this system; It is the responsibility of the application to restrict - * concurrency as necessary by keeping internal information on the current - * number of requests. 0 is returned on success, or an error number. - * XXX Add support for synchroneous and asynchroneous operation. Current - * operation is only asynchroneous, but we would like to add a boolean here to - * decide. We also could add back the result value of the thread function - * which would only be useful in synchroneous operation, when we are waiting - * until the task ends... Of course, it's still easy for applications to use - * these in a synchroneous manner, by using a message and/or ring, - * conditionnal variable, etc. - * Also evaluate if a callback function to be called to notify end of - * asynchroneous operation would be useful. - */ -int -pthread_object_call(pthread_port_t **port, - void (*function)(pthread_object_t *, void *), void *args) -{ - pthread_object_t *obj = NULL; - pthread_object_msg_t *msg = NULL; - int error; - - DEBUG_PTHREAD_ENTRY(); - - if (function == NULL) { - error = EINVAL; - goto err; - } - - /* - * Allocate a thread from the pool to reserve it, and tell it to call - * a function via a message. The message cannot be on the stack in - * this case, since it holds arguments to be passed to a thread, and - * also consists of an asynchroneous message for wich we do not expect - * a response back, waiting for it. We just dispatch it and go on. - */ - if ((obj = thread_object_alloc()) == NULL) { - error = ENOMEM; - goto err; - } - if ((msg = pthread_object_msg_alloc()) == NULL) { - error = ENOMEM; - goto err; - } - - msg->command = PTHREAD_OBJ_CALL; - msg->u.call.function = function; - msg->u.call.arguments = args; - if ((error = pthread_msg_put(obj->port, &msg->message)) != 0) - goto err; - - /* - * Everything successful; - * If caller wants the message port of the thread, supply it - */ - if (port != NULL) - *port = obj->port; - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - if (msg != NULL) - pthread_object_msg_free(msg); - if (obj != NULL) - thread_object_free(obj); - - DEBUG_PTHREAD_EXIT(); - return error; -} - - - -/* - * INTERNAL STATIC FUNCTIONS - */ - -/* - * Internally used to allocate a ready thread from the pool. - */ -inline static pthread_object_t * -thread_object_alloc(void) -{ - pthread_object_t *obj = NULL; - - DEBUG_PTHREAD_ENTRY(); - - if (pthread_mutex_lock(&thread_object_pool_mutex) != 0) - goto err; - obj = (pthread_object_t *)pool_alloc(&thread_object_pool, FALSE); - (void) pthread_mutex_unlock(&thread_object_pool_mutex); - -err: - return obj; -} - -/* - * Internally used to free a no longer needed thread back to the pool of ready - * threads. - */ -inline static void -thread_object_free(pthread_object_t *obj) -{ - - DEBUG_PTHREAD_ENTRY(); - - if (pthread_mutex_lock(&thread_object_pool_mutex) == 0) { - (void) pool_free((pnode_t *)obj); - (void) pthread_mutex_unlock(&thread_object_pool_mutex); - } - - DEBUG_PTHREAD_EXIT(); -} - -/* - * Internally called by mmpool(3) to create a thread object. - */ -static bool -thread_object_constructor(pnode_t *pnode) -{ - pthread_object_t *obj = (pthread_object_t *)pnode; - int success = TRUE; - - DEBUG_PTHREAD_ENTRY(); - - /* - * Note that we leave thread_object_main() initialize the port field - * when it creates its port and ring. - */ - if (pthread_create(&obj->thread, &thread_object_attr, - thread_object_main, obj) != 0) { - success = FALSE; - goto err; - } - - /* - * Wait until new thread ready notification. Without this, at least - * with NetBSD 2.0 SA threads, hell would break loose. Thread creation - * isn't really a bottleneck in our case anyways, since we only need - * to do it when all threads of the pool are already busy. - */ - (void) pthread_ring_wait(&thread_started_ring, NULL); - -err: - DEBUG_PTHREAD_EXIT(); - return success; -} - -/* - * Internally called by mmpool(3) to destroy a thread object. - */ -static void -thread_object_destructor(pnode_t *pnode) -{ - pthread_object_t *obj = (pthread_object_t *)pnode; - pthread_object_msg_t *msg; - - DEBUG_PTHREAD_ENTRY(); - - /* - * To be freed, the thread has to be terminated. We thus send it a - * quit message and then wait for it to exit using pthread_join(). - * Note that we let the thread destroy the port field. Although we - * theoretically could use a message on the stack here, let's be safe. - * Thread destruction is only performed rarely anyways, so this isn't - * a performance problem. - */ - if ((msg = pthread_object_msg_alloc()) != NULL) { - msg->command = PTHREAD_OBJ_QUIT; - (void) pthread_msg_put(obj->port, &msg->message); - } - (void) pthread_join(obj->thread, NULL); - - DEBUG_PTHREAD_EXIT(); -} - -/* - * Actual thread's main loop. We create a message port and listen for command - * messages (quit and call). When we obtain a quit request, we destroy the - * port and exit cleanly. The quit event can never occur during the execution - * of a call command, since it is only called on already freed thread nodes - * (by mmpool(3) pool_free()). It is advized to applications which need to - * obtain and use the port of the thread after thread_object_call() to only - * send proper user messages, not system reserved ones. - */ -static void * -thread_object_main(void *args) -{ - pthread_object_t *obj = (pthread_object_t *)args; - pthread_port_t port; - pthread_ring_t ring; - pthread_msg_t *imsg; - pthread_object_msg_t *msg; - - DEBUG_PTHREAD_ENTRY(); - - /* - * Create our incomming message port as well as its corresponding - * notification ring we can sleep on. Then advertize our port address. - * Ideally, we should somehow panic if any of this initialization - * fails. XXX - */ - (void) pthread_port_init(&port); - (void) pthread_ring_init(&ring); - (void) pthread_port_set_ring(&port, &ring); - obj->port = &port; - - /* - * Notify parent that we are ready, so that it may proceed - */ - (void) pthread_ring_notify(&thread_started_ring); - - /* - * Main loop, which keeps executing until we obtain a PTHREAD_OBJ_QUIT - * message, at which event we cleanly exit. - */ - for (;;) { - /* - * Wait for any message(s) to be available, without taking any - * CPU time. - */ - (void) pthread_ring_wait(&ring, NULL); - - /* - * We were awaken because at least one message is available. - * Process all messages in the queue. - */ - while ((imsg = pthread_msg_get(&port)) != NULL) { - msg = (pthread_object_msg_t *)(&((pnode_t *)imsg)[-1]); - if (msg->command == PTHREAD_OBJ_QUIT) { - /* - * We are ordered to exit by the object - * destructor. - */ - pthread_object_msg_free(msg); - goto end; - } - if (msg->command == PTHREAD_OBJ_CALL) { - /* - * Request to execute a function. This means - * that we were allocated/reserved first. - */ - msg->u.call.function(obj, - msg->u.call.arguments); - pthread_object_msg_free(msg); - /* - * Free/release us back, so that we be - * available again to process further - * requests. It is possible that freeing - * ourselves cause a PTHREAD_OBJ_QUIT message - * to be queued soon on our port by the - * destructor function. This is safe, since - * the destructor does not cause us to be - * destroyed until it waits for us to have - * ended cleanly using pthread_join(). - */ - thread_object_free(obj); - } - } - } - -end: - /* - * Discard messages that are still queued on our port (if any) - */ - while ((imsg = pthread_msg_get(&port)) != NULL) { - msg = (pthread_object_msg_t *)(&((pnode_t *)imsg)[-1]); - pthread_object_msg_free(msg); - } - /* - * Free our resources and exit. - */ - (void) pthread_port_destroy(&port); - (void) pthread_ring_destroy(&ring); - - DEBUG_PTHREAD_EXIT(); - pthread_exit(NULL); - - /* NOTREACHED */ - return NULL; -} diff --git a/tests/pthread_utils/mm_pthread_pool.h b/tests/pthread_utils/mm_pthread_pool.h deleted file mode 100644 index 2a46ebd..0000000 --- a/tests/pthread_utils/mm_pthread_pool.h +++ /dev/null @@ -1,97 +0,0 @@ -/* $Id: mm_pthread_pool.h,v 1.1 2004/12/27 11:16:16 mmondor Exp $ */ - -/* - * Copyright (C) 2004-2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef MM_PTHREAD_POOL_H -#define MM_PTHREAD_POOL_H - - - -#include - -#include -#include - -#include - - - -typedef struct { - pnode_t node; - pthread_t thread; - pthread_port_t *port; -} pthread_object_t; - -typedef struct { - pnode_t node; - pthread_msg_t message; - int command; - union { - /* PTHREAD_OBJ_CALL, sent to thread_object_main() */ - struct { - void (*function)(pthread_object_t *, void *); - void *arguments; - } call; - /* PTHREAD_OBJ_QUIT, sent to thread_oject_reaper() */ - pthread_object_t *quit; - /* PTHREAD_OBJ_USER, custom user messages */ - struct { - int user_command; - void *user_data; - } user; - } u; -} pthread_object_msg_t; - -enum pthread_object_commands { - PTHREAD_OBJ_CALL, - PTHREAD_OBJ_QUIT, - PTHREAD_OBJ_USER, - PTHREAD_OBJ_MAX -}; - - - -extern int pthread_object_init(int); -extern inline pthread_object_msg_t *pthread_object_msg_alloc(void); -extern inline int pthread_object_msg_free( - pthread_object_msg_t *); -extern int pthread_object_call(pthread_port_t **, - void (*)(pthread_object_t *, - void *), void *); - - - -#endif diff --git a/tests/pthread_utils/mm_pthread_sleep.c b/tests/pthread_utils/mm_pthread_sleep.c deleted file mode 100644 index a9f8c58..0000000 --- a/tests/pthread_utils/mm_pthread_sleep.c +++ /dev/null @@ -1,285 +0,0 @@ -/* $Id: mm_pthread_sleep.c,v 1.5 2006/02/05 13:00:48 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - - -MMCOPYRIGHT("@(#) Copyright (c) 2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: mm_pthread_sleep.c,v 1.5 2006/02/05 13:00:48 mmondor Exp $"); - - - -static int pthread_sleep_proc_init(void); -static void pthread_sleep_proc_init2(void); -static int pthread_sleep_thread_init(pthread_ring_t **); -static void pthread_sleep_thread_exit(void *); - -static pthread_key_t pthread_sleep_proc_key; -static pthread_once_t pthread_sleep_proc_initialized = PTHREAD_ONCE_INIT; - - - -static int -pthread_sleep_proc_init(void) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - - error = pthread_key_create(&pthread_sleep_proc_key, - pthread_sleep_thread_exit); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -static void -pthread_sleep_proc_init2(void) -{ - int error; - - DEBUG_PTHREAD_ENTRY(); - - if ((error = pthread_sleep_proc_init()) != 0) { - (void) fprintf(stderr, "pthread_sleep_proc_init() - %s\n", - strerror(error)); - DEBUG_PTHREAD_EXIT(); - exit(EXIT_FAILURE); - } - - DEBUG_PTHREAD_EXIT(); -} - -static int -pthread_sleep_thread_init(pthread_ring_t **res) -{ - int error; - pthread_ring_t *ring; - - DEBUG_PTHREAD_ENTRY(); - - if ((ring = malloc(sizeof(pthread_ring_t))) == NULL) { - error = ENOMEM; - goto err; - } - - if ((error = pthread_ring_init(ring)) != 0) - goto err; - - if ((error = pthread_setspecific(pthread_sleep_proc_key, ring)) != 0) - goto err; - - *res = ring; - - DEBUG_PTHREAD_EXIT(); - return 0; - -err: - if (ring != NULL) - free(ring); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -static void -pthread_sleep_thread_exit(void *specific) -{ - pthread_ring_t *ring = (pthread_ring_t *)specific; - - DEBUG_PTHREAD_ENTRY(); - - (void) pthread_ring_destroy(ring); - free(ring); - - /* - * Although NetBSD threads don't need this, some pthread - * implementations do. Some will crash for attempting to reference the - * already freed memory twice calling us again until we NULL the - * pointer for the data. Lame, but the POSIX standard was unclear - * about this. - */ - (void) pthread_setspecific(pthread_sleep_proc_key, NULL); - - DEBUG_PTHREAD_EXIT(); -} - - - -/* - * Suspends the calling thread for duration specified in supplied timespec. - * Returns 0 on success, or an error number. - */ -int -pthread_nanosleep(struct timespec *ts) -{ - int error; - struct timeval tv; - struct timespec its; - pthread_ring_t *ring; - - DEBUG_PTHREAD_ENTRY(); - - /* - * Process specific initialization if needed - */ - if ((error = pthread_once(&pthread_sleep_proc_initialized, - pthread_sleep_proc_init2)) != 0) - goto err; - /* - * Thread specific initialization if needed - * XXX Use pthread_once() here too, or mutex around ring? - */ - if ((ring = pthread_getspecific(pthread_sleep_proc_key)) == NULL) { - if ((error = pthread_sleep_thread_init(&ring)) != 0) - goto err; - } - - /* - * Generate absolute time timespec using current time and supplied - * timespec delay. - */ - if (gettimeofday(&tv, NULL) == -1) { - error = errno; - goto err; - } - TIMEVAL_TO_TIMESPEC(&tv, &its); - timespecadd(&its, ts, &its); - - /* - * We can finally sleep. We expect ETIMEDOUT to be the normal return - * value in this case, which we convert to a no-error. Other errors - * will be returned un changed. - */ - if ((error = pthread_ring_wait(ring, &its)) == ETIMEDOUT) - error = 0; - -err: - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Suspends the current thread for the duration specified into supplied - * timeval. Returns 0 on success or an error number. - */ -int -pthread_microsleep(struct timeval *tv) -{ - struct timespec ts; - int error; - - DEBUG_PTHREAD_ENTRY(); - - TIMEVAL_TO_TIMESPEC(tv, &ts); - error = pthread_nanosleep(&ts); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Suspends execution of current thread for duration of specified - * milliseconds. Returns 0 on success or an error number. - */ -int -pthread_millisleep(unsigned int ms) -{ - struct timeval tv; - int error; - - DEBUG_PTHREAD_ENTRY(); - - tv.tv_sec = ms / 1000; - tv.tv_usec = (ms % 1000) * 1000; - error = pthread_microsleep(&tv); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Suspends execution of thread for duration of specified number of seconds. - * Returns 0 on success or an error number. - */ -unsigned int -pthread_sleep(unsigned int seconds) -{ - struct timespec ts; - int error; - - DEBUG_PTHREAD_ENTRY(); - - ts.tv_sec = seconds; - ts.tv_nsec = 0; - error = pthread_nanosleep(&ts); - - DEBUG_PTHREAD_EXIT(); - return error; -} - -/* - * Suspends execution of thread for durection of specified number of - * microseconds. Like usleep(3). - */ -int -pthread_usleep(useconds_t ms) -{ - struct timeval tv; - int error; - - DEBUG_PTHREAD_ENTRY(); - - tv.tv_sec = 0; - tv.tv_usec = ms; - error = pthread_microsleep(&tv); - - DEBUG_PTHREAD_EXIT(); - return error; -} diff --git a/tests/pthread_utils/mm_pthread_sleep.h b/tests/pthread_utils/mm_pthread_sleep.h deleted file mode 100644 index 93b6766..0000000 --- a/tests/pthread_utils/mm_pthread_sleep.h +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id: mm_pthread_sleep.h,v 1.2 2005/09/16 08:49:06 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef MM_PTHREAD_SLEEP_H -#define MM_PTHREAD_SLEEP_H - - - -#include -#include -#include - - - -extern int pthread_nanosleep(struct timespec *); -extern int pthread_microsleep(struct timeval *); -extern int pthread_millisleep(unsigned int); -extern unsigned int pthread_sleep(unsigned int); -extern int pthread_usleep(useconds_t); - - - -#endif diff --git a/tests/pthread_utils/tests/msg_test.c b/tests/pthread_utils/tests/msg_test.c deleted file mode 100644 index bb7e918..0000000 --- a/tests/pthread_utils/tests/msg_test.c +++ /dev/null @@ -1,269 +0,0 @@ -/* $Id: msg_test.c,v 1.3 2005/11/18 10:54:58 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - - -MMCOPYRIGHT("@(#) Copyright (c) 2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: msg_test.c,v 1.3 2005/11/18 10:54:58 mmondor Exp $"); - - - -#define THREADS 32 -#define ROUNDS 8 -#define TIMEOUT 1 -/*#define PRINTLOCK*/ -/*#define NOPRINT*/ - - - -struct message { - pthread_msg_t node; - int id, i; -}; - - - -int main(void); -static void threadfunc(pthread_object_t *, void *); -static void printfunc(const char *, ...); - - - -static pthread_port_t main_port; -static pthread_mutex_t print_lock; - - - -int -main(void) -{ - pthread_ring_t ring; - struct message *msg; - int i, err; - int threads_args[THREADS]; - struct timeval tv; - struct timespec ts, ts1; - - if ((err = pthread_mutex_init(&print_lock, NULL)) != 0) { - (void) printf("main() - stdout lock - %s\n", strerror(err)); - exit(EXIT_FAILURE); - } - - if ((err = pthread_port_init(&main_port)) != 0 || - (err = pthread_ring_init(&ring)) != 0 || - (err = pthread_port_set_ring(&main_port, &ring)) != 0) { - printfunc("main() - initialization - %s\n", strerror(err)); - exit(EXIT_FAILURE); - } - - printfunc("Main: launching threads\n"); - - if ((err = pthread_poll_init()) != 0) { - printfunc("main() - pthread_poll_init() - %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - /* - * Initializes a poll of ready threads which can be dispatched - * functions to execute. - */ - if ((err = pthread_object_init(THREADS + 1)) != 0) { - printfunc("main() - pthread_object_init() - %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - /* - * Now dispatch a main reentrant function to many threads, without - * waiting for them to complete, in an asynchroneous manner. - * XXX Because of the way this works, the parent main thread should - * actually already be listening to messages... We did create a port - * however, which should queue messages until we reach the main loop. - */ - for (i = 0; i < THREADS; i++) { - threads_args[i] = i; - if ((err = pthread_object_call(NULL, threadfunc, - &threads_args[i])) != 0) - printfunc("main() - pthread_object_call() - %s\n", - strerror(errno)); - } - - ts1.tv_sec = TIMEOUT; - ts1.tv_nsec = 0; - for (;;) { - /* - * Read messages as long as there are any, and reply to each - * of them in a synchroneous manner. - */ - while ((msg = (struct message *)pthread_msg_get(&main_port)) - != NULL) { - - printfunc( - "Main: Received message %d from thread #%d\n", - msg->i, msg->id); - - if ((err = pthread_msg_reply((pthread_msg_t *)msg)) - != 0) - printfunc( - "Main: pthread_message_reply() - %s\n", - strerror(err)); - } - - /* - * No more messages to process; Wait for any message(s) to be - * available. - * Note that there is special provision in the event where - * this loop first polling for new messages before processing - * them, which causes waiting for the ring to immediately - * return instead of actually waiting if any messages already - * have been sent. - */ - printfunc("Main: Waiting for messages\n"); - - (void) gettimeofday(&tv, NULL); - TIMEVAL_TO_TIMESPEC(&tv, &ts); - timespecadd(&ts, &ts1, &ts); - if ((err = pthread_ring_wait(&ring, &ts)) != 0) { - printfunc("Main: pthread_ring_wait() - %s\n", - strerror(err)); - break; - } - } - - (void) pthread_mutex_destroy(&print_lock); - (void) pthread_port_destroy(&main_port); - (void) pthread_ring_destroy(&ring); - - return 0; -} - -static void -threadfunc(pthread_object_t *obj, void *args) -{ - int id = *(int *)args; - int i, err; - struct message msg; - pthread_port_t rport; - pthread_ring_t rring; - - if ((err = pthread_port_init(&rport)) != 0 || - (err = pthread_ring_init(&rring)) != 0 || - (err = pthread_port_set_ring(&rport, &rring)) != 0 || - (err = pthread_msg_init((pthread_msg_t *)&msg, &rport)) != 0) { - printfunc("threadfunc() - initialization - %s\n", - strerror(err)); - return; - } - - msg.id = id; - - (void) printfunc("Thread #%d started\n", id); - - for (i = 0; i < ROUNDS; i++) { - /* - * Prepare and send synchronous message. For asynchronous - * operation, we would need to allocate a message and to send - * it, and not expect a reply back immediately, even letting - * the other end free the message as necessary. In synchronous - * mode we can use the same message over and over and share - * its memory area using proper send/reply methods for - * synchronization. - */ - msg.i = i; - if ((err = pthread_msg_put(&main_port, (pthread_msg_t *)&msg)) - != 0) - printfunc("Thread: pthread_message_put() - %s\n", - strerror(err)); - - /* Now wait for synchronous reply and discard it */ - if ((err = pthread_ring_wait(&rring, NULL)) != 0) { - printfunc("Thread: pthread_ring_wait() - %s\n", - strerror(err)); - break; - } - if (pthread_msg_get(&rport) == NULL) - printfunc("Thread: pthread_msg_get() == NULL!?\n"); - printfunc("Thread #%d received reply message for %d\n", - id, i); - } - - printfunc("Thread #%d ending\n", id); - - (void) pthread_port_destroy(&rport); - (void) pthread_ring_destroy(&rring); - (void) pthread_msg_destroy((pthread_msg_t *)&msg); -} - -static void -printfunc(const char *fmt, ...) -{ - char buf[1024]; - va_list arg_ptr; - int len; - -#ifdef NOPRINT - return; -#endif - - *buf = '\0'; - va_start(arg_ptr, fmt); - if ((len = vsnprintf(buf, 1023, fmt, arg_ptr)) < 1) - return; - va_end(arg_ptr); - -#ifdef PRINTLOCK - (void) pthread_mutex_lock(&print_lock); -#endif - (void) fwrite(buf, len, 1, stdout); -#ifdef PRINTLOCK - (void) fflush(stdout); - (void) pthread_mutex_unlock(&print_lock); -#endif -} diff --git a/tests/pthread_utils/tests/poll_test.c b/tests/pthread_utils/tests/poll_test.c deleted file mode 100644 index 7be14bc..0000000 --- a/tests/pthread_utils/tests/poll_test.c +++ /dev/null @@ -1,73 +0,0 @@ -/* $Id: poll_test.c,v 1.1 2005/09/14 23:48:10 mmondor Exp $ */ - -/* - * Copyright (C) 2005, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - - -MMCOPYRIGHT("@(#) Copyright (c) 2005\n\ -\tMatthew Mondor. All rights reserved.\n"); -MMRCSID("$Id: poll_test.c,v 1.1 2005/09/14 23:48:10 mmondor Exp $"); - - - -int main(void); - - - -int -main(void) -{ - int err; - - if ((err = pthread_poll_init()) != 0) { - (void) fprintf(stderr, "main() - pthread_poll_init() - %s\n", - strerror(err)); - exit(EXIT_FAILURE); - } - - return 0; -} diff --git a/tests/pthread_utils/tests/polltest.c b/tests/pthread_utils/tests/polltest.c deleted file mode 100644 index ceedfd5..0000000 --- a/tests/pthread_utils/tests/polltest.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * The goal of this program is to verify if it is valid for multiple threads - * to poll(2) on the same filedescriptor, and if so, what happens whenever - * an event is triggered on that descriptor. - * - * XXX Problems: - * - Only one of the polling threads seems to be awaken when an event occurs - * on the descriptor. This probably means that using a signal would be - * better... I sure don't want to need a filedescriptor per ring... - * If I did however, would this really hurt? Are there that many rings? - * But oops, this actually means two filedescriptors for each! - * using a signal is probably better. However, we then need to clobber some - * signal... We could use SIGUSR2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#define THREADS 8 - - - -int main(void); -static void *thread_poll(void *); -static void *thread_notify(void *); -static void thread_print(int, const char *); - - - -static int sockets[2]; -static int threadargs[THREADS]; -static pthread_mutex_t print_mutex; -static pthread_mutex_t sockets_mutex; - - - -int -main(void) -{ - pthread_t threadid; - int i; - - /* - * Create socketpair which will be used to trigger events to awaken - * polling threads. - */ - if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockets) != 0) { - perror("socketpair()"); - exit(EXIT_FAILURE); - } - if (fcntl(sockets[0], F_SETFL, O_NONBLOCK) != 0 || - fcntl(sockets[1], F_SETFL, O_NONBLOCK) != 0) { - perror("fcntl()"); - exit(EXIT_FAILURE); - } - - pthread_mutex_init(&print_mutex, NULL); - pthread_mutex_init(&sockets_mutex, NULL); - - /* - * First launch THREADS polling threads - */ - for (i = 0; i < THREADS; i++) { - threadargs[i] = i; - pthread_create(&threadid, NULL, thread_poll, &threadargs[i]); - } - sleep(1); - - /* - * And finally launch notifyer thread - */ - pthread_create(&threadid, NULL, thread_notify, NULL); - - /* - * Now just wait - */ - for (;;) - (void) pause(); -} - -static void * -thread_poll(void *args) -{ - struct pollfd fds[1]; - int n; - int id = *(int *)args; - char c; - - fds[0].fd = sockets[1]; - fds[0].events = POLLIN; - for (;;) { - thread_print(id, "Polling"); - if ((n = poll(fds, 1, -1)) == -1) { - perror("poll()"); - return NULL; - } - thread_print(id, "Poll returned"); - if (n == 0) { - thread_print(id, "Woke up! (no data)"); - continue; - } - if ((fds[0].revents & POLLIN) != 0) { - /* Attempt to read event/byte */ - thread_print(id, "Woke up! (with data)"); - pthread_mutex_lock(&sockets_mutex); - while ((n = read(sockets[1], &c, 1)) == 1) - thread_print(id, "Read data!"); - if (n == -1) - thread_print(id, strerror(errno)); - pthread_mutex_unlock(&sockets_mutex); - } - } -} - -/* ARGSUSED */ -static void * -thread_notify(void *args) -{ - char c = '\0'; - struct pollfd fds[1]; - - fds[0].fd = sockets[0]; - fds[0].events = POLLOUT; - for (;;) { - sleep(1); - thread_print(-1, "Notifying"); - pthread_mutex_lock(&sockets_mutex); - if (write(sockets[0], &c, 1) != 1) { - /* Poll until we can send data */ - (void) poll(fds, 1, -1); - } - pthread_mutex_unlock(&sockets_mutex); - } -} - -static void -thread_print(int id, const char *str) -{ - - pthread_mutex_lock(&print_mutex); - printf("%d: %s\n", id, str); - pthread_mutex_unlock(&print_mutex); -} diff --git a/tests/pthread_utils/tests/sigtest.c b/tests/pthread_utils/tests/sigtest.c deleted file mode 100644 index cc4b681..0000000 --- a/tests/pthread_utils/tests/sigtest.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * The goal of this program is to verify if it is valid for multiple threads - * to be awaken from a poll(2) call by a single process-wide signal. This - * would allow the notifyer of a thread message event to generate this signal - * if needed to cause interested treads to wake up. Threads which do not want - * to receive the signal can simply ignore it using pthread_sigmask(). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#define THREADS 8 - - - -int main(void); -static void *thread_poll(void *); -static void *thread_notify(void *); -static void thread_print(int, const char *); - - - -static int sockets[2]; -static int threadargs[THREADS]; -static pthread_mutex_t print_mutex; -static pthread_mutex_t sockets_mutex; - - - -int -main(void) -{ - pthread_t threadid; - int i; - - /* - * Create socketpair which will be used to trigger events to awaken - * polling threads. - */ - if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockets) != 0) { - perror("socketpair()"); - exit(EXIT_FAILURE); - } - if (fcntl(sockets[0], F_SETFL, O_NONBLOCK) != 0 || - fcntl(sockets[1], F_SETFL, O_NONBLOCK) != 0) { - perror("fcntl()"); - exit(EXIT_FAILURE); - } - - pthread_mutex_init(&print_mutex, NULL); - pthread_mutex_init(&sockets_mutex, NULL); - - /* - * First launch THREADS polling threads - */ - for (i = 0; i < THREADS; i++) { - threadargs[i] = i; - pthread_create(&threadid, NULL, thread_poll, &threadargs[i]); - } - sleep(1); - - /* - * And finally launch notifyer thread - */ - pthread_create(&threadid, NULL, thread_notify, NULL); - - /* - * Now just wait - */ - for (;;) - (void) pause(); -} - -static void * -thread_poll(void *args) -{ - struct pollfd fds[1]; - int n; - int id = *(int *)args; - char c; - - fds[0].fd = sockets[1]; - fds[0].events = POLLIN; - for (;;) { - thread_print(id, "Polling"); - if ((n = poll(fds, 1, -1)) == -1) { - perror("poll()"); - return NULL; - } - thread_print(id, "Poll returned"); - if (n == 0) { - thread_print(id, "Woke up! (no data)"); - continue; - } - if ((fds[0].revents & POLLIN) != 0) { - /* Attempt to read event/byte */ - thread_print(id, "Woke up! (with data)"); - pthread_mutex_lock(&sockets_mutex); - while ((n = read(sockets[1], &c, 1)) == 1) - thread_print(id, "Read data!"); - if (n == -1) - thread_print(id, strerror(errno)); - pthread_mutex_unlock(&sockets_mutex); - } - } -} - -/* ARGSUSED */ -static void * -thread_notify(void *args) -{ - char c = '\0'; - struct pollfd fds[1]; - - fds[0].fd = sockets[0]; - fds[0].events = POLLOUT; - for (;;) { - sleep(1); - thread_print(-1, "Notifying"); - pthread_mutex_lock(&sockets_mutex); - if (write(sockets[0], &c, 1) != 1) { - /* Poll until we can send data */ - (void) poll(fds, 1, -1); - } - pthread_mutex_unlock(&sockets_mutex); - } -} - -static void -thread_print(int id, const char *str) -{ - - pthread_mutex_lock(&print_mutex); - printf("%d: %s\n", id, str); - pthread_mutex_unlock(&print_mutex); -} diff --git a/tests/rlookup/GNUmakefile b/tests/rlookup/GNUmakefile deleted file mode 100644 index e35d47b..0000000 --- a/tests/rlookup/GNUmakefile +++ /dev/null @@ -1,22 +0,0 @@ -# $Id: GNUmakefile,v 1.1 2007/03/01 03:51:20 mmondor Exp $ - -MMLIB_PATH := ../../mmlib - -MMLIBS := $(addprefix ${MMLIB_PATH}/,mmpool.o mmhash.o mmarch.o mmstring.o mmlog.o) -LIBS := -lc -OBJS := rlc.o main.o -CFLAGS += -Wall -g -DDEBUG -BINS := test - -all: $(BINS) - -%.o: %.c - cc -c ${CFLAGS} -I. -I${MMLIB_PATH} -o $@ $< - - -test: $(MMLIBS) $(OBJS) - cc -o $@ $(MMLIBS) $(OBJS) $(LIBS) - - -clean: - rm -f $(BINS) $(OBJS) $(MMLIBS) diff --git a/tests/rlookup/main.c b/tests/rlookup/main.c deleted file mode 100644 index 7e96976..0000000 --- a/tests/rlookup/main.c +++ /dev/null @@ -1,68 +0,0 @@ -/* $Id: main.c,v 1.2 2007/03/01 11:18:01 mmondor Exp $ */ - -/* - * Copyright (c) 2007, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -/* - * Headers - */ - -#include -#include -#include - -#include - - - -#define PATH "/nfs/hal/usr/pkgsrc" - - - -int main(void); - - - -int -main(void) -{ - unsigned long long l1, l2; - int i; - - (void) printf("Initializing\n"); - if (rlc_init() == -1) - exit(EXIT_FAILURE); - - (void) printf("Adding\n"); - if (rlc_device_add(PATH) == -1) - exit(EXIT_FAILURE); - - (void) printf("Query testing\n"); - while ((i = scanf("%llu,%llu", &l1, &l2)) != EOF) { - rlc_results_t *r; - - if (i != 2) { - (void) printf("Format: dev_t, ino_t\n"); - (void) fpurge(stdin); - continue; - } - if ((r = rlc_lookup((dev_t)l1, (ino_t)l2)) != NULL) { - for (i = 0; i < r->results; i++) - (void) printf(" -> %s\n", r->result[i]); - rlc_free_results(r); - } else - (void) printf("No match\n"); - } - - (void) printf("Removing\n"); - if (rlc_device_rem(PATH) == -1) - exit(EXIT_FAILURE); - - (void) printf("Done, exiting\n"); - rlc_exit(); - exit(EXIT_SUCCESS); -} diff --git a/tests/rlookup/rlc.c b/tests/rlookup/rlc.c deleted file mode 100644 index 83e1a61..0000000 --- a/tests/rlookup/rlc.c +++ /dev/null @@ -1,619 +0,0 @@ -/* $Id: rlc.c,v 1.2 2007/03/01 11:18:01 mmondor Exp $ */ - -/* - * Copyright (c) 2007, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * TODO: - * - We should scan all currently mounted file systems and obtain their dev_t - * getvfsstat(2) could be used for this. - * - We should obtain the base path name for a mounted file system. - * - We should verify if the dev_t is the same when a new mountpoint is - * created for a new file system (when we get notified by mount). - * - We should be able to monitor mount/unmount operations as well as - * obtain lookup requests easily via a library. Possibly via kqueue or - * another such mechanism. - * - We also should be able to obtain all modification events for a monitored - * file system via similar kernel notification. While we're initially - * scanning we should be able to catch those events to apply them to your - * table once we complete scanning. - * - How should we process rename events? We would need to be provided both - * original and target paths, or we wouldn't be able to process them. - * I'm not sure if kqueue can provide that much information in its current - * form. - * - Verify how ifwatchd(8) obtains its notifications. Verify how usb - * attach/detach events are sent to userland as well. If those all use - * different systems, verify if kqueue couldn't be improved to support all - * of this or if a new unified notification system should be developped. - * - A form of compression could be used so that path names compress very - * well in memory rather than storing full pathnames (despite the fact that - * we only store the upto-mountpoint path once per dnode). - * A per-path element tree-based compression system would be great. - */ - -/* - * NOTES: - * - This test program implements a userspace inode to path lookup daemon. - * - No pool really requires constructor/destructor support because we really - * want to free all resources associated with an object when freeing it, - * and that other than memory resources there are no heavy passes other than - * at rlc_dnode_t creation which cannot be re-used by other instantiations. - * - We currently use an rlc_inode_t memory pool per rlc_dnode_t object. - * The intent is to make possible using a slave process per dev_t, such that - * adding a new file system to monitor (which requires heavy disk I/O) does - * not prevent quickly resolving requests for inodes on other file systems. - * Alternatively, a thread could be used per file system, but sharing the - * pool would still require synchronization (and locality of information - * would be less likely for batch lookup requests for a file system). - * This remains questionable as path names currently still use malloc/free - * but would need a variable allocation dnode specific heap allocator to - * achieve data locality. - * - Ultimately it would be great if the information could be snapshot to - * disk in order to speed up re-mounting with inode lookup support. - * However, this would also require this system to be started after mounting - * a filesystem before any modification events are able to occur, which - * would require kernel modifications. fsck(8) would also need to be aware - * of the system. We don't care about this for now. - * - We probably could have used a list_t instead of a hashtable_t to store - * multiple matching paths for an inode. Since no two identical paths - * should be returned for an inode, it would be safe and slightly faster for - * the initial directory scanning. The hash table may however enhance the - * speed of rename events related lookups eventually. - */ - - - -/* - * Headers - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - - - -/* - * Definitions - */ - -/* Tweak for performance testing */ -#define DNODE_MAX 32 -#define DNODE_BUCKETS 8 -#define PNODE_BUCKETS 8 - -/* Node for a device (dev_t) */ -typedef struct rlc_dnode { - hashnode_t node; - dev_t device; /* Key */ - pool_t inode_pool; - hashtable_t inode_table; - char *mountpoint; -} rlc_dnode_t; - -/* Node for an inode (ino_t) */ -typedef struct rlc_inode { - hashnode_t node; - ino_t inode; /* Key */ - nlink_t links; - hashtable_t pnode_table; - list_t pnode_buckets[PNODE_BUCKETS]; -} rlc_inode_t; - -/* Node for a path node (string) */ -typedef struct rlc_pnode { - hashnode_t node; - char path[1]; /* Key */ -} rlc_pnode_t; - -struct rlc_pnode_lookup_iterator_udata { - const char *mountpoint; - char **array; - int idx, error; -}; - - - -/* - * Static prototypes - */ - -static int rlc_dnode_cmp(const void *, const void *, size_t); -static u_int32_t rlc_dnode_hash(const void *, size_t); -static rlc_dnode_t *rlc_dnode_alloc(dev_t, const char *); -static void rlc_dnode_free(rlc_dnode_t *); -static bool rlc_dnode_free_iterator(hashnode_t *, void *); -static int rlc_dnode_populate(rlc_dnode_t *, const char *); - -static int rlc_inode_cmp(const void *, const void *, size_t); -static u_int32_t rlc_inode_hash(const void *, size_t); -static rlc_inode_t *rlc_inode_alloc(rlc_dnode_t *, ino_t, nlink_t); -static void rlc_inode_free(rlc_inode_t *); -static bool rlc_inode_free_iterator(hashnode_t *, void *); - -static rlc_pnode_t *rlc_pnode_alloc(size_t); -static void rlc_pnode_free(rlc_pnode_t *); -static bool rlc_pnode_free_iterator(hashnode_t *, void *); -static bool rlc_pnode_lookup_iterator(hashnode_t *, void *); - -static dev_t rlc_mp_dev(const char *); - - - -/* - * Static globals - */ - -static int rlc_initialized = 0; -static pool_t rlc_dnode_pool; -static hashtable_t rlc_dnode_table; - - - -/* - * Static functions - */ - -/* ARGSUSED */ -static int -rlc_dnode_cmp(const void *from, const void *to, size_t size) -{ - - assert(from != NULL && to != NULL); - - if (*(dev_t *)from == *(dev_t *)to) - return 0; - - return -1; -} - -/* ARGSUSED */ -static u_int32_t -rlc_dnode_hash(const void *key, size_t size) -{ - - assert(key != NULL); - - return (*(dev_t *)key & 0xffffffff); -} - -static rlc_dnode_t * -rlc_dnode_alloc(dev_t dev, const char *mp) -{ - rlc_dnode_t *dn; - - assert(mp != NULL); - - /* XXX Would need synchronization if shared */ - if ((dn = (rlc_dnode_t *)pool_alloc(&rlc_dnode_pool, FALSE)) == NULL) - goto err; - dn->device = dev; - - if (!pool_init(&dn->inode_pool, "inode_pool", malloc, free, NULL, - NULL, sizeof(rlc_dnode_t), 65536 / sizeof(rlc_dnode_t), 0, 0)) - goto err; - - if (!hashtable_init(&dn->inode_table, "inode_table", - HT_DEFAULT_CAPACITY, HT_DEFAULT_FACTOR, malloc, free, - rlc_inode_cmp, rlc_inode_hash, TRUE)) - goto err; - - /* XXX Assumes that mountpoint is sanity-checked without trailing / */ - if ((dn->mountpoint = strdup(mp)) == NULL) - goto err; - - return dn; - -err: - if (dn != NULL) { - if (HASHTABLE_VALID(&dn->inode_table)) - hashtable_destroy(&dn->inode_table, FALSE); - if (POOL_VALID(&dn->inode_pool)) - (void) pool_destroy(&dn->inode_pool); - if (dn->mountpoint != NULL) - free(dn->mountpoint); - (void) pool_free((pnode_t *)dn); - } - - return NULL; -} - -static void -rlc_dnode_free(rlc_dnode_t *dn) -{ - - assert(PNODE_VALID((pnode_t *)dn)); - - free(dn->mountpoint); - hashtable_iterate(&dn->inode_table, rlc_inode_free_iterator, NULL); - hashtable_destroy(&dn->inode_table, FALSE); - (void) pool_destroy(&dn->inode_pool); - - (void) pool_free((pnode_t *)dn); -} - -/* ARGSUSED */ -static bool -rlc_dnode_free_iterator(hashnode_t *nod, void *udata) -{ - - rlc_dnode_free((rlc_dnode_t *)nod); - - return TRUE; -} - -static int -rlc_dnode_populate(rlc_dnode_t *dn, const char *root) -{ - static char path[PATH_MAX + 1]; - static rlc_inode_t *in; - static rlc_pnode_t *pn; - static struct dirent ent, *entp; - static struct stat st; - - char *dpath = NULL; - DIR *dir; - int i; - - in = NULL; - pn = NULL; - (void) snprintf(path, PATH_MAX, "%s/%s", dn->mountpoint, root); - if ((dir = opendir(path)) == NULL) - goto err; - - while ((i = readdir_r(dir, &ent, &entp)) == 0 && entp != NULL) { - if ((ent.d_name[0] == '.' && ent.d_name[1] == '\0') || - (ent.d_name[0] == '.' && ent.d_name[1] == '.' && - ent.d_name[2] == '\0')) - continue; - - (void) snprintf(path, PATH_MAX, "%s/%s/%s", dn->mountpoint, - root, ent.d_name); - if (lstat(path, &st) != 0) - goto err; - if (st.st_dev != dn->device || st.st_nlink == 0) - continue; - - if ((in = rlc_inode_alloc(dn, st.st_ino, st.st_nlink)) == NULL) - goto err; - if (!hashtable_link(&dn->inode_table, (hashnode_t *)in, - &in->inode, sizeof(ino_t), FALSE)) - goto err; - i = snprintf(path, PATH_MAX, "%s/%s", root, ent.d_name); - if ((pn = rlc_pnode_alloc(i)) == NULL) - goto err; - (void) strncpy(pn->path, path, i); - /* Fixed table, will succeed */ - (void) hashtable_link(&in->pnode_table, (hashnode_t *)pn, - pn->path, i, FALSE); - pn = NULL; - in = NULL; - - /* Recurse into subdirectories */ - if ((st.st_mode & S_IFMT) == S_IFDIR) { - if ((dpath = strdup(path)) == NULL) - goto err; - i = rlc_dnode_populate(dn, dpath); - free(dpath); - if (i != 0) - goto err; - } - } - if (i != 0) - goto err; - - (void) closedir(dir); - return 0; - -err: - if (pn != NULL) - rlc_pnode_free(pn); - if (in != NULL) - rlc_inode_free(in); - if (dir != NULL) - (void) closedir(dir); - return -1; -} - -/* ARGSUSED */ -static int -rlc_inode_cmp(const void *from, const void *to, size_t size) -{ - - assert(from != NULL && to != NULL); - - if (*(ino_t *)from == *(ino_t *)to) - return 0; - - return -1; -} - -/* ARGSUSED */ -static u_int32_t -rlc_inode_hash(const void *key, size_t size) -{ - - assert(key != NULL); - - return (*(ino_t *)key & 0xffffffff); -} - -static rlc_inode_t * -rlc_inode_alloc(rlc_dnode_t *dn, ino_t inode, nlink_t links) -{ - rlc_inode_t *in; - - if ((in = (rlc_inode_t *)pool_alloc(&dn->inode_pool, FALSE)) == NULL) - return in; - - in->inode = inode; - in->links = links; - hashtable_init2(&in->pnode_table, "pnode_table", in->pnode_buckets, - PNODE_BUCKETS, rlc_inode_cmp, rlc_inode_hash); - - return in; -} - -static void -rlc_inode_free(rlc_inode_t *in) -{ - - assert(PNODE_VALID((pnode_t *)in)); - - hashtable_iterate(&in->pnode_table, rlc_pnode_free_iterator, NULL); - (void) pool_free((pnode_t *)in); -} - -/* ARGSUSED */ -static bool -rlc_inode_free_iterator(hashnode_t *nod, void *udata) -{ - - rlc_inode_free((rlc_inode_t *)nod); - - return TRUE; -} - -static rlc_pnode_t * -rlc_pnode_alloc(size_t size) -{ - - return malloc(sizeof(rlc_pnode_t) + size); -} - -static void -rlc_pnode_free(rlc_pnode_t *pn) -{ - - assert(pn != NULL); - - free(pn); -} - -/* ARGSUSED */ -static bool -rlc_pnode_free_iterator(hashnode_t *nod, void *udata) -{ - - rlc_pnode_free((rlc_pnode_t *)nod); - - return TRUE; -} - -static bool -rlc_pnode_lookup_iterator(hashnode_t *nod, void *udata) -{ - rlc_pnode_t *pn = (rlc_pnode_t *)nod; - struct rlc_pnode_lookup_iterator_udata *ud = udata; - /* XXX Uses a lot of stack */ - char path[PATH_MAX + 1]; - - /* - * We actually could provide direct pointers to mountpoint and - * path component for performance in our current case, but IPC - * requests will need to be provided with actual full paths... - */ - path[PATH_MAX] = '\0'; - (void) snprintf(path, PATH_MAX, "%s/%s", ud->mountpoint, pn->path); - if ((ud->array[ud->idx++] = strdup(path)) == NULL) { - ud->error = 1; - return FALSE; - } - - return TRUE; -} - -static dev_t -rlc_mp_dev(const char *mp) -{ - struct stat st; - - if (lstat(mp, &st) == -1 || ((st.st_mode & S_IFMT) & S_IFDIR) != 0) - return st.st_dev; - - return -1; -} - - - -/* - * Public functions - */ - -int -rlc_init(void) -{ - - assert(!rlc_initialized); - - /* - * XXX Needs to use shared memory allocator if using processes. - * Could be dynamically resizeable otherwise, but would then require - * synchronization with threads. - */ - if (!pool_init(&rlc_dnode_pool, "dnode_pool", malloc, free, NULL, - NULL, sizeof(rlc_dnode_t), DNODE_MAX, 1, 1)) - goto err; - if (!hashtable_init(&rlc_dnode_table, "dnode_table", - DNODE_BUCKETS, HT_DEFAULT_FACTOR, malloc, free, rlc_dnode_cmp, - rlc_dnode_hash, FALSE)) - goto err; - - /* XXX */ - - rlc_initialized = 1; - return 0; - -err: - if (POOL_VALID(&rlc_dnode_pool)) - (void) pool_destroy(&rlc_dnode_pool); - - return -1; -} - -void -rlc_exit(void) -{ - - assert(rlc_initialized); - - hashtable_iterate(&rlc_dnode_table, rlc_dnode_free_iterator, NULL); - hashtable_destroy(&rlc_dnode_table, FALSE); - (void) pool_destroy(&rlc_dnode_pool); -} - -/* - * XXX The two following functions may eventually require synchronization. - * Moreover, since they can be expensive, it might be best to do it with - * asynchroneous notification in another thread or process. - */ - -int -rlc_device_add(const char *mp) -{ - dev_t dev; - rlc_dnode_t *dn = NULL; - - assert(mp != NULL); - - if ((dev = rlc_mp_dev(mp)) == -1) - goto err; - if ((dn = (rlc_dnode_t *)hashtable_lookup(&rlc_dnode_table, &dev, - sizeof(dev_t))) != NULL) - goto err; - - /* XXX Assumes path is sanity checked with no trailing / */ - if ((dn = rlc_dnode_alloc(dev, mp)) == NULL) - goto err; - if (rlc_dnode_populate(dn, "/") != 0) - goto err; - if (!hashtable_link(&rlc_dnode_table, (hashnode_t *)dn, &dn->device, - sizeof(dev_t), FALSE)) - goto err; - - /* XXX */ (void) printf("Added device: %llu (%llu entries)\n", - (unsigned long long)dev, - (unsigned long long)HASHTABLE_NODES(&dn->inode_table)); - return 0; - -err: - if (dn != NULL) - rlc_dnode_free(dn); - - return -1; -} - -int -rlc_device_rem(const char *mp) -{ - dev_t dev; - rlc_dnode_t *dn; - - if ((dev = rlc_mp_dev(mp)) != -1 && (dn = (rlc_dnode_t *)hashtable_lookup( - &rlc_dnode_table, &dev, sizeof(dev_t))) != NULL && - strcmp(mp, dn->mountpoint) == 0) { - hashtable_unlink(&rlc_dnode_table, (hashnode_t *)dn); - rlc_dnode_free(dn); - - return 0; - } - - return -1; -} - -rlc_results_t * -rlc_lookup(dev_t dev, ino_t inode) -{ - rlc_results_t *r; - rlc_dnode_t *dn; - rlc_inode_t *in; - int results, i; - struct rlc_pnode_lookup_iterator_udata udata; - - /* First lookup for dnode */ - /* XXX would need synchronization */ - if ((dn = (rlc_dnode_t *)hashtable_lookup(&rlc_dnode_table, &dev, - sizeof(dev_t))) == NULL) - return NULL; - - /* Now lookup for inode within dnode */ - if ((in = (rlc_inode_t *)hashtable_lookup(&dn->inode_table, &inode, - sizeof(ino_t))) == NULL) - return NULL; - results = (int)HASHTABLE_NODES(&in->pnode_table); - - /* Found, create results object */ - if ((r = malloc(sizeof(rlc_results_t) + (sizeof(char *) * results))) == - NULL) - return NULL; - r->results = results; - udata.mountpoint = dn->mountpoint; - udata.array = r->result; - udata.idx = 0; - udata.error = 0; - for (i = 0; i < r->results; i++) - r->result[i] = NULL; - hashtable_iterate(&in->pnode_table, rlc_pnode_lookup_iterator, - &udata); - - if (udata.error) { - for (i = 0; i < r->results; i++) { - if (r->result[i] != NULL) - free(r->result[i]); - } - free(r); - r = NULL; - } - - return r; -} - -void -rlc_free_results(rlc_results_t *r) -{ - int i; - - assert(r != NULL); - - for (i = 0; i < r->results; i++) { - assert(r->result[i] != NULL); - free(r->result[i]); - } - free(r); -} diff --git a/tests/rlookup/rlc.h b/tests/rlookup/rlc.h deleted file mode 100644 index 88bea62..0000000 --- a/tests/rlookup/rlc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id: rlc.h,v 1.1 2007/03/01 03:51:20 mmondor Exp $ */ - -/* - * Copyright (c) 2007, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -typedef struct rlc_results { - int results; - char *result[1]; -} rlc_results_t; - - - -int rlc_init(void); -void rlc_exit(void); -int rlc_device_add(const char *); -int rlc_device_rem(const char *); - -/* - * XXX Public for now, but would be static with a lib using IPC to the daemon - * instead. - */ -rlc_results_t *rlc_lookup(dev_t, ino_t); -void rlc_free_results(rlc_results_t *); diff --git a/tests/rotate/GNUmakefile b/tests/rotate/GNUmakefile deleted file mode 100644 index 41ca002..0000000 --- a/tests/rotate/GNUmakefile +++ /dev/null @@ -1,57 +0,0 @@ -# $Id: GNUmakefile,v 1.2 2006/05/06 12:25:02 mmondor Exp $ - -CC := cc -RM := rm -UNAME := uname - -CFLAGS += -Wall - -# Enable for verbosity/debugging -#CFLAGS += -v -H -g -#LDFLAGS += -v -g - -# And to disable assertions -CFLAGS += -DNDEBUG - -OBJS := main.o -BINS := rotate -CBINS := $(addsuffix .exe,$(BINS)) - -SDL_CFLAGS := $(shell sdl-config --cflags) -SDL_LDFLAGS := $(shell sdl-config --libs) -SDL_LDFLAGS += -lSDL_gfx - -# OS dependent settings follow -OS := $(shell $(UNAME) -s) -ifneq (,$(findstring CYGWIN,$(OS))) - # cygwin-mingw - CFLAGS += -mno-cygwin -I/usr/include/mingw - LDFLAGS += -mwindows -mno-cygwin -L/usr/lib/mingw -L/usr/local/lib -# GL_CFLAGS := -# GL_LDFLAGS := -lopengl32 -lglu32 -else - # unix - CFLAGS += -I/usr/include -I/usr/pkg/include -I/usr/X11R6/include - LDFLAGS += -L/usr/lib -L/usr/pkg/lib -L/usr/X11R6/lib -# GL_CFLAGS := -# GL_LDFLAGS := -lGL -lGLU -endif - -#CFLAGS += $(SDL_CFLAGS) $(GL_CFLAGS) -#LDFLAGS += $(SDL_LDFLAGS) $(GL_LDFLAGS) -CFLAGS += $(SDL_CFLAGS) -LDFLAGS += $(SDL_LDFLAGS) - -all: $(BINS) - -%.o: %.c - $(CC) -c $(CFLAGS) -I. -o $@ $< - -#$(BINS): $(OBJS) -# $(CC) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) - -$(BINS): $(OBJS) - $(CC) -o $@ $(OBJS) $(LDFLAGS) - -clean: - $(RM) -f $(BINS) $(CBINS) $(OBJS) stdout.txt stderr.txt diff --git a/tests/rotate/main.c b/tests/rotate/main.c deleted file mode 100644 index b2ed875..0000000 --- a/tests/rotate/main.c +++ /dev/null @@ -1,195 +0,0 @@ -/* $Id: main.c,v 1.1 2006/05/06 12:25:02 mmondor Exp $ */ - -/* - * Copyright (C) 2006, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include -#include -#include - -#include -#include -#include - - - -int main(int, char **); - - - -static SDL_Surface *screen_surface; - - - -int -main(int argc, char **argv) -{ - SDL_Surface *s, *save; - int a, ad, at; - size_t fnlen; - char *fnbuf, *file; - - if (argc != 3) { - (void) fprintf(stderr, "Usage: rotate \"\" \n"); - exit(EXIT_FAILURE); - } - - if ((file = strdup(argv[1])) != NULL) { - char *cptr; - - if ((cptr = strrchr(file, '.')) != NULL) - *cptr = '\0'; - } else { - (void) fprintf(stderr, "strdup(%s)\n", argv[1]); - exit(EXIT_FAILURE); - } - - fnlen = strlen(file) + 16; - if ((fnbuf = malloc(fnlen)) == NULL) { - (void) fprintf(stderr, "fnbuf = malloc(%d)\n", (int)fnlen + 8); - exit(EXIT_FAILURE); - } - - at = (double)strtol(argv[2], NULL, 10); - ad = (360 / at); - if (at * ad != 360) { - (void) fprintf(stderr, " must be a divisor of 360\n"); - exit(EXIT_FAILURE); - } - - if (SDL_Init(SDL_INIT_VIDEO) == -1) { - (void) fprintf(stderr, "SDL_Init() - %s\n", SDL_GetError()); - exit(EXIT_FAILURE); - } - if ((screen_surface = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF)) - == NULL) { - (void) fprintf(stderr, "SDL_SetVideoMode() - %s\n", - SDL_GetError()); - goto err; - } - - if ((s = SDL_LoadBMP(argv[1])) == NULL) { - (void) fprintf(stderr, "SDL_LoadBMP(%s) - %s", - argv[1], SDL_GetError()); - goto err; - } - if ((save = SDL_CreateRGBSurface(SDL_SWSURFACE, s->w, s->h, 32, - s->format->Rmask, s->format->Gmask, s->format->Bmask, - s->format->Amask)) == NULL) { - (void) fprintf(stderr, "SDL_CreateRGBSurface() - %s\n", - SDL_GetError()); - goto err; - } - - /* - * XXX Assumes 0x000000 is the trasparent color, should probably be - * part of the command line parameters. - */ - { - Uint32 col; - - col = SDL_MapRGB(s->format, 0x00, 0x00, 0x00); - if (SDL_SetColorKey(s, SDL_SRCCOLORKEY, col) == -1) { - (void) fprintf(stderr, "SDL_SetColorKey() - %s\n", - SDL_GetError()); - goto err; - } - } - - for (a = 0; a < 360; a += ad) { - SDL_Surface *t; - SDL_Rect d; - int cx, cy, c; - - cx = s->w / 2; - cy = s->h / 2; - c = (cx >= cy ? cx : cy); - - /* - * XXX Again assumes that 0x000000 color is transparent. - * Moreover, in a future version, we also could allow to scale - * the bitmap image as wanted... - */ - if (boxRGBA(save, 0, 0, s->w - 1, s->h - 1, - 0x00, 0x00, 0x00, 0xff) != 0 || - boxRGBA(screen_surface, 320 - c, 240 - c, 320 + c, 240 + c, - 0x00, 0x00, 0x00, 0xff) != 0) { - (void) fprintf(stderr, "boxRGBA() - %s\n", - SDL_GetError()); - goto err; - } - - if ((t = rotozoomSurface(s, (double)-a, 1.0, 1)) == NULL) { - (void) fprintf(stderr, "rotozoomSurface() - %s\n", - SDL_GetError()); - goto err; - } - d = (SDL_Rect){320 - (t->w / 2), 240 - (t->h / 2), 0, 0}; - if (SDL_BlitSurface(t, NULL, screen_surface, &d) != 0) { - (void) fprintf(stderr, "SDL_BlitSurface() - %s\n", - SDL_GetError()); - goto err; - } - SDL_FreeSurface(t); - - d = (SDL_Rect){320 - c, 240 - c, 320 + c, 240 + c}; - if (SDL_BlitSurface(screen_surface, &d, save, NULL) != 0) { - (void) fprintf(stderr, "SDL_BlitSurface() - %s\n", - SDL_GetError()); - goto err; - } - (void) snprintf(fnbuf, fnlen - 1, "%s-%03d.bmp", file, (int)a); - if (SDL_SaveBMP(save, fnbuf) != 0) { - (void) fprintf(stderr, "SDL_SaveBMP(%s) - %s\n", - fnbuf, SDL_GetError()); - goto err; - } - - if (SDL_Flip(screen_surface) != 0) { - (void) fprintf(stderr, "SDL_Flip() - %s", - SDL_GetError()); - goto err; - } - } - - SDL_Quit(); - exit(EXIT_SUCCESS); - -err: - SDL_Quit(); - exit(EXIT_FAILURE); -} diff --git a/tests/sdl-client/GNUmakefile b/tests/sdl-client/GNUmakefile deleted file mode 100644 index e316dd3..0000000 --- a/tests/sdl-client/GNUmakefile +++ /dev/null @@ -1,90 +0,0 @@ -# $Id: GNUmakefile,v 1.31 2006/05/23 01:32:50 mmondor Exp $ - -CC := cc -RM := rm -UNAME := uname -TOUCH := touch -OBJDUMP := objdump -OBJCOPY := objcopy -GREP := grep -AWK := awk -DATE := date -STRIP := strip - -TMPDIR := /tmp - -CFLAGS += -Wall - -# Enable for verbosity/debugging -#CFLAGS += -v -H -g -#LDFLAGS += -v -g - -# And to disable assertions -CFLAGS += -DNDEBUG -CFLAGS += -g - -OBJS := main.o debug.o pool.o thread_msg.o thread_net_recv.o \ - thread_net_send.o screen.o decode.o -BINS := client -CBINS := $(addsuffix .exe,$(BINS)) -RAWOBJS := bmp/RomDD.bmp.enc.o bmp/FedCA.bmp.enc.o wav/nt_cloaked.wav.enc.o \ - wav/nt_uncloak.wav.enc.o wav/nt_shield_up.wav.enc.o \ - wav/nt_shield_down.wav.enc.o wav/nt_fire_torp_other.wav.enc.o \ - wav/nt_plasma_hit.wav.enc.o wav/nt_explosion_other.wav.enc.o \ - fnt/7x13.fnt.enc.o - -SDL_CFLAGS := $(shell sdl-config --cflags) -SDL_LDFLAGS := $(shell sdl-config --libs) -SDL_LDFLAGS += -lSDL_image -lSDL_mixer -lSDL_net -lSDL_gfx - -# OS dependent settings follow -OS := $(shell $(UNAME) -s) -ifneq (,$(findstring CYGWIN,$(OS))) - # cygwin-mingw - CFLAGS += -mno-cygwin -I/usr/include/mingw -DWIN32 - LDFLAGS += -mwindows -mno-cygwin -L/usr/lib/mingw -L/usr/local/lib -# GL_CFLAGS := -# GL_LDFLAGS := -lopengl32 -lglu32 -else - # unix - CFLAGS += -I/usr/include -I/usr/pkg/include -I/usr/X11R6/include - LDFLAGS += -L/usr/lib -L/usr/pkg/lib -L/usr/X11R6/lib -# GL_CFLAGS := -# GL_LDFLAGS := -lGL -lGLU -endif - -# Determine target of compiled objects so that we may convert binaries -# to compatible objects using objcopy and then link them like other modules. -OBJTARGET := $(shell $(TOUCH) $(TMPDIR)/obj.c && \ - $(CC) $(CFLAGS) -c -o $(TMPDIR)/obj.o $(TMPDIR)/obj.c && \ - $(OBJDUMP) -t $(TMPDIR)/obj.o | \ - $(GREP) 'file format' | $(AWK) '{print $$4}' \ - && $(RM) $(TMPDIR)/obj.o $(TMPDIR)/obj.c) -OBJARCH := $(shell echo $(OBJTARGET) | $(AWK) -F '-' '{print $$2}') -SEED := $(shell date +%s) - -#CFLAGS += $(SDL_CFLAGS) $(GL_CFLAGS) -#LDFLAGS += $(SDL_LDFLAGS) $(GL_LDFLAGS) -CFLAGS += $(SDL_CFLAGS) -LDFLAGS += $(SDL_LDFLAGS) - -all: $(BINS) - -%.o: %.c - $(CC) -c $(CFLAGS) -I. -o $@ $< - -encode: - $(CC) -o encode encode.c - -$(RAWOBJS): encode - ./encode $(basename $(basename $@)) $(basename $@) $(SEED) - $(OBJCOPY) -I binary -B $(OBJARCH) -O $(OBJTARGET) $(basename $@) $@ - $(RM) -f $(basename $@) - -$(BINS): $(OBJS) $(RAWOBJS) - $(CC) -o $@ $(OBJS) $(RAWOBJS) $(LDFLAGS) - $(STRIP) -s -w -R .comment -R .ident -R .debug* $@* - -clean: - $(RM) -f $(BINS) $(CBINS) $(OBJS) $(RAWOBJS) encode encode.exe \ - stdout.txt stderr.txt diff --git a/tests/sdl-client/README b/tests/sdl-client/README deleted file mode 100644 index 222484f..0000000 --- a/tests/sdl-client/README +++ /dev/null @@ -1,190 +0,0 @@ -$Id: README,v 1.16 2006/05/23 01:32:50 mmondor Exp $ - -An attempt to develop a portable game client using SDL among unix -and windows operating systems. The only officially supported -compiler should be GCC (and mingw under windows, avoiding the need -for cygwin libraries). The compiling/development environment when -under windows will use cygwin to provide a shell, vim and cvs, -while compile options will be specified as needed for it to use -the mingw compiler (which also comes as part of cygwin). - -Initial tests will be using SDL, SDL_mixer and SDL_net. - -If all works well, it should also be easy to use OpenGL portably. -I was already able to get portable SDL/OpenGL code working, a while -ago, but this generated no sound and had no network requirements. -Hence this test. - -Moreover, the test server under kqueue/ needed a client for further -testing to be possible at its development stage. - -Since SDL_net does not provide non-blocking I/O (and it remains -unclear if windows supports this properly), a decision was made to -port to SDL an inter-thread messaging library I had done for use -with POSIX threads, and to use multiple threads. - -One thread will be used to send data to the server, another thread -to receive data form the server, yet another thread to deal with -all user input events, and a main thread to receive all those events -in an asynchroneous manner form the utility threads and run the -main loop. - -04:21 <@lucca> one thread to send, one thread to receive, one thread to poll - for io events, and one thread to bring them all and in the darkness - bind them. - -:) - -Ogg-vorbis will be used for music, using SDL_mixer. Ship rotations -will be performed using SDL_gfx. - -It is very important to avoid having to link this client statically -against GPL or LGPL libraries, because of the viral nature of those -licenses. I do not intend to release my code under those licenses. -If it ever publically is released, it shall be done under a MIT/BSD -derived license. - -I am also thinking about dedicating a thread for the connect state -to the server, or possibly to have the writer or reader thread also -perform that task. - -It is possible that a thread be ideal for rendering as well. It -could be notified when a screen refresh is wanted, when it could -set a flag. When it's time for it to draw a frame (honoring FPS), -it would if the flag is set, or perhaps it simply could when it -wants. I wonder if it would be appropriate for the display thread -to not need a mutex, since it would always be read-only accessing -the data. - -Anticipated design so far: - Main thread - User events thread - Network receive thread - Network Send/Connect thread - Display thread (the Receive thread will draw for now). - -It is possible that states may be desired. For instance, there -would be the connection state, the one where the user and client -have to provide authentication information (this could be part of -connect phase perhaps), and in-game state. - -At first, as a test, the world will all be seen by everyone and -will fit into their screen. A world of 1024x768 could be used for -this :) Then there will probably be addition of a chat system with -messages window, to continue enhancing the protocol. Things will -go on from there... - -Hmm for now I want to simply use a joypad. -- Button 0 fires in direction of the paddle direction. -- Buttons 1 and 3 could act like button 0, to provide secondary weapon (1) - and special weapon (3). -- Button 2 attempts to correct navigation direction in the direction - of the paddle. -- Button 6 would accelerate. -- Button 7 would decelerate. -- Button 4 could toggle shields -- Button 5 could toggle cloak - -Equivalent keyboard layout: -- uiojlm,. would change angle just like the gamepad directions. -- w would toggle cloak -- s would toggle shield -- z would thrust up -- a would thrust down -- d would cause direction change -- space would torp -- f would fire second weapon -- g would fire special weapon - -And we're already out of buttons, we can't beam up/down armies or -bomb. Unless button 3 was special instead of a special weapon, -and allowed to perform various commands depending on the paddle -direction (i.e. up/down to beam up/down, left to bomb). This also -means that orbiting/launching would need to be automatic. Of course -all this is if we're thinking about a game like netrek. But we'll -simply only allow dogfighting at first. - -Now it becomes tricky how I'll minimize bandwidth sent from the -client to the server. Probably that buttons events will be monitored, -and then current paddle direction when required. In the case of -direction change button, the last paddle direction applied would -be remembered, and if the same, the event could be dropped. If -not, send a direction change packet. What happens if a button -remains pressed while a direction change occurs? We probably should -ignore it. - - -Threading limitations under win32 -================================= - -There seem to be bugs when using SDL with multiple threads under windows -which I did not observe on unix systems. The docs specify that the main -thread should perform the drawing, but it wasn't specified that another -thread than the initial one would not be able to obtain all user input -events on windows. Typed keys would not be received, for instance. - -It then appears that most of the processing must be done in the main -initial thread, while only networking related blocking functions will -be done in slave threads. - -There also seem to be other windows-specific problems using SDL threads, -such as instability. I have noticed that when using another thread -for user events reception, part of the application would often lockup, -despite my code properly using mutexes as required, and all sound and -greaphics being performed by the main initial thread nevertheless. -These problems were also not found to occur on unix systems. - -The design was thus changed for now, and threads will be used for SDL_net -functions only, since they are blocking. Let's hope that this will work -stably, however. It remains to be tested. - - -Storing images and sound samples as part of the executable binary -================================================================= - -I was able to include read-only (.rodata) and read-write (.data) into -binaries directly from files using objcopy and linking them on NetBSD, -Linux and cygwin-mingw. The SDL_image library, which I now successfully -built for mingw, includes functions that can use RWops, and the SDL -library allows to easily create RWops from memory buffers. Moreover, the -SDL_mixer library also allows to do this to load sound samples. I should -thus modify the makefiles and code to very easily use these features. - -The SDL_mixer library however does not allow by itself to do this easily -with music files. However, thise generally being considerably larger, -it should not be a problem and they can remain external. - -If this works fine, it would be easy to generate a cryptographic block -cipher key at build time and to include that key within the executable -as well. Copies of the binary files to be included could then be -encrypted using that cipher to a temporary copy which will be linked -in, and an initialization function could be provided to unencrypt the -files prior to use. Of course, since the key is also in the executable, -there is no real security. However, it could prevent computer-illiterate -people from too easily ripping our original content. RC4 could be used -for this for instance, or even a much more simple custom encoding -algorithm :) - - -Using a map -=========== - -We probably want to randomize the ship's positions on the map. -Randomization in this respect could be done on a position in a -circle of varied radius distance to the location of the actual -ship. This would prevent clients from being able to exactly fire -at the actual ship position using the map (which also would make -cloaking useful against an unofficial client). - - -PROGRAMMING STYLE -================= - -The style chosen for this project consists of the (Net)BSD KNF style -(Kernel Normal Form) style borrowed from. All code should conform to it. -Additionally, lint(1)-style comments are used to make the code clearer -for future code auditors. - - - -Matt diff --git a/tests/sdl-client/bmp/FedCA.bmp b/tests/sdl-client/bmp/FedCA.bmp deleted file mode 100644 index be3a56267b517c13484c6601f95d26989608c14b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4854 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 diff --git a/tests/sdl-client/bmp/fedship.bmp b/tests/sdl-client/bmp/fedship.bmp deleted file mode 100755 index 465806fdf2c5fbb1f9b021b287f87554ace7c012..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103478 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

Uj`^3 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 icQSl8#el))=Ata84~-!jbw1<(uw>O!_$d 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 UWygl@X?bKh5_lD(v)RG^FTEQsqyPW_ diff --git a/tests/sdl-client/bmp/indship.bmp b/tests/sdl-client/bmp/indship.bmp deleted file mode 100755 index 1a7e39b8bcd9a35dbab210a0fb7b8794593e7b44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87098 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

    ^m#*$c2-ijG}lrJuhAnT^m}TF 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 diff --git a/tests/sdl-client/bmp/misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp b/tests/sdl-client/bmp/misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp deleted file mode 100644 index c55b1721534c44ce6deb1a75cadfdce04c6a0fd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3390 zcmeHJ-)kH<5T00MZOGULKMCJ<3#ODl_(5esb-9by^u2v4h2$YrWyo#XJD(kv`~aI( z|HS@B={M5dC1+Za#}+botJSwNl4kVH?&yaf!y#n}XurYrC$7J6J-{yu^jD9{wTB0K zsl0plu5>nSh&n}=cr19_V{w(WI}DCGTDT!^R(9^2d75A==rw(uiae0lbmfQT~Kapbu`I#_xZu-oq*y#Z4*uh zj1NhNm}ApWht8Xa`gD2B$E|iqGWLhnVVe!*3p@;yeY5X~XBQ-onPzl&dplU_+&Rf} zCRdH#bkXp^J-(zJ$Ie=WgytlHIx2 z-0WbcUx_izM)=?@UW672G1=3s;NVinhJ^ec8sa~kSNmsSxktYMzi?+A+v+)tcv+gi)eOo5s8Yw3f7wj z7X)86`~&sF(2K)6Waj$u(f}m78Srw8lbZv-Wqg#WgI>n>*yQo^q26C|8iYcgzgrQ_ z*{?!HkqkMCY@)vGoN>FwHsb~@#TxpLirHG=P(Uf-fWYAZ+nd}2?0-bPVX2dFbVjkj zRjC)K4I6A&`C{iP=tsFzEHztK_!|SunbZwCoB5Qe`{0`j19W?Ie&E))SotlMjB6Uh z7&K(Jddb~zXJjH%2&oIiH!l1>76~jl|p_H&SDPw9ZRnQ|b&A@^$sUuLuRWlz(4m}D@ zS5=6U{TM4`bHl_&W|%ofgAD_nR(vhy2-HhYg!RF5NL6YQj+82&6pyl4;ib$0;mjBM z4#z>wWxhn?7tiO2h+hUjR diff --git a/tests/sdl-client/bmp/misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1.bmp b/tests/sdl-client/bmp/misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1.bmp deleted file mode 100644 index 5c2ab05190944fcd96557fcba456757dcc0f0e3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4862 zcmeH~?~5D98ONXPgq1^9C)z++VOMJ3C9gWlf)W!~XSbn&Lf`aN)4rKSt&YN-NjL~< zx!QZIk>7~KFJ8s3CA@Y2@VTCE*jU@UPzB`pv?!DIj)76Db9P>ye7l|q# zq`ETqR+mcE5yC;LtLi(f12<)#r|iscQnmrRjiZySf&18)WWK*Pc1Z&hD970th7~(( zCzAm}NSYVwYzO_JzeZNCe^YV+r3ZXSBw*<7Nk`k_!ThxQrh}u>dWvPPJRH`-V z1%w%&m)X?J(Sok$a8Xy;vvsRxM3U+%W1TuAWM>+hvfct?Ieq@c0_B{O=Mc*$Fh=X%?eYk@ngBD zH7g)mnst{}n4NwC6ANrvV^RFHni6-z<^|KR2ZrT?v8r*PHV&(8n5~Dhy1-81l2A>z zq)@R7VPLi2Jwqk3{`BYgV}2NxlZ1@ z^}4*=zI;9(6c2x9n6qbnbBr-wdh=d5wti<=F0#4_`g{3}el)gzVi^6%JM6d${Y8pW zJIv7DX$QVi_qvpg3uEE9=e+XO099UNXT{6zW0B1+KC3*-!2c!#igea-c{aeD&E6z5 zXK)zdhjMW#&W(~svf;nC)eE$F)vgy~r*i#9^BDUpD`S2)rb_5Ew@b3Wz;e5x6K^{b zt4rz&JI7*HlD&|$dH1Xr|FK#L^R38}I?C9^rR~A~9+=;qjmz=yg2e^>Rc@r!6YRr` zO;0@T!)arB&hBm6e9{?@Xik6SLWD(8{U=u14tIxRb;-ZoZg>Z4Endtj5BlEOw$gr! z8Y)_AHNfO>)jmyXgP8_H$5duEQGKwLAY;TVKR&@+?ysW;>$dUbJrWiEfN>M``-@A~ zL-p7Dcg-S-)Vf&e6u(L|jQBid@XeT$vU8-stklj-it+gR|HO#Kge|`+{Cs7k6B+rf z!XCM1NLB2t%3eqA`z;5r+LU>Cy+;nTX3tsme!y(IWZMGo0*+G29Rh>aY-|d(VVC93 zV3aZ|%oy(@2rMcU2%>baz&B;AzhY1qEiw47yrb zhK5o`_d=1s1%}U^nAreY+Y(~!L&J93cJXkmFV7i1fs7q%7rtu`VaIvlF_>YD$IQHf zJB@|ny13a#EG4_lF&`o3F!qFr`DyYpecn&_>Ju$)V9HbGlyC2AiSI#d1UIqduo6nP zLvq1Br!m9MKA8N>a?08ENM1)ThX4H$k z>vx?}aS%pgf(L#>xgB^iPbvA0$L+NEMN}4 zakMvX9z&B@97xx2da9zI;HBp5JgR~>ZwjNJAa3j6)MxlKMPo!w&5%U>t(!NntwRb% zgs)S!6Y8y-Z7{nRpsjG&luMd_zlG1$5Vy-=8#_Ny{{nmelSE8-X<^^GR%&LKvfRN1 znYh@hnf^E=+m7nL>KS&t}_r*-p1?O$o#EiDUF)ilarj2LkXBqhaWZ+AA C4jL!` diff --git a/tests/sdl-client/bmp/misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1.bmp b/tests/sdl-client/bmp/misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1.bmp deleted file mode 100644 index e8ac5d4f9acb7587bd21fd2a3fd114d9e6eba41c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3390 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 z 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 diff --git a/tests/sdl-client/bmp/sbexpl.bmp b/tests/sdl-client/bmp/sbexpl.bmp deleted file mode 100755 index b06ffcf99fd8c3a219a6bbd445c4eb1abd60077d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29050 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 i`Ua|EW8?}WU~0XUJ8$PLBP*WY;c4 diff --git a/tests/sdl-client/bmp/shexpl.bmp b/tests/sdl-client/bmp/shexpl.bmp deleted file mode 100755 index 72a62c41fcfaa119067fe52360690784255384ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9832 zcmb`MdvILUeaFu^cO@GPVvVthglz3DknL(@GOi{Va0H8G2aSs3PDiQ6NfB$n!iBi} z;dbQWAXbJ56y%hN2NIr^#lx6%+VxaFd~9x23qB@9$h0 z+CP$+44V1vz4x5+dq3~h(iNSnoc qf?}TMBe~=e(N-Wdqynf`ob==k8GVU6HdY&7AM%EVGI^`N~nR2<+ zz%{^iQ?9Uv>-Ag(f9YJ|2ItNL=2o%WfO8E%{U)xrIoCLlb4@_wCayrk?KyYO9XVIe zbw1E^d)dvuqwJan%kG>z%WeTMe~9aF+2sa++bS;i17Hxi6Zm1p<%cV7#ZM~k&+f0d zZ$D6Ve-3m%Sash9Ry|a8-w`~_J@6L~jkv3}j<_D60$epR;;sgIMtSCX&9-q@869`m z0@rbW9oOq0VeL`Y1dmU-3b5v}DR=#&fbM~{j{rR1@R)NqZg+0&cv?qvMs!M#d{`kMFHqw*3{>$16)mpRcw* zvbTEq=-z7kqrmnTxISN9CU|Ub^_!2sFtQw2y8We*E4IHlvJAN537(&PW#o#Vy*$$K z#EavdPXd4c^7yxQzC3=#KfE!%@*iIr|K7x}#&7!7#Q6GuotRob@o!Uq4gAg9Z%=KU zoSgbwuHWa{H#IqR^MOg%58Qn4fV%~__0W{NVe5z^}tka)4>C|O@|KT zs)vCi2XnU_KA79|&Y|3*4Zk?;k4P{@$VTZ66#i4}NgC za>uWaRPKELaOH;|9s%B|4DtMqAoESL)IOqO9jI(C2l$+lLS?3on;>_vJm%Q^W@#!?@ zi`*Am**VQ6>6Nv-FXeQqdA9BNmQc*Oz{#vVhn7>J$9~DToZ>?96zB7ycm{j*&Nqja z8Q^B1%vH3CzPXOQb2%CEKI@BG=dP&L^WvEmJ{yX)U`LD@oULK^EGQv+-gibiVCqCm zEz46Hjn!= zxG!*0lGeFIG_Z;<&ej!NUp$?i`KCis3?|#GREtnNjlD)rW{Mg38g41HOs^)=tC#?d zoXbb+ptU&6W#udvE=`6;H{F^Yl|qKFNx{yntqS zd`3Knj7XEkqP;-Ymx2omEhb9xq;uy>8?#%;a%QdX4S76cp49$Vb??}#3%$O>*NF>K zYoBOv?ki}3Kg2uBey?xk7g>@b8p}d?ojSw$3y|spzmV01K^U@VK6G+AdOKq9E6HVX z*+vl15=tdS6ZRt(pkeZ{hNkj;^a-oYr#i)AqKJ_t^4PNZ^D~NwGg+}6)4x$CS)JqL z8#G5k=gtv_W}`rKWKOOV@kAbRQbZ;^G{gC?p$`~n^ffZWvMRAm3|YJ& zgDj_LRGdslB(}9!7OmitW~5gB=5^+D7n;vRySY(D^m8tUHgf?aHCs2uJ>qem>7_H+ zU%JFKq}7US93^hzc>$dATz^;H`h9y1qDdB>2OTVH`5dT4zEoi4Z08G#kxV|6#0ecP zkdA(Z@0^*>u|mCAsH_hKB+J(1*#TG5v7?iv8dsao5WQNP?E=qf70ZWg=m4)Y-*&(k z4W5ZKXoU{nnh^J)pzO{%Zw-fjxt0w7O&2V;Lr!OGo^<>VT4kv*g%z>Y;Y`L#lt zrFE{Enj;%vZQ)8MqC*kV3x%H$0d?j@cx4p91+*(EVF31cy2Sp=92HUc#t}&Zm#f9>v)31ztsZ!B4)3MzI zRKRq$53CsLlemD#fslDdoR`BofLw+C(8|HF$?v6A#-4U#xi90&?LRE0Dzb6@n zn>?iGZSoCZ_4@(fE^wE_CCU+{lC3QNQ%w|2$~f>sm(h{sqD|+CQZir~w!;hU_`MrT zw{pU&HXV&f#8cue%C-EG^>&{p(y=AlKqH`QYLC{0+JN;s~asB75P5KWZ%&gbg*KovXMK|3nT^1s5y;Z?gdu>XCta)-^9Eqip`m znjX;X2>4o5h$6DVA{4&JG2q+%60C{#$k2@)WDQwD)%O2TVU2tV`5N#=)8rVIx3Prs zNztuJ(+k*HC@`;TDnt@hI4qFHT&x-?9n-$uygL9rlR&%@WQLc`m2_F11|L1_R~65! zD#@{EGJp+;SRXA7=M0mV%|0bzV!KYX(ypqsYQLmi=7;b_8?`-R!i72$Bfw-o$yxPD znRkP9SB_GNS}n_a{bq|-i=mA0so$!y(p^(TTK`miRTW}xDvml5O@Um4a*kZX56XkM zX7(2DNlLn3OdM$rQ~oPk?zTL)o+-WPZ%y(=hU#s-kuDYA2aqK8GyH;ditlNkQ$tUS z7LoU~Dj5`a%xb1X#FWj&RWf#m9@#3Bt%>zm@nxsjqcTet?JFmzJDl0p;*qG9rgcmW z7MDR)968ZTzUq;mH5H!hZOX@vjIy|HhJ1t#85H3f*)8;+zbwrJi^3o5lL<8SyXsi=l-?NpC1!Qb8Xkn!Dl0rChjyguH4Rq#IeL>v z@)om1M@BQU`es+?htK-V&M@Ym^?g)Y_3wIUE<(o5Oa@F&dZ&+;t|8;_S{+n}kbMJE z?nYYi9OGUq>YLr1sO5KFOn2Q z!=j^P@BStM(r!TdF~8fdLud5<+-BxAMP@JlHwiQY)k=2eER#*W^%A@-kKN?gp@%r@ z4I)-r`m4BV_8~83f~olJ0;>%zmxN2A{$b24upV0NSPrSNP+s;Hrg>@}b{?kx^&_$D z9rfLg#J|QLtltK?F(aIO?$Z?Y332L9g3|~)&ly`@%`RJ z-stzcvFYvvAE$in8IAX_H(+)a_tZOOuRCTTDj^!o3vCuX#4WP!LFT8#0~@1z z^egt$G$Y)CaES&*GqVQqtDDXAOC|KPihrD7j z#b07^A--5CpruI`W4j$s%3AumWHiv)I(uq$c^I!@8TlD0lvR;`(vP*6OX#d6y`@<+ zUm4Vkmjy5sSN!fZDWpN49|ty)*#pe$-Ku}gJ?b2({8q#AzBkcSKLmb!|BaJ)ANpL3 zCDub_y-6TFsB(U>O&97`<~OKdMP?<g8Cy^{+liQyG-OG3G?mAii#AN&pU1B%Q=C?1NphLmzMQ*( z8s12tr78YiP5k)W-e}UCD?$T#Bstm%OSMliAkTI2j;5Gl0!r+QDlr2_=%|sEG})`l z4JVvTnr!O25_?cB)u%X1jLPE7igAXIRZ*R3rmwYWhVL-yo_tfql5|H!gsi08;tkF- zgXtaC7xd+g??$uDf_l?LlLV=la~5X!zGb^D%pzB!(MprTzGCs6w{$+cf5`OlW#KTz zSm!Sw2QyO%Jy#afbM&Mamk%%8&!(~NRj7VX0J1AdT-GDvnbVXabqJfRuATa}d@ z-{p6P9c215oK$77_tex9s)gM|;DGXwJlL5`_#>QEZpo*7A(KV|Ayc1_xWv9KV@ATF{hkUziiRG!%S90 zcGYL1+A7q0elqL_cQmLvZ-m;A#kaWGj0BFliF$%+pky2Mlg4QRyfJzwU4>O)x0zm@ zDKFt^LWmW847>yW7ydXB!VkRd*lslJf~V}!aS}^Yl(M(aI>^sCJ?UQs?{zRog_}&G z>!^PWu5Iwh>pwBbSwh>GH&M#1SVMTn!oD!+-$u`UJRR{*AnBHqSb4raU=ggb6NyCm zB~E<;yq4_uZ~K4o`%+H~`XuF45DpS**3Z1{%ZwsSP9Rsr==COI9$9VQx2i>1Y#uxl=yf}V>gcC%| zSRy|RegP}*SD7u>L+uD>um%{PfCmKODPEX=EMhbzTiq~zt0F%ph6%Hr_y|{WzQ!7O z7B!k9vL`iMg%37ZX6)d^gnvDA+`ox+Ca~osUfUV=FzITpp7vXwT!eVtwhYb{yj9-#G&5UlSYYV;Lj_(w9{O3BN+EtbZy0#in8rY92@ClT~wrLekE|@ z^t^#RW>B;B_xODmd|7_G{l-jHH{zSzN&PO859vyg=a@GoR>NzHdEq%uFxLcGW4qs#jQM|p z-Vps{ZT#9x<X+J_pI{&CTB1z|uE7O%M@Nb*~Fb zqSm9@sH($x-b;}x%bZ4qSpgAHSQ?yE7fykzV|ND%wQvV70_bk9wzS zu6F4(>N@faehG8^Swx1ueA0Qv=WNbk*OgdG@5!nv8~xM%XLw8T(#~Wn4_pfs`@a|6 zS6?IahTDXnpP`l=@&D`(k~KTX#f^TDuGIrK^9HB&)mPn2u`of+*vDDA3Kd(OV@R=( zc6EJ46Ww-p-tn&|s!6X>=l7Ahj}vn`PoBsB%9$K`|DH#UUgr;64LX|E6V+y&|5Ntu zy&MgduhQ)ytF1@<@$fOVOMeOl~%uq_rBkccHZ^-zVYYByv`L7rj-nqoPj%2?sd24T)aY zS%0+lxK-CTkZ$9&bexnf>Y%C;s`|&m(Hc=d?(fHU(%NJs^Yx{s$1EDV=4i`e1vMcrtoyA{q2I{Bke8|~JZ1PKd^(NPCM8g<#w@gPF zr==&o9_e-k^>nIXh?C18H7u)nh*SFCYt|;6LF$oo)Z3`)v#9m>naTz-E$`=mRS8@C gkHa9a#aE!7*Z+AJ@W1uinIWs(`ZDwXi?p2oU&l{pMgRZ+ diff --git a/tests/sdl-client/conf.h b/tests/sdl-client/conf.h deleted file mode 100644 index e0a91c9..0000000 --- a/tests/sdl-client/conf.h +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: conf.h,v 1.6 2006/05/19 11:16:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Various hardcoded configuration parameters. - */ - -#define SERVER_HOST "hal.xisop" -#define SERVER_PORT 7777 diff --git a/tests/sdl-client/debug.c b/tests/sdl-client/debug.c deleted file mode 100644 index 4dd5bae..0000000 --- a/tests/sdl-client/debug.c +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id: debug.c,v 1.2 2006/05/19 09:16:14 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include - - - -#ifndef NDEBUG -void -debug(const char *file, const char *func, int line, const char *fmt, ...) -{ - va_list lst; - char buf[1024]; - - va_start(lst, fmt); - vsnprintf(buf, 1023, fmt, lst); - va_end(lst); - (void) fprintf(stderr, "%s:%s():%d - %s\n", file, func, line, buf); -} - -void -debug2(const char *file, const char *func, int line, const char *fmt, ...) -{ - va_list lst; - char buf[1024]; - - va_start(lst, fmt); - vsnprintf(buf, 1023, fmt, lst); - va_end(lst); - (void) fprintf(stderr, "%s:%s():%d - %s\n", file, func, line, buf); - - exit(EXIT_FAILURE); -} -#endif diff --git a/tests/sdl-client/debug.h b/tests/sdl-client/debug.h deleted file mode 100644 index 30827c0..0000000 --- a/tests/sdl-client/debug.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $Id: debug.h,v 1.2 2006/05/19 09:36:57 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef DEBUG_H -#define DEBUG_H - - - -#ifndef NDEBUG - -/* - * Macro similar to assert(3) but which does not exit the application. Will - * instead log the condition unless DEBUG_ASSERT_ABORT is set. - * Moreover, the aborting one actually simply calls exit(2) after logging the - * error instead of generating a SIGABRT signal. - */ -#ifdef ASSERT_ABORT -#define ASSERT(c) if (!(c)) \ - debug2(__FILE__, __func__, __LINE__, "ASSERT(" #c ") == %d", c); -#else -#define ASSERT(c) if (!(c)) \ - debug(__FILE__, __func__, __LINE__, "ASSERT(" #c ") == %d", c); -#endif - -#else - -#define ASSERT(c) ; - -#endif - - - -void debug(const char *, const char *, int, const char *, ...); -void debug2(const char *, const char *, int, const char *, ...); - - - -#endif diff --git a/tests/sdl-client/decode.c b/tests/sdl-client/decode.c deleted file mode 100644 index f0b0bc4..0000000 --- a/tests/sdl-client/decode.c +++ /dev/null @@ -1,38 +0,0 @@ -/* $Id: decode.c,v 1.2 2006/05/10 01:28:01 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Function to easily decode data processed by the encode command. - */ - - - -#include -#include - -#include - - - -void -decode(void **ndata, size_t *nsize, void *data, size_t size) -{ - uint8_t *ptr, *tptr, *key; - - ptr = (uint8_t *)data; - *ndata = &ptr[4]; - *nsize = size - 4; - - for (key = ptr, ptr = &ptr[4], tptr = &ptr[*nsize]; - ptr < tptr; ptr++) { - *ptr ^= key[0] ^ key[1] ^ key[2] ^ key[3]; - key[0]--; - key[1]++; - key[2] -= 3; - key[3] += 3; - } -} diff --git a/tests/sdl-client/decode.h b/tests/sdl-client/decode.h deleted file mode 100644 index ab5f3b6..0000000 --- a/tests/sdl-client/decode.h +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: decode.h,v 1.1 2006/05/10 00:48:40 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Function to easily decode data processed by the encode command. - */ - - - -#ifndef DECODE_H -#define DECODE_H - - - -void decode(void **, size_t *, void *, size_t); - - - -#endif diff --git a/tests/sdl-client/dlist.h b/tests/sdl-client/dlist.h deleted file mode 100644 index a3bc766..0000000 --- a/tests/sdl-client/dlist.h +++ /dev/null @@ -1,174 +0,0 @@ -/* $Id: dlist.h,v 1.5 2006/04/27 10:59:19 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2006, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#ifndef DLIST_H -#define DLIST_H - - - -typedef struct list list_t; -typedef struct node node_t; - - - -struct node { - node_t *prev, *next; -}; - -struct list { - node_t *top, *bottom; - int nodes; -}; - - - -/* Some macros to optimize operations on doubly linked lists */ -#define DLIST_INITIALIZER {NULL, NULL, 0} - -#define DLIST_INIT(lst) do { \ - (lst)->top = (lst)->bottom = NULL; \ - (lst)->nodes = 0; \ -} while (/* CONSTCOND */0) - -#define DLIST_UNLINK(lst, nod) do { \ - register node_t *prev = (nod)->prev, *next = (nod)->next; \ - \ - if (prev != NULL) \ - prev->next = next; \ - else \ - (lst)->top = next; \ - if (next != NULL) \ - next->prev = prev; \ - else \ - (lst)->bottom = prev; \ - (lst)->nodes--; \ -} while (/* CONSTCOND */0) - -#define DLIST_APPEND(lst, nod) do { \ - register node_t *tmp = (lst)->bottom; \ - \ - if (tmp != NULL) { \ - tmp->next = (nod); \ - (nod)->prev = tmp; \ - (nod)->next = NULL; \ - (lst)->bottom = (nod); \ - } else { \ - (lst)->bottom = (lst)->top = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_INSERT(lst, nod) do { \ - register node_t *tmp = (lst)->top; \ - \ - if (tmp != NULL) { \ - tmp->prev = (nod); \ - (nod)->prev = NULL; \ - (nod)->next = tmp; \ - (lst)->top = (nod); \ - } else { \ - (lst)->top = (lst)->bottom = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_INSERTAT(lst, atnode, nod) do { \ - register node_t *prev = (atnode)->prev, *next = (atnode); \ - \ - (nod)->next = next; \ - next->prev = (nod); \ - if (prev != NULL) { \ - prev->next = (nod); \ - (nod)->prev = prev; \ - } else { \ - (lst)->top = (nod); \ - (nod)->prev = NULL; \ - } \ - (lst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_SWAP(dst, src, nod, ins) do { \ - register node_t *prev = (nod)->prev, *next = (nod)->next; \ - \ - if (prev != NULL) \ - prev->next = next; \ - else \ - (src)->top = next; \ - if (next != NULL) \ - next->prev = prev; \ - else \ - (src)->bottom = prev; \ - (src)->nodes--; \ - if ((ins)) { \ - if ((prev = (dst)->top) != NULL) { \ - prev->prev = (nod); \ - (nod)->prev = NULL; \ - (nod)->next = prev; \ - (dst)->top = (nod); \ - } else { \ - (dst)->top = (dst)->bottom = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - } else { \ - if ((prev = (dst)->bottom) != NULL) { \ - prev->next = (nod); \ - (nod)->prev = prev; \ - (nod)->next = NULL; \ - (dst)->bottom = (nod); \ - } else { \ - (dst)->bottom = (dst)->top = (nod); \ - (nod)->next = (nod)->prev = NULL; \ - } \ - } \ - (dst)->nodes++; \ -} while (/* CONSTCOND */0) - -#define DLIST_TOP(lst) ((void *)((list_t *)(lst))->top) -#define DLIST_BOTTOM(lst) ((void *)((list_t *)(lst))->bottom) -#define DLIST_NEXT(var) ((void *)((node_t *)(var))->next) -#define DLIST_PREV(var) ((void *)((node_t *)(var))->prev) - -#define DLIST_FOREACH(lst, var) \ - for ((var) = DLIST_TOP((lst)); (var) != NULL; (var) = DLIST_NEXT((var))) - -#define DLIST_NODES(lst) (((list_t *)(lst))->nodes) - - - -#endif diff --git a/tests/sdl-client/encode.c b/tests/sdl-client/encode.c deleted file mode 100644 index 66701da..0000000 --- a/tests/sdl-client/encode.c +++ /dev/null @@ -1,107 +0,0 @@ -/* $Id: encode.c,v 1.4 2006/05/19 03:35:43 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHT RESERVED. - */ - -/* - * Very simple encoding algorithm. Given a 32-bit key, - * it will encode the supplied file using XOR encoding and changing - * the integer values. - * For even more simplicity, the key is randomly generated and stored as - * part of the output file as the first four bytes :) - * This really shouldn't be considered encryption, it merely is simple - * encoding for computer-illiterates to not too easily rip our images - * and sound samples. - */ - - - -#include -#include -#include - - - -#define BUF_SIZE 65536 - - - -int main(int, char **); -void encode(uint8_t *, size_t, uint8_t *key); - - - -int -main(int argc, char **argv) -{ - FILE *ifh, *ofh; - uint8_t key[4], *buf; - size_t s; - - if (argc != 4) { - (void) fprintf(stderr, - "Usage: encode \n"); - exit(EXIT_FAILURE); - } - - if ((buf = malloc(BUF_SIZE)) == NULL) { - (void) fprintf(stderr, - "Could not allocate %d bytes\n", BUF_SIZE); - exit(EXIT_FAILURE); - } - - if ((ifh = fopen(argv[1], "r")) == NULL) { - (void) fprintf(stderr, - "Cannot open '%s' for reading\n", argv[1]); - exit(EXIT_FAILURE); - } - - if ((ofh = fopen(argv[2], "w")) == NULL) { - (void) fprintf(stderr, - "Cannot open '%s' for writing\n", argv[2]); - exit(EXIT_FAILURE); - } - - /* Generate random key and write it to output file */ - srand((unsigned int)strtoul(argv[3], NULL, 10)); - key[0] = rand() & 0xff; - key[1] = rand() & 0xff; - key[2] = rand() & 0xff; - key[3] = rand() & 0xff; - if (fwrite(key, 1, 4, ofh) != 4) { - (void) fprintf(stderr, - "Error writing key to '%s'\n", argv[2]); - exit(EXIT_FAILURE); - } - - while ((s = fread(buf, 1, BUF_SIZE, ifh)) > 0) { - encode(buf, s, key); - if (fwrite(buf, 1, s, ofh) != s) { - (void) fprintf(stderr, - "Error writing to '%s'\n", argv[2]); - exit(EXIT_FAILURE); - } - } - - (void) fclose(ofh); - (void) fclose(ifh); - free(buf); - - exit(EXIT_SUCCESS); -} - -void -encode(uint8_t *data, size_t size, uint8_t *key) -{ - uint8_t *tdata; - - for (tdata = data + size; data < tdata; data++) { - *data ^= key[0] ^ key[1] ^ key[2] ^ key[3]; - key[0]--; - key[1]++; - key[2] -= 3; - key[3] += 3; - } -} diff --git a/tests/sdl-client/fnt/10x20.fnt b/tests/sdl-client/fnt/10x20.fnt deleted file mode 100644 index 99b34864883761ad0f44e1733af72d539ade0f91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10240 zcmeHNPj6f`5T7MgLPeUDfJ35fH|YV+TdlMNHDpr>p@*7OBmf z&%>wKkHMu9AETVg{5(4u+s`jfk+{WH_W94xW6yXz<2NrvNauVY86`ZubROE!9;bC0 z(v%u*cq*m!xQl)`_>-^mhe1anUo4+Q+q_DaW1=rGHjSa6n-?T=8Qakk*`3&WHf6*RGg*o09>AfwEE>X0$cOCJr zc%uI@qAi>2%CEd1ZF<*TRawq$dgT_AGM+2ELA&&~{B1}XEpNjwN^vrTqR~^vp{HS- zC(mfh(+aJK9nf>s@MbuzIi?>@H_pdJI3=6(lAbKe_6lP+Le8nYYu!(*m-Hm3l$5^@ z)5c=$4kJ$&1F=#A;dw&Hd0H2Hd&(z-JS81-D%Ll(e;D;SpYj)n(6 zQjYyMUn?XAN;><7NPQGMV>fOEXPkOren>q{J?UE$pF0q`hmxDX6ZlF~!?Q5YOnltA zP(z+`n_gI7KmzAH=kqp!LS25wug;~scg`DllwQ6UsNXNF&$+^`T8hioX3w|}_OK!(Jr)Qezxlivc`mtG>cOehHK+9E{7mv6lA$fflEr@nWQueBGdg&-?LoZ1*i~O?jUHwn z%U!?6F*2vuB^TGfk?b|>U$3~nu6@hTQOu>6+x%Le-V=s0H{LMX=hATV%l*Lapf%=J z^*}ua=ztn(HJoW*dtS4<@Y3ql%l>03cBqu6>GGro6mABX3sj-okah~3hW1$RwVcya zJCsWyrFC_!S;YNnOXHSWd7B={>Zf5Z=Dg1-es-zBv41-kuh^A9&qlTFu6k1Z-V?uN zS^*E%MNc(b?OdB)`}S=2wk~@6IN^l6FT72IZq4Nes>xQae&5#D)<2+C+xEiKG%&YA zz^Qhu3D0qUz{uv8d|r5(6NwS1=gBoAoy}&&oe?vY(vQ-ozEFQl7_`OvTjp0s#+I;c z51e{T5Bg#pIzmgi9+-@B+?l))#3wZGw>owd`wBX~uhxsFYKXmUp|-{S7?6}>9k@zQ zfpg21+fyg0^mH%q4%wB|yI_Y^;@vo3q22^beu-!*^6>lBlv8?Z?7H+K(&)7e=cv4t z(o1PL_C*Q{Z+XXA+fDUG0yh%4k-&`v{yz!8BBzmiv(fpSXb&DJc<{O0#`T7um%Yi`0FOd>G!nwfKIs2>E6iZ3*X8kW~*t>$m@y3qv(hjMermz8nw_bYNwZQozu z!LOUtFF)n)_*?mVx?F8KdYkTx-__eS?$+J+G@@G)KOM-s@d^DUe-nvO-Qim@rkwEA z3U{1xZ`^8k+qf+*J0DN^dwx>j-trVA+Tk1w@ubzz$LIK%G<|2ur2exqA-n?9mX=o^XswWEJA?gRRm zclZ&#NBM1%=vVo^HsaecJucCMo|wHt>{0K$>G{=2qUoR_Jci|r=qisNr>((;-@7- z^Haz_Gx9SYi|s$SM4DVo8vZQH#rv(4;!G~q>(3OY{CcmKQk?Av`Z301qH4u18IgiU zG^TPFv22mZ7=^FCgMb;!e_l+4rlQAE&XY+8aS*$CwBvfT^r{jUsNhUGHJoWp4M(zi z+_A34L90}%SL2-fhxE1h-+uV2c*37~M^?(?lc`_DjzEI;#Yt_F$LXAyc@fqBZk)-l zhBLX;aJIfQ5*XWOU88AX4QK1C;cR_Z)QU~2yqY3E!yUGiIq uqnli6IFm~aXZ+T1rhhrE7p$UvACDut`*PyVuI(=^WBmUGZTlO?JO2gelED=K diff --git a/tests/sdl-client/fnt/5x7.fnt b/tests/sdl-client/fnt/5x7.fnt deleted file mode 100644 index 361216556ee69d3fac1610c06a01b05ba008080d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1792 zcmd^Ephu{zd7aBHn2!;(Sgn|Pr1jB`f4fngQnmyC!ybPXt zrmiK+lJ#eM+QXh^(O(|znb)t6?lIb^uf9bqb>xz*)*0bqjt0f};?IuWd;GB8f9DVo z#-UBK!4miYpbwS+CnS8Q*E|4BEC$Qkz;ra>Z3D8n_@s zv2f0bSs9x#SM*%V+EBasW@P7YVpI10Goz`j?s zTAQueXxJQZwPK95IQ&t&3##_^=C<^kQD)sUKpbfOIC`Vf(6lx&*{q%CzBhT$1!cd= zN^55c;y6%RitH_8(WEG2`Yyl@Tqzh+a+CrkYnm&`ZdO-#u3I>P5#vphVDF{3T|GDy zk&!%tMw@hr+Yhpvse6L+R;n+}rUb3{6k(3FcEyKCLbE=(63xm@0q$2WZd6&J651nL zxMLfZEiv=UU8gZS(cVpRccns|3*d^HgFg2uq0q)nyU& z8`aN~0>YPaNu@x+9FC{plC{r9dooR%2Vf6zJC1b1aoNP6(=?Or`A=Y^*WLx*_tAGW zHJj<@P~Nlo57r#{_iVm%BXjFvd;2+*cvtVfgC3OC(5o?h-_LWH6z|#m0TP$**<{4V zn(*FQr)k&V@yu%eVqTE@1q=zoQWj8&y(@VeL!wNsp-c->U(l~fRhCIJwONoCU`Jfq xxHfm`gFE4UacD}oBGlfcqIioTo&3u?@$n96HhItm#TMiXB-CsYAQ4Ik_ZLi~-Ut8y diff --git a/tests/sdl-client/fnt/5x8.fnt b/tests/sdl-client/fnt/5x8.fnt deleted file mode 100644 index 01add720b2f68bf43371056c40dcc43d7fb2542d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2048 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 diff --git a/tests/sdl-client/fnt/6x13.fnt b/tests/sdl-client/fnt/6x13.fnt deleted file mode 100644 index e259f1a344526247500ba29a2a80162ef197a3da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHJA++N-3^WW3EEEh3ELad2Xs}>m;D?5VhJk^FhK7X;3j-Gx78Vu;EVvoTPP$7D z-+QP3e&VsDv1Hj%oy%_4zwA^bY(Y56-#`AGOX-=?xounOp79=kN-sh%#W?j{-*p5r z#^HAhch68h-z#u#^OO=zv&j~9+>gWX9ER~$H11>L z>J;8(B`2IacnobGD z@)ou%973#)HnwMPW&l>*LnnHcng&$E5F-`hXNngEQxb~$g?VmZ7Zq$6hNhVV&Dys2 ze%b8sZ86@~stI$9Z_ue3d@K$6fNj?Q3NFXRb>0{-ocN*1fjgp_O3i%s`ru-l z&_}5%8v)L#9W;Ur@n(i;?=1ovDFZcHMjRJL9rRH0!Bk_!0d3oc(F9GJ4{EUSc>XP5 z;Bo##LUWm~Uz|dYOlf`>JyWv!G!2X(mtC_J4e#lj;p`e%HS_}8ZKacH#7)eHq2c(t zo^dX$5X`JVRH)5v=G-stPEF*4O^;lu58P^rNZ}YLj&`Hqwt_$EkUmpu`8W%D{~9w) z+XI+ljLk1TS|DEmYO?REx@e}*ZuOp?nB|?16Q=oA!T8RBse#7w`N8mi`S0$4I93(H z6eQ%7vVP&6`>TP?!TVq*na2x#uK3Wm5Wt1M5E?y}dru^DnDb+O|Ezl z@*T}owsQ0p*nK0x>+yI!3IRVPyKu=JAQT3s21AnJSv5l%(gOsRMv*y&Dd6^ZoUDKWk5KbD4#&HLSXy1bY03T6w z2AE-~1N7qu===x3ULR(nm%I?TANVnLd#3agY)8*Rf5$p#RA>y`E39(>taAWR9{@gq zwbsudd=3Dg1Hk71+BILLHzMkJUbD3+vT@_JsASs#*>(V*1CV;xFeUu%urFE@u4vnN zT|>n7O6giWKcH3@T?f<$0NVl7%riUqIPD~Cn*`IcB=*T00mI%~4#VC7!`=bI-T}j| zpvQ6D0SQAFQuZ7{tY`7}mu^pOQ@TAB==M~gJ5m9BCT762nfC$Ua{&14z{}L?mZ}e; zKH8K(1+q6*4o``~wF5nmYgh diff --git a/tests/sdl-client/fnt/6x13B.fnt b/tests/sdl-client/fnt/6x13B.fnt deleted file mode 100644 index 503b773cc2eafd52f47477fc7cd3bb1287976587..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHJuY2S+5ETeCI8a~^P*`w4V1a@EfcyakfdU5t3=9ec76b+q6c!c+957f=5FmKK zAmD((0)s*Wg8&18zBePuP6~?qeO0nvJ!Y`vJpX+7Gt;z9 zQ(I#|w1zo^);5-k{#*FwedixKfPk@PiSgs;@luDiF~T55fzt*)i_wC5>VHhsd}Hmp zW+QyBtGv@UZ7V<@Z7VMokQ^h?7yEy~{}e0RyLFNWDtTv-7F9`lV(HsH^tVO>HFHxn za|Xu5kt6w6MH_?6o6fn-xi4FiNNUsk@Riq)3L$X^kw@X8Px-cf^{v*?bkWz=`Iwa5 zy1F=>X$iJMP+RLbtgVgVlLPNWVFYvb8CI<0aWqK{(H&o7ZpDYH0+n+iP-@W?80wtu zR|!e%AgG`h1Vl`IRcQm&b>r`+D9vYL2-}h+4Oq7&^%-n546egv%Mcm+?Z#HR5eke=a)4cfM$pHNjbDG&)nC#wN(B|8B0P1yjDr&J%6EECql)EGE= z?clJ0X~F9tQ`+>k#$)7gab1%nBrCy@I2{!%1YEewYN%VutC&=YFXnyPpfYym(Lrv8 zECcfy6W8D*u`|%a_8Xr6kNHK(E{#q{DZCe$8jpb@NJ-q($`f!p(@rd!}CeLA)r+$3-`f~Z2 z2)6th-(0f5!~N$UKHm@2rP`Nxduq9v3H*XPrv;!pmnBK03NC0IINx~b;9!SZeFRN+ zkeu!h0J^)4y~8n_3CwvIhCkPJcmW#=#DTjSA>gN*+*3T2vCa;#&JIAm1K8jM!C=B+ zvx9y*0NCsjxiyz`H^OUPRJf-=KsHHyW-9<5>=M}QfYe0|90sxE6Ya)>cUkYsy z1{~c1sCUpE0o9N?4DyBzYP>cHxTfGo%;|Qya+rhy=ym~gy8tXyK=V_x10g^8;qt&4 zhTd6hP)QGRFU`$$4tLf8kh(}<(=&o>vjY@p2l$;?z|^n5OG?ECUhmgbE>LFM)pCKd y%`V9W5(y3$Z1cQ@Zv2S)jI0lXV;S_$N(EAo3ZwvRAJuR-N>$~qPq(J3iR5qOSDa!1 diff --git a/tests/sdl-client/fnt/6x13O.fnt b/tests/sdl-client/fnt/6x13O.fnt deleted file mode 100644 index cb5a27f030eed956cbb25a4c2fb9683718e14196..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHJEpy~J5EU>mSRgRKAV9#t;DDh(fPsKPfPull0RsX81_T%w7#tWl;6T8Efrfzx z1NSE^3=9k$c<*&fR&J~A_*R`#HPLf-KlPW@HfA&de`m9r|6IdxxL)r{YpHeW4$Ggm za*m+wmP56xnueh3miN0&()TSN>auo%!6cyXUoYTto(R;3E>WxQul@V2?b_1ZG>Ai0 z__qX%nVV)9h8SNlyW1lBs&?+=y8bmvOqDkO_;0Zsvgr79x094dg{GOCTV%HP!{F=Y zQ`G9QDXkmUizwQrX@@^v9tq0Q$}`!6x5IJ{&z!X-7S8G@v*YaN)p3iZb=1B7wyFl8 z)y*=*1W*)0wJa3aCWLT44^BWkNI;S+9|9ch76CJCd{LfHR4YrgSAWyyo4am*OcEcu z?sPt@8f-v-FlYm|FeM3rFC!a#@C;IXi$FubnT{DKNq{w*RJaZgixREQ$6%wTRsmqY zu9rnZm*8$Vm1)+}I1-ggxC^$i}=uvYwa`kz67*6W^wc z&e0u58=7ov-1q&U)h1Z6232bs+xF@~2msRA5NR2;4?MbEV|a&z?J2#9J<5r$q75ZT zJbr&(=%lTdN#=|BtnClpiH=HrAod~ErznbhN~ESDnPcVno=)^A(jh_TN%{(o?2j}O zi8U>KlZ=|uRP^=23PDW^L^XN5sTuP)j_axf#(ZIuLd5#O423v<#tNDH@H;%vR|7U( zdQKZ>wWj*ccH3>t`e+Wo#tLbD1i%BS4?%-_Be?^cm&a0@%*>@dNLOJ7IQPbcv@l>B zup$oo1NYyE-hk?{$M65^7terYiDQ9ri;lx}jkoAe11$JvIBDzf-Nu}grjQOXkpL!D zU00>FA(dF4c{ zxNAHk5>W0i1p&mJBr&Xl>-0XrxaQEo%z+vl&7i8k0DLNB3B1h!VP{}|LvHu)*Xv(k zgQIw_c_(7N;~Wes42GMYlL5}j0Mr@4hJ#9Dhi@6cCIi@HAXD=h!|@a6!0Ql>d%aZ2 zhPz6`Cff$cwgK2=KJ{rEU7xRfn#K^(*SgE|9HX8^VgL=7#Y zeT_*H`gA9w#fAZM@|6eC?QP`H?G4cF4bbfk(Cq}Oy2^lrem7mWD;g!z`p7vUjVVb_ z0+OBtBqIsHw>H&>ac2OV3}CYXSG6Tls;Odu@|e;BMTvNj)Wm}Xv_Mf!+({C&H9omC tp$N3_599is^+^SapRHOT1)ye46o4%Qcpw6uS^Q`W=kKq4X+=$^+23ZW$7}!q diff --git a/tests/sdl-client/fnt/6x9.fnt b/tests/sdl-client/fnt/6x9.fnt deleted file mode 100644 index cca4689668968d2fdb00062d2cbb500d9bd23fa6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2304 zcmeHIE0o+g5Nv2DxFDdRprE0kpg_PtLqkKu0SgQV1Oyr^FkBE2I503UFmR!v!GctE z%aeDv==f>glS}x~XWtim&*?%3LMDD3eKhm8Mj#?|f;m{-Fn@ZkuMim%p^J79yYO>}cQtN?V6`i(q zirb`lD?!WWPGq>y?{oU52&Xy`ccAJaYlrqBzk_ly5UA#ND z0g_UOYAU$6`|@ksY_Bq2n%9ECEwC3t1E8+)k~)`|dny`iFWgiN*f6iQdzr2FW!bi0 ztYWE(iU^2kJo5;cJX6oyD`yQIc94l@N{PDwv~l3LPb@t;jRkzY8zMbk2qazCRLJ@= zP!gh|4**sN&&Rw9)_8^9pTN5kszSvEK?Q}YM1G<{^kzS(vN*}WqeI-((yya+4EYRC zRs}YXo;SRi4_oDTL(rh=l9W6$ZLEv4-NT@o?WPOU!H|q4g!GE;YXSbB{!0h&+}KNu z(AV1Ic>a>rR+qX#14aQ21JKf}`;3Q9QaJlQKYw}o@;t*P)g(}0#JbjK2$#HTfS>vK z+slg?)4|6F!q*z?y~+?Y3^Z~EGxJg|V@9C2w=uRY)D%9!l00TSgKX-GhjPz# zN^>wUcA=NM=Co6SUovjVc%>7m02j;w!Z?U007L&vCG)zk>v!bf90lh!3;lcyDj^x??qN!chb;5uZoU6T}8$JpuA?A|mgQcDnv@8OJHZ z9U6B(L2Muze_7;{ql{Xz)m3Y$+`Z8bI_)GAVgq=Jjdo5+h~Ys*)As6TPL2xbPopNp zagIWqMph@tCpE!lutsS;$?618iCl-AvHOHNEJGA;Rj>;L2zc5!kW&J4{1GV%1X*3i c$=ng9XM5QW0_zI^y#Ap=Z0BCEovTXv15=`0umAu6 diff --git a/tests/sdl-client/fnt/7x13.fnt b/tests/sdl-client/fnt/7x13.fnt deleted file mode 100644 index d20852efc8f7f3b29753079502d1064fd7e56084..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 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 X0Cfali-6T&;$~Ku^;98NbCQ1n*yqe< diff --git a/tests/sdl-client/fnt/7x14.fnt b/tests/sdl-client/fnt/7x14.fnt deleted file mode 100644 index fdcd7522218b5be752214150d92c37808d974a6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3584 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 diff --git a/tests/sdl-client/fnt/8x13.fnt b/tests/sdl-client/fnt/8x13.fnt deleted file mode 100644 index 9de72b4606003e78fdc7b4c28f7cbbe8bf7d0413..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHJF>B;T6dr^)gjtL*E<`Y~Fe;W5L4*{G5r+`Mh{YVs;-m;J%o46L!G#MKLM$r6 zks>Urt_WedDr}J=zrdu(uSj81qzb|02l(=R?~OFNgcKxNP#6Y*&#ss) z;8^uZ)I`HvnnzXWbC%{7YIdD2l&$1>eh|j_dQC-?6cpVVVY-kdiCtC{o*%_|!(k0< zjy$i(2>i)mQkIP`zBPG%x#~4XF;StzXhWxC+JLQ)zXfNfaAQWmU5DRl^IRO2#Wk3j!|uwWl)u{K6m=B6l=6-mtS7(2 zUzcq`KG?h{&LmkhAhS^8B)Pa9^X&M3DT^!0YH_uwN*M++5ut9|pLSi>wk@fPVzr!~ zSvH1=B1@>zsA;7huzxwvJRs5Z)LD_|S)YX`>yB(ET2O?oZL!;@)2V1MciVN{t|T=y z({NgKW*OziuMJR!T1q)~t7J+~3X8o6~= zmsZOqsn?$8ogz3Icxbbtu^ODyxTZhW=Cmwlc}6SCruo4EO}U&}hWTb931WsYtgLQq zeq_ur%$VO0olf!tJNjnXbT_MSs##rvNXX$Rx3+}DT*AGehuur7!R3M?m+K9S`;A2hl>x)xr~|0j4t#Vz0*JNKL~_V2f%#&y z*?jZ3*?bE&Tzj}=;8F%&%!5LOI>lfDJAio{0JQ@#KKJB0VD4b!0Bjt<=a2)en#C`+ zHh%uvv_HP-zWTBS0ohnV+MaCyWE%i%93b_e0f)QMyzFc~UoMxcEEj5~R3i#U9RRfh zSeyeGhRP=U8N_*CHqkb-5=HpDC@u*QI9GD~F#xyIAVCgbq5&X34v_Hrpx$)XY(bbJ z$&bu4lqoppY8K}iG^8E?LYi^~jHtoKo&#w$0@Vm4(bSjkg^V`v+LbA=IgNN=BZ}QN z(r~2=qY#KYJ;1g$H6JQWk>-cFcQs2Q-xn}YJI!=D0vHD3zGn5cKF?8%B#)x`6M%n? A8UO$Q diff --git a/tests/sdl-client/fnt/8x13B.fnt b/tests/sdl-client/fnt/8x13B.fnt deleted file mode 100644 index 96179a0a7d876cddcd27486e171639993c96573e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHKJ8R@t6uuav!U!`}xR}9i_6Mj4Mg(C}xY#0Xz@+ZuiMJnnhjd&Xw5FmK=T7cZbu z>>3x3@V5AM@MFrdE=x1FAY*pm0i7`27*K(4{B%w`D)G zp!D|AA0M%J;XWIVR$10kty&$0;x_ksY{(>%Wdh_gZ{ivesr z(~zj=ibCa>w+63C5Cnw-2**iQmJK{2C(rAuTggI!5$1^>i=TNcG~ z4)zQjY)iM)H~nlwko}Q?K*S82)klPkgu(?!9ksqju32tAe%#zsFy@X8cLk^?6CR4m zq^3?)@NB4~25_Su6>J-$0>kN)Y#WGDNnl)<^fI}n$)QXks?RH&?2eeB1 zho+0-TeG4S8bHRX$ITM90VGXiaG#nlHMItujSG}h?@BdI-(0(?Tnpk7bf_=XdVQW{ zvD_%SyjnHv(W2mThHd~rG7^mmK+4E=q1O&QsRVOZc`kJb_Q*jyD1kFVTVd@b!GiSj zVBH0C^ui@p5aL}0pQ<}$y9z7PNXX_TQlnyEBG@LE?C_k*K}}U>Ug9)u9eAxZiHEHb zGa(7Zf2sPOsBA6t9^; z-Y)HRj6M3`_>NLgU5e-HBOv2x6^4{`c^Qa3)5v*deU5S3?39P@7)PliaAqiuJ>)gQ zL-$AXr`q}d`5(>z+S-?xL5$p|+uKi^G2acaqRGy)Mp{SC_FQJac1Zi=(BoHxK-zLR z%h0;lU%!04)@GZ9?iYN);4Y-oZ2fMXohrbsRPXQax1f`PfyMRvg&3H3T)uF}!NTB6 z$@Bt4N(Y27(~HPnOuZnweW2p6xNo>5&Dooqo0~U39UL4Ss>HL&C`5-MF~`XHy62WFQ01<~ zHm^aQfUw;I*zN($^#JiqUP*Ygme=5LY~md)mOW$$fpd;-cO!>xcYtnpfNpnyZnuE- z=>Y7R?DLUZf2L_)p{_m%%#SHej|Z9_4>Thluy^Dwy>ZGpn2RsE`*E F&c6;bfy4j+ diff --git a/tests/sdl-client/fnt/8x13O.fnt b/tests/sdl-client/fnt/8x13O.fnt deleted file mode 100644 index a38a37105608b49ab60ff7dd13d2358823648407..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3328 zcmeHKO=~1Y7_M!bwG2aOhdI=t31w4UPZ+>~tSYiAz z)H|*aOx(6&49-`^xl&g+sq2+dlQh5xKNy=#J~`f7Vpz7bqy6X3Pzn{yv9`@=ADB~< z8cCYw>T(tX7>TDQf5tvPx2Plp-j;U0hsi3$lS2YHQANsfUJv zBsPt%4sz#$39rcwkE4jxa_crXl4NK|X}&XVk!4fQow+=kyNDt%Cue2z>PIKdOP`-8 zinev*)F90f5$jKyNjayGx;5K+HLYhPL!gPxrk-&osIX0bSj6r|Q5=`2K&qh7sV@fqa5_dT)66#N6=zXkcZos+lbvI@|N)PkT8~fl%K`;Ji>$sA|Mb zEBIS4!wtK4{Pp#PE!Z^5b?!bK80)KQy{=RnJlqy>3v&OKW*;73e}8QW%=PCb|N2oP zR6H(lkj)s!!rDcMleOJJx8hGf)R@{iKR{fB0ChkIy2%5vx?6 zTq5;kl*sJa#$byak~mcdf8d;vPh`&iLnp!If+Wb&IEVX`;LUq7{gAPEf zyJ{i;_Nc0=$J6!tOR$BWh3^3DgGM#AZ3_DYfPDf0bpTj{MulY4H5hk6uiuemSqD(p zEPvIuH^S=4#~)mL{u$kg#5S3re|feR5L*kdCIF&tCEy4*T9ohZ?;l-Vy_(h3-Ko9e z?xw83xd7l?0B|k<`c9*L+BOB_0-$|b2~oEIYeJjCngFmS0IX?&62ll@1+E#v>d>YT z#UL>jcr{~z2jpo>V9fCnlr=uN+K*DC=p&mSaxU~N1Tg^QJ^=g=5&$f~Hoj;1USHRY IVN);p3)sb=q5uE@ diff --git a/tests/sdl-client/fnt/9x15.fnt b/tests/sdl-client/fnt/9x15.fnt deleted file mode 100644 index 349e5bd9086bd4b6cf40d95b543e7beae0c57636..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7680 zcmeHMUu#@N6hE8BbR#iImpnuW=_aft6p<9c21(N0bd8&!O{)e9q8RFfFG4_&3S~E6 zqmMrLpx>Y$$8XWM`1{Sd=bo9_xe3_U%&>Rvo!^`@=ii(=b5}&y>tCbz}v+kf{QRc&M z-oOg$gS*HQsFb>fWkEWq3*M33=}eP)#z}+@=)l%iwNNMvY z)94mr{3rZwp(BnB#TDU*63V{Ks49(Jxds?_6GRYW$jhSK34O1^bz7dvCl1zk3ym>d z56Ny)9SO3>3)e}+vS}!WKKgV~ofg|l_m7`~?AKth^IkRHzB*1wyeSfqoAkB?&yA?Q{Kyg zZ!FyeIiJ`fTGjzP=w(Lc;MWdjKS0D%!WjqA(?|VL&Wg0_VJ^j0_L#HI%b88**h8u> zwN$-ReO04@JeIvM^Nj39Qt7Q**YA9g_wmj>=vL|?Vi;4gzDBS1i>*k+DV&Q@2&_sQ zsIBQEu0k)0o?y*?D_;kz#ZANcnnYCBnWGjfkl_X+~hL&PIMTB}Gx)~@ucFU+q z=BQ;P=Im~;m-}eF&iI!3*{;{beNgB+)U`VUn^@Tm>zr#nuAVteQX7ALdsz+9OmW@# zeaO<1N3aa@mKTjhW>K~288T{Kd=;m0MUE|Svv^E7D;JGSU9GWyx!;I)9JFL!_OO0f zci{)+qa1RXDY=)`aJv(&;dtJ;fG&!y-cztLJEA&M{AooS1W9EWcL~ zscTsK{OWd2W!4d@qxxZ*v(wT?Dyef$y`Y|P^a*x18;DJ<-tY6$!Yyc<&P%V1>!`nj z_jF#=Lwb$lO2<(buHk(BI$B!4hUyyDw@>rDhw?eRndV{c7Wii88us;jyNZcf>{wO< zPA}fBSX(a0TZPXn+U2lw(p_E~dEUwc`2ElxZrU3Q+*sho0C+ZTX2_qRr&v4^90`)MzH-h-q-wAm=~gam+(78UiAHy_vX*KTj2GD{1A2pI^q$| z39NhaUR`tA{42mT?mY`34*1-~&PewW{`RwRJ2>+U!#C6TBxfjF^Q-we#*FiZ{05ol z<%9YZ!cm6alRu<|^G5t#RP9Vl9?7Q#T0QaFo}SjS7}5Q@)MtG=6RKRgi)cc1&)$Rz z_FPZE#=at?oF%N=W|UNG*f;4Hh@4jBAuOqNT(u`Ea=0=d^rK3B)q|$*B>0fohSl~+ zrf(TFeaon6R7P!H%S4)g%nLSe8MS%KsLk7iO8sr(Us#1T{?4F2va_|FuGN$-v(o8x zTILe!GM7+`jd;iJG3gqWX;nHqIKlA<-@1Zr{R(n5<6V%$y!yG@G;-`9`r2a} bl~MCT8MWPrqxrd8-#6xm^c#ixw?z9N5ddW# diff --git a/tests/sdl-client/fnt/9x15B.fnt b/tests/sdl-client/fnt/9x15B.fnt deleted file mode 100644 index 23bc97e3f27224b5d3113300feed860271207883..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7680 zcmeHM&x>3|5H4NV1YEM$m0dO>;(19R3}hXN0Z+MlpD-{97{Wq8SF)L%qX+*0!IK9M z3SPYhHyKC{F4=>Zm52rc@w$+M5toeL*Y&=s?l(O#M+ZuGmP76d%6^{C;BYw zcGB~i{ha#GTNolQqOU~ezqyaclYSlPoRQ`yqPwY$Kl7F+F&lhpS8W^lvb}|JcRDwi zU9=~lODT%Z*cH&-jJadiK-20y#KPk^q3OU+lp;ME~SMeuk`9!5B?X4Z3k(F<}5uZ zI60af*wLl-=P+0sPWJD1=oS9F1IrUz!*2m}58fAP5njFy8x2rDK?_o(=a6yFe#aP- z)8z`365nlbNge1U@lYn$nQ}*RZK z@T%Zd#J9&dIHH%}>RKP9QSg-|P}k@nt;7#tvp(V|Qa<{V#tQ;H#@LMU^V~~;^1FA^ zIB~4*w0af~$A`pTBJIKpNy8@ZAz~s;nqH5mz3&AG`TI@%{nT@*k-jHw_#SCk_%b~s z_viKGg^KQvF^6=5HR-UA_4x>NX#2@F0lPl=GuLQrf5FSS_j#CPE~OgVV|xlBdSLfK zxy>kV2sQO`^0M!NeUPES`>fF?|Lzbx>}_a_!3DhKw$dDy&kfPF zWK~|u?6tmK}LdE0On!s|oR7BYud1RULyFw*dpu0(rh@sr;x@o@GystcBWzTw` zSP?j2dIWtPO9>%W+-{H<+8_xldNO_;LJ$t*KQiQr+J`C2T6m~9Uc38gJUdtQ}UXGF5 zAU;rzf@>G(A9f>Y=K4jwmpqCY!?Lhil;cx7(NGVk+UOHu40{BtSLH+%!2?xJbH%V* zWm?@7^wlxEkLz%`a~LApwBLx)KQ;9U>g6N2f<1wtr$x__#BaRxCY*C_FYTRt_FhbLxTCC@pZLA8-L~)STl{XLJVZZ{HZe1I?S1?# z{Q~jQDs;J)?zpa@wAzO8z6)xvZ)LNX@l_vE-L~)T$Cgw>$oQi4>bH3v+&^d?+L`%; z&?U5rl|;>)PjB;b-@Wkpx!r2kc((lzR=Sz!Jgn$6+sDh_=PY70*3iKQ?xnbTlD20$ z|ps z8`z=E>+#1Y+w{=C_Irjm?gVUlPSBaqyY^kgJk^UyQ!s!MZwHbfEQNPE8WyDRn{ zC{8aWO4&|>lQ&rVI5X}iI$(8^YUl1HwC*Hr8S{R+*4bL;Q0ZGomv9?%b}p}_JMVct z%g&mKd_Gd#$=B|94>$$6+@9Qt;7bb0g-hdz zShlL8lDUrRyLD6=%|reB7oZhmjWO4^3ysWXZy@#uI63_S`W5sTZ^t%DxHO90bAHy4 zMs-vg)ltb@N2BNRI33dil_YaSQqEi2ihMaL znd`jzZXK0I^HAD|iT?pI={>!qhet8*WS?g78>1g_mY=(&Q5}^=byPCf(R$DMxqB-` StzuYFyp^=^wXW>hdH(~RDjH4z diff --git a/tests/sdl-client/fnt/9x18.fnt b/tests/sdl-client/fnt/9x18.fnt deleted file mode 100644 index 0651c97276b494c6c888382a2721074b5f417ea0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9216 zcmeHN&re)85S}G8St<$%;(#hbSVCJARTWXChy##ak~9ly(7r=^>X&kt$V* zgjoKK9DC@Y{SSKR|CJm4KF^!ypU-f}slwJi+s~iJGvo2tZ$L!TuhNsDjDqKnO;1?# zWm$G*A}7Zal*`g@JO4g@ET{bxJeIM%#&3+~HJNU5OQ@;51~;$p`xdx4%)=a~E%Y*P z;q{!%xZg|+X%IuqCo&HTN+|)!tSlhUrmv&6axiH*nMA#8+?8MCd-)orG^jr2jMH88 zZXjRA>s)r7BYeJ#hZkG#+SzPm4x2x=zV34VI31T`Pck~`nD^H{$@qC+v~#)6qMuyP zIi0icoa->BlfMaNzkr?h48IF_ncJZvwV$|d413mstRv$m_b07>0-L4PrfE*DxSm7z z+?0p%MG9%#v#0E_7FevrIw6E_;>3N-Tuv^<@d` zId*z6`BIG1;f$Q`GUm#8pWu{a|16$8}CO6?STUMpUNR`c?9^bVlF9T5cO&!?fJ# zf_{vmu0XyH+P{ib(($%pHqOd;O{tr*e!h{%O@08auh{Um?8~CdYw!hTZEa^$ImCL8 z@Y7OjDP~0m&B_m5IVj9!9@GcnI`YVFHCxzpg% z$##SBs)t-ITQ9DY@s!fB{iQVS!G^Ai9LK1T&bX02MhL8Loa zRENn#`G4^tm=z((oqjZVs_CJPEAEX|r%+COl>sJKtEq$Crn;DQdI=gM8{^wF_ zf17RXQbNJJTUv&&SMBJFZS7SEaP^yz`K#>h`HOQ6oNM4*1OF!t&{s0WKC>j@H0}@w z?)%{pYO5LKY%wdIYCLmz&Xtp%N{c`+TBLlXNY8D^d5l^@3~3dy35`oF;bd7y%M#DL zv!!j^RNl&;@&|rz-AyVV$5{6qevC|C%e$L5GeE3EgJV1w5dG>-M>q*fv5j~{*L_8> zK6~;H`2AP@!m|`f5jl#96BezE7#h>*6~joDGy zr*)faAiqJb8TrUXvtyiLK9x7pLp&}2dx~F+efhGJ4*drAA)|TxN(t|)_VrbZ?dVO9 zG`izI`W;xuhbXcUoRo ztjWt|-oVO|T-Il$$9TD{&q|LmI}E=l6%}Ii+^J){DOq%<{AJa{`FO|qF@B*vM1GDp z!)Cb2Zk$>fewEvrTA!66#$>lXD?^N}sr6YIV#2vBW@UEfCDz&yQXDn@`^b53lgc9* z_glm6dx;-wYt9S!e!t6Vu^r>8hA|D)Fn;wJ;pvJa+3I&;IFo*h*XL3xZ^6UQV6HJ% z|5hk?P^YC)n;J)o&nB}FwMP1f(1$A#uOF^y8RPZSjWG-9o=f9~oHdLBg?lHw1$1MK zn;ISCrjFr#aRWDx71)+qbZF0}Wc5O|SW~QLr4-BMB~$&BF(z3JV-r OYQag)zlfLPTK@s#?p|U5 diff --git a/tests/sdl-client/fnt/9x18B.fnt b/tests/sdl-client/fnt/9x18B.fnt deleted file mode 100644 index d93d09d0d0e712303299913ff73da7802bf8b304..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9216 zcmeHM&1xJ+5H3X^bP!gK8zdx?ClCnMh8Q_{h(I8h4GU608+k!s3nX^;F#=pEDBssLHQiI))0TrS0d=!8J=0%Tcl~sAO|6KQZ)8b6mCusv zmrYN4Ta``Oleye1=D2UlYTNnK;&XY|&%l>*DR1$+lyzBYs`c6Zja#4c<+56tg~<(05!{yZvsc;N*dHawlfs_ zFR|i>1>VVHTCe3g8}DBbla68Am-WT^!ejh1F@BuK+$?S~I)2PuJ#((RqUGs$zHTF* zlAJxA+pM`HLrfY$0)tI43lbebnh$J@1!%wjHR+A zyXe`Gvv7SYzhK{%%O*U=e=oWN?MgaqcZ+e;ee0hTrM#O2JcfJyHFoNWJPDrVb=dn| z)Uo`DItl9-$|>saT>ze@VZU?76a6cG#}1QnwAQAOC^x=rF5f~Vk@7~c6-@2Ouo@uc?$Nd8p!pa z{c*hNYh=UPyYgikrEGHf>_NJ}E&gcgE69AW9d8XrKdeLanYCG;-Diyr+I@^&<_kTh zYF@9quoPd;U^l5f@54%biS}dEav9~AktfsG1Zf=f+L*0no~+6fvgj!8ublT7@o`6R zcjPuU#@h*Y>J-08BL_d1aUAbC?_+s^y?2yI(N zp^VNUWPJ#UzmSiutGyFL`m3lWhqkk6yp)&09-{r^Yo@QWovfbG>wPadCF6PNC3F!a zXlEvEaoH{BN${ufG}V^3)&cByAM1YKa?=jbIIewsXG69A6!IL)(+oWdd_^lN`5zr* zRx~Qwk6M<_qWaC}igd=%dYKM&Jq#K-Y4wsVI=pxaIjTRPWpmC{XE|TvjEtUpC&~Ff z%P@KlKY+etfyKPz~SaVF2b+Z5(=Udp-rAm8J6jy7{V zu{?(Cp5S|m@6O`uVrv6)PD18tf>xeYw?T8rMk7UgQ@;B%(ok{D=klZcoUNI-8EU=U zT@GK6A(}KNd%ui`VWzG8zk$XD^%bYR7XKXJ8}t-*FiJZS;WMvzig;|JtsOw}zZR~!F%s4<@>)J>J7gh;@(8;~zpoCQ3*m}(0M*kYUgsrEBvGvq2ww^jh#b94vSHZsY`>PdDqjy?fU#`jc(l1~030+$? zzG@ibtA;TzK%)Wp2vZkY)I>1Jq~1$DKk7$FRpyGu(Jjxn?{4DmUJ17~{Q$ zF`d>h=E3cJk2dB{ZV6s&*65rZvHHUO#rnLt?}iS}0hA|1$Fj4zFx%=`+ zru}{ly%5iv`drH8^Kcf-5mCH`6v~B`rt+hIHvgm8C?D#L{vq|@iiz^+$3*$`W6VO- z^2>ASe-48DbhM4=f4b|bVLlA;MxBnWr$$F}6+`&!n6cZ-#H^=JE!SjnuH~9c&NYn5 zxrQ-2tYg#;>liXhJqZ4;r}19H81FTV>9mGP a=b{u;$9X=Ad&W+mnD -#include -#include -#include -#include - -/* THIRD PARTY LIBRARY HEADERS */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* APPLICATION HEADERS */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* DEFINITIONS */ - -enum userevents { - UE_FPS -}; - -struct font { - int w, h; - void *data; - size_t size; -}; - -#define VECTOR_X(x, a, r) ((int)(x) + (cos_table[(a)] * (r))) -#define VECTOR_Y(y, a, r) ((int)(y) + (sin_table[(a)] * (r))) - - - -/* PRIVATE PROTOTYPES */ - -int main(int, char **); - -static void axis_angle_update(void); -static void handle_uevent(SDL_Event *); -static void handle_recvmsg(thread_amsg_t *); -static void objects_update(void); -static void frame_clear(void); -static void frame_draw(void); - -static int surface_blit_angle(SDL_Surface *, int, int, double, - int); -static SDL_Surface *bmp_load_key(void *, size_t); - -static Mix_Chunk *sample_load(void *, size_t); - -static struct font *font_load(void *, size_t, int, int); -static void font_blit_string(struct font *, int, int, - const char *, uint8_t, uint8_t, uint8_t, uint8_t); - -static Uint32 fpscnt_callback(Uint32, void *); - -static void trig_init(void); - - - -/* PUBLIC GLOBALS */ - -thread_port_t main_port; - - - -/* PRIVATE GLOBALS */ - -static int joy_angle = 0; - -static int shields = 0, cloaked = 0, nav_thrust = 0, - cur_nav_thrust = 0, nav_angle = 0, - cur_nav_angle = 0, nav_pos_x = 512, nav_pos_y = 384, - max_thrust = 12; -static SDL_Surface *rship, *fship; - -static Mix_Chunk *snd_cloak, *snd_uncloak, *snd_shield, *snd_unshield, - *snd_torp, *snd_hit, *snd_explode; - -static FPSmanager fpsh; -static SDL_TimerID fpst; -static char fpsstr[8]; -static int fpscnt; - -static struct font *font; - -static double cos_table[360], sin_table[360]; -static int fired = 0; - - - -/* PRIVATE FUNCTIONS */ - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - thread_ring_t main_ring; - SDL_Thread *recv_threadid, *send_threadid; - Mix_Music *mus; - - /* Initialization */ - screen_init(); - trig_init(); - (void) SDL_ShowCursor(0); - (void) SDL_EnableKeyRepeat(0, 0); - - /* - * Ignore a few events with potentially high frequency but which - * we don't need - */ - (void) SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - (void) SDL_EventState(SDL_JOYAXISMOTION, SDL_IGNORE); - (void) SDL_EventState(SDL_JOYBALLMOTION, SDL_IGNORE); - (void) SDL_EventState(SDL_JOYHATMOTION, SDL_IGNORE); - (void) SDL_EventState(SDL_KEYUP, SDL_IGNORE); - - /* - * Network - */ - if (SDLNet_Init() != 0) { - (void) fprintf(stderr, "main() - SDLNet_Init() - %s\n", - SDLNet_GetError()); - exit(EXIT_FAILURE); - } - - /* - * Audio - */ - if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) != 0) { - (void) fprintf(stderr, "main() - Mix_OpenAudio() - %s\n", - Mix_GetError()); - exit(EXIT_FAILURE); - } - snd_cloak = sample_load((void *)&_binary_wav_nt_cloaked_wav_enc_start, - (size_t)&_binary_wav_nt_cloaked_wav_enc_size); - snd_uncloak = sample_load( - (void *)&_binary_wav_nt_uncloak_wav_enc_start, - (size_t)&_binary_wav_nt_uncloak_wav_enc_size); - snd_shield = sample_load( - (void *)&_binary_wav_nt_shield_up_wav_enc_start, - (size_t)&_binary_wav_nt_shield_up_wav_enc_size); - snd_unshield = sample_load( - (void *)&_binary_wav_nt_shield_down_wav_enc_start, - (size_t)&_binary_wav_nt_shield_down_wav_enc_size); - snd_torp = sample_load( - (void *)&_binary_wav_nt_fire_torp_other_wav_enc_start, - (size_t)&_binary_wav_nt_fire_torp_other_wav_enc_size); - snd_hit = sample_load((void *)&_binary_wav_nt_plasma_hit_wav_enc_start, - (size_t)&_binary_wav_nt_plasma_hit_wav_enc_size); - snd_explode = sample_load( - (void *)&_binary_wav_nt_explosion_other_wav_enc_start, - (size_t)&_binary_wav_nt_explosion_other_wav_enc_size); - (void) Mix_AllocateChannels(16); - (void) Mix_ReserveChannels(2); - if ((mus = Mix_LoadMUS("ogg/1.ogg")) == NULL) { - (void) fprintf(stderr, "main() - Mix_LoadMUS() - %s\n", - Mix_GetError()); - exit(EXIT_FAILURE); - } - if (Mix_PlayMusic(mus, -1) != 0) { - (void) fprintf(stderr, "main() - Mix_PlayMusic() - %s\n", - Mix_GetError()); - exit(EXIT_FAILURE); - } - - /* - * Bitmap graphics - */ - rship = bmp_load_key((void *)&_binary_bmp_RomDD_bmp_enc_start, - (size_t)&_binary_bmp_RomDD_bmp_enc_size); - fship = bmp_load_key((void *)&_binary_bmp_FedCA_bmp_enc_start, - (size_t)&_binary_bmp_FedCA_bmp_enc_size); - - /* - * Bitmap fonts - */ - font = font_load((void *)&_binary_fnt_7x13_fnt_enc_start, - (size_t)&_binary_fnt_7x13_fnt_enc_size, 7, 13); - - /* - * We're already the main thread. - * Initialize our message port and notification ring. - */ - if (thread_ring_init(&main_ring) == -1) { - (void) fprintf(stderr, - "main() - thread_ring_init(main_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if (thread_port_init(&main_port) == -1) { - (void) fprintf(stderr, - "main() - thread_port_init(main_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - thread_port_set_ring(&main_port, &main_ring); - - /* XXX We should obtain user login information */ - - if (thread_amsg_pool_init() != 0) { - (void) fprintf(stderr, "main() - thread_amsg_init()\n"); - exit(EXIT_FAILURE); - } - - /* Launch network utility threads */ - if ((recv_threadid = SDL_CreateThread(thread_net_recv, NULL)) - == NULL) { - (void) fprintf(stderr, - "main() - SDL_CreateThread(thread_net_recv) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if ((send_threadid = SDL_CreateThread(thread_net_send, NULL)) - == NULL) { - (void) fprintf(stderr, - "main() - SDL_CreateThread(thread_net_send) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - - /* - * XXX Wait until we receive the server's connection status. - * We should display a "connecting to server" or such message to the - * user during this time. - */ - { - struct msg_connect *cmsg; - - while ((cmsg = (struct msg_connect *)thread_msg_get( - &main_port)) == NULL) - (void) thread_ring_wait(&main_ring, -1); - - if (cmsg->status == -1) { - (void) fprintf(stderr, "%s\n", cmsg->error); - exit(EXIT_FAILURE); - } - - (void) thread_msg_reply(&cmsg->msg); - } - - /* FPS counter initialization */ - (void) strcpy(fpsstr, "000 fps"); - fpscnt = 0; - fpst = SDL_AddTimer(5000, fpscnt_callback, NULL); - - /* FPS management initialization */ - SDL_initFramerate(&fpsh); - SDL_setFramerate(&fpsh, 10); - - /* - * Main loop. - * Listen for messages and events and process them, while drawing - * frames. - * - * XXX There remain design choices to make here. - * We could only draw a frame once we received all data for a frame - * from the server, thus waiting for the EndOfFrame message to draw, - * in which case we only need to bother drawing the current new - * received data. If we did this, we potentially could reduce the - * incomming asynchroneous messages rate so that a single one is sent - * once every messages for a frame were obtained. This method would - * probably be the most efficient, while allowing the client to update - * its display as fast as it is able to obtain the server information - * for a frame. However, this also means that for a very large world, - * if a map exists or such, there could be more data needing to be - * sent per frame, unless there also were in a frame the information - * to update the existing world information, which would be similar to - * the second method. Hmm since we need to send a difference packet - * for every object on the map, or to possibly resend their position, - * what could be done is having the server sending updates less - * frequently for that data. Although, we would need to make sure to - * avoid causing lag to the normal 10fps display when - * sending/processing large map packets. We possibly could - * intermingle some map information data per normal frame, having the - * server round-robin the map information among the clients in a - * distributed way? Say we have 50 connected clients, and that we - * want a map update rate of approximately 1 second interval, we could - * send the data among them at 50 / 10, meaning that we send each - * client update of 5 clients. With round robin this means that every - * client, 10 times per second are receiving enough update information - * so that within a second the whole map be updated. Of course, we - * would need not to break this when clients connect/disconnect. - * - * Or, we could instead maintain our own known world and display - * states and only update them via the messages received from the - * server, allowing us to maintain a steady frame rate (although this - * would also mean that no change could be made between certain - * frames). - */ - for (;;) { - thread_amsg_t *amsg; - SDL_Event ev; - - /* Process incomming server messages. */ - while ((amsg = (thread_amsg_t *)thread_msg_get(&main_port)) - != NULL) { - handle_recvmsg(amsg); - thread_amsg_destroy(amsg); - } - - /* Update gamepad current angle. */ - if (gamepad != NULL) - axis_angle_update(); - - /* - * Process incomming user events, sending corresponding - * messages to the server when appropriate. - */ - while (SDL_PollEvent(&ev)) - handle_uevent(&ev); - - /* - * XXX Probably to be done on the server, but such a step - * might still be necessary perhaps. - * Update objects position in preparation to draw the current - * frame. - */ - objects_update(); - - /* - * Draw current frame and wait until it's time to draw another - * frame. - */ - frame_draw(); - SDL_framerateDelay(&fpsh); - } - /* NOTREACHED */ - - thread_port_set_ring(&main_port, NULL); - thread_port_destroy(&main_port); - thread_ring_destroy(&main_ring); - - exit(EXIT_SUCCESS); -} - -static void -axis_angle_update(void) -{ - int angle, x, y; - - angle = joy_angle; - - /* On win32 -1 is reported for dead state instead of 0! */ - if ((x = SDL_JoystickGetAxis(gamepad, 0)) > 127) - x = 1; - else if (x < -128) - x = -1; - else - x = 0; - - if ((y = SDL_JoystickGetAxis(gamepad, 1)) > 127) - y = 1; - else if (y < -128) - y = -1; - else - y = 0; - - if (x == 0 && y == 0) - return; - if (x == 0 && y == -1) - angle = 0; - else if (x == 1 && y == -1) - angle = 45; - else if (x == 1 && y == 0) - angle = 90; - else if (x == 1 && y == 1) - angle = 135; - else if (x == 0 && y == 1) - angle = 180; - else if (x == -1 && y == 1) - angle = 225; - else if (x == -1 && y == 0) - angle = 270; - else if (x == -1 && y == -1) - angle = 315; - - if (joy_angle != angle) - joy_angle = angle; - - return; -} - -static void -handle_uevent(SDL_Event *ev) -{ - - if (ev->type == SDL_MOUSEMOTION) - return; - - /* - * Quit commands events. - */ - if ((ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_ESCAPE) || - ev->type == SDL_QUIT) - exit(EXIT_FAILURE); - - /* - * Button events. joy_angle affects several of them. - * We currently ignore release events. - */ - if (ev->type == SDL_JOYBUTTONDOWN) { - int ch; - - if (ev->jbutton.state != 1) - return; - - switch (ev->jbutton.button) { - case 0: - /* Torp */ - if ((ch = Mix_PlayChannel(-1, snd_torp, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - fired = 1; - break; - case 1: - /* Secondary weapon */ - if ((ch = Mix_PlayChannel(-1, snd_hit, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - break; - case 2: - /* Navigation direction change */ - if (nav_angle != joy_angle) - nav_angle = joy_angle; - break; - case 3: - /* Special weapon */ - if ((ch = Mix_PlayChannel(-1, snd_explode, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - break; - case 4: - /* Toggle shields */ - shields = (shields == 0 ? 1 : 0); - Mix_PlayChannel(1, - (shields == 1 ? snd_shield : snd_unshield), 0); - break; - case 5: - /* Toggle cloak */ - cloaked = (cloaked == 0 ? 1 : 0); - Mix_PlayChannel(2, - (cloaked == 1 ? snd_cloak : snd_uncloak), 0); - break; - case 6: - /* Thrust accelerate */ - if (nav_thrust < max_thrust) - nav_thrust++; - break; - case 7: - /* Thrust decelerate */ - if (nav_thrust > 0) - nav_thrust--; - break; - } - - return; - } - - /* - * Keyboard events - */ - if (ev->type == SDL_KEYDOWN) { - int angle = joy_angle, ch; - - switch (ev->key.keysym.sym) { - /* Angle changes */ - case SDLK_i: - angle = 0; - break; - case SDLK_o: - angle = 45; - break; - case SDLK_l: - angle = 90; - break; - case SDLK_PERIOD: - angle = 135; - break; - case SDLK_COMMA: - angle = 180; - break; - case SDLK_m: - angle = 225; - break; - case SDLK_j: - angle = 270; - break; - case SDLK_u: - angle = 315; - break; - /* Navigation change */ - case SDLK_d: - /* Direction */ - if (nav_angle != joy_angle) - nav_angle = joy_angle; - break; - case SDLK_z: - /* Thrust up */ - if (nav_thrust < max_thrust) - nav_thrust++; - break; - case SDLK_a: - /* Thrust down */ - if (nav_thrust > 0) - nav_thrust--; - break; - /* Weapons */ - case SDLK_SPACE: - /* Torp */ - if ((ch = Mix_PlayChannel(-1, snd_torp, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - fired = 1; - break; - case SDLK_f: - /* Secondary weapon */ - if ((ch = Mix_PlayChannel(-1, snd_hit, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - break; - case SDLK_g: - /* Special weapon */ - if ((ch = Mix_PlayChannel(-1, snd_explode, 0)) != -1) - Mix_SetPosition(ch, joy_angle, 50); - break; - /* Toggles */ - case SDLK_s: - /* Shield */ - shields = (shields == 0 ? 1 : 0); - Mix_PlayChannel(1, - (shields == 1 ? snd_shield : snd_unshield), 0); - break; - case SDLK_w: - /* Cloak */ - cloaked = (cloaked == 0 ? 1 : 0); - Mix_PlayChannel(2, - (cloaked == 1 ? snd_cloak : snd_uncloak), 0); - break; - default: - break; - } - - if (joy_angle != angle) - joy_angle = angle; - return; - } - -} - -static void -handle_recvmsg(thread_amsg_t *amsg) -{ - - /* XXX */ - if (amsg->size != -1) - (void) fwrite(amsg->data, amsg->size, 1, stdout); - else { - (void) fprintf(stderr, "Error reading from server socket\n"); - exit(EXIT_FAILURE); - } -} - -/* - * These will normally occur on the server. - * However, it's nice for temporary testing. - */ -static void -objects_update(void) -{ - - /* - * XXX - * Adjust current thrust according to ship's acceleration/deceleration - * speeds in order to eventually reach nav_thrust. It seems that - * we need floating point variables to perform this. - */ - if (cur_nav_thrust != nav_thrust) { - if (cur_nav_thrust < nav_thrust) - cur_nav_thrust++; - else - cur_nav_thrust--; - } - - /* - * XXX - * For now we also should use cos/sin and allow the ship to move - * around in its current direction at its current thrust. - * We should also bounce when reaching the borders for now, - * by reversing its angle. - */ - if (cur_nav_thrust != 0) { - nav_pos_x = VECTOR_X(nav_pos_x, cur_nav_angle, - cur_nav_thrust + 1); - nav_pos_y = VECTOR_Y(nav_pos_y, cur_nav_angle, - cur_nav_thrust + 1); - } - - /* - * XXX - * We need to rotate cur_nav_angle in the shortest direction to - * nav_angle, while making sure to always have angles in the range - * 0 - 359 only. Moreover, if the degrees stepped are too large - * to exactly reach nav_angle, we want to just reach it at the last - * step. To properly test the later condition, we step relatively - * to the current thrust. - */ - if (cur_nav_angle != nav_angle) { - if (cur_nav_angle < nav_angle) { - if ((cur_nav_angle += (max_thrust + 10) - - cur_nav_thrust) > nav_angle) - cur_nav_angle = nav_angle; - } else { - if ((cur_nav_angle -= (max_thrust + 10) - - cur_nav_thrust) < nav_angle) - cur_nav_angle = nav_angle; - } - } -} - -static void -frame_clear(void) -{ - uint32_t *ptr, *tptr; - - /* - for (ptr = screen_surface->pixels, - tptr = &ptr[screen_width * screen_height]; - ptr < tptr; ) { - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - *ptr++ = 0x00000000; - } - */ - - for (ptr = screen_surface->pixels, - tptr = &ptr[screen_width * screen_height]; - ptr < tptr; ptr = &ptr[8]) { - ptr[0] = 0x00000000; - ptr[1] = 0x00000000; - ptr[2] = 0x00000000; - ptr[3] = 0x00000000; - ptr[4] = 0x00000000; - ptr[5] = 0x00000000; - ptr[6] = 0x00000000; - ptr[7] = 0x00000000; - } -} - -static void -frame_draw(void) -{ - - frame_clear(); - /* SDL_FillRect(screen_surface, NULL, 0); */ - - surface_blit_angle(rship, nav_pos_x, nav_pos_y, cur_nav_angle, 0); - if (cloaked) - filledCircleRGBA(screen_surface, nav_pos_x, nav_pos_y, 25, - 0x00, 0x00, 0x00, 0x80); - if (shields) { - aacircleRGBA(screen_surface, nav_pos_x, nav_pos_y, 25, - 0xe0, 0xe0, 0x20, 0x60); - filledCircleRGBA(screen_surface, nav_pos_x, nav_pos_y, 25, - 0xf0, 0xf0, 0x30, 0x40); - } - aalineRGBA(screen_surface, - VECTOR_X(nav_pos_x, cur_nav_angle, 40), - VECTOR_Y(nav_pos_y, cur_nav_angle, 40), - VECTOR_X(nav_pos_x, cur_nav_angle, 60), - VECTOR_Y(nav_pos_y, cur_nav_angle, 60), - 0xff, 0xff, 0xff, 0x80); - - if (fired) { - int i; - - fired = 0; - for (i = 0; i < 255; i++) { - pixelRGBA(screen_surface, - VECTOR_X(nav_pos_x, joy_angle, i), - VECTOR_Y(nav_pos_y, joy_angle, i), - 0xff, 0xff, 0x00, 0xff - i); - } - } - - { - char str[256]; - - (void) snprintf(str, 255, - "Thrust: %02d/%02d (%02d), " - "Angle: %03d (%03d), " - "Position: (%03d,%03d), " - "Shields: %3s, " - "Cloak: %3s", - cur_nav_thrust, max_thrust, nav_thrust, - cur_nav_angle, nav_angle, - nav_pos_x, nav_pos_y, - (shields == 1 ? "On" : "Off"), - (cloaked == 1 ? "On" : "Off")); - font_blit_string(font, 17, 17, str, - 0x00, 0x00, 0x00, 0xff); - font_blit_string(font, 16, 16, str, - 0xff, 0xff, 0xff, 0xff); - } - - font_blit_string(font, 17, 741, fpsstr, 0x00, 0x00, 0x00, 0xff); - font_blit_string(font, 16, 740, fpsstr, 0xff, 0xff, 0xff, 0xff); - - (void) SDL_Flip(screen_surface); - fpscnt++; -} - -static SDL_Surface * -bmp_load_key(void *data, size_t size) -{ - SDL_RWops *rwo; - SDL_Surface *s; - Uint32 c; - void *ndata; - size_t nsize; - - decode(&ndata, &nsize, data, size); - - if ((rwo = SDL_RWFromMem(ndata, nsize)) == NULL) - goto err; - if ((s = IMG_LoadBMP_RW(rwo)) == NULL) - goto err; - SDL_FreeRW(rwo); - - c = SDL_MapRGB(s->format, 0, 0, 0); - if (SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, c) == -1) - goto err; - - return s; - -err: - (void) fprintf(stderr, "bmp_load_key() - %s\n", SDL_GetError()); - exit(EXIT_FAILURE); -} - -static int -surface_blit_angle(SDL_Surface *s, int x, int y, double a, int clean) -{ - SDL_Surface *t; - SDL_Rect d; - int r; - - ASSERT(a > -1 && a < 360); - - if (clean) { - int cx, cy, c; - - cx = s->w / 2 + 2; - cy = s->h / 2 + 2; - c = (cx >= cy ? cx : cy); - (void) boxRGBA(screen_surface, x - c, y - c, - x + c, y + c, 0x00, 0x00, 0x00, 0xff); - } - - if ((t = rotozoomSurface(s, -a, 1.0, 1)) != NULL) { - d = (SDL_Rect){x - (t->w / 2), y - (t->h / 2), 0, 0}; - r = SDL_BlitSurface(t, NULL, screen_surface, &d); - SDL_FreeSurface(t); - } else - r = -1; - - return r; -} - -static Mix_Chunk * -sample_load(void *data, size_t size) -{ - SDL_RWops *rwo; - Mix_Chunk *c; - void *ndata; - size_t nsize; - - decode(&ndata, &nsize, data, size); - - if ((rwo = SDL_RWFromMem(ndata, nsize)) == NULL) - goto err; - - if ((c = Mix_LoadWAV_RW(rwo, 0)) == NULL) - goto err; - - SDL_FreeRW(rwo); - return c; - -err: - (void) fprintf(stderr, "sample_load() - %s\n", SDL_GetError()); - exit(EXIT_FAILURE); -} - -static struct font * -font_load(void *data, size_t size, int width, int height) -{ - struct font *font; - void *ndata; - size_t nsize; - - decode(&ndata, &nsize, data, size); - - if ((font = malloc(sizeof(struct font))) == NULL) - goto err; - - font->data = ndata; - font->w = width; - font->h = height; - font->size = nsize; - return font; - -err: - (void) fprintf(stderr, "font_load()\n"); - exit(EXIT_FAILURE); -} - -static void -font_blit_string(struct font *font, int x, int y, const char *str, - uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - - (void) gfxPrimitivesSetFont(font->data, font->w, font->h); - (void) stringRGBA(screen_surface, x, y, str, r, g, b, a); -} - -/* ARGSUSED */ -static Uint32 -fpscnt_callback(Uint32 interval, void *args) -{ - - (void) sprintf(fpsstr, "%03d fps", fpscnt / 5); - fpscnt = 0; - - return interval; -} - -/* Initialize trigonometric tables */ -static void -trig_init(void) -{ - int i; - double f; - - for (i = 0; i < 360; i++) { - f = ((2 * M_PI) / 360) * (i - 90); - sin_table[i] = sin(f); - cos_table[i] = cos(f); - } -} diff --git a/tests/sdl-client/main.h b/tests/sdl-client/main.h deleted file mode 100644 index 12b8cb2..0000000 --- a/tests/sdl-client/main.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id: main.h,v 1.3 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Exported resources by the main program, mainly for thread modules. - */ - - - -#ifndef MAIN_H -#define MAIN_H - - - -#include - -#include - - - -extern thread_port_t main_port; - - - -#endif diff --git a/tests/sdl-client/ogg/README b/tests/sdl-client/ogg/README deleted file mode 100644 index 90d493c..0000000 --- a/tests/sdl-client/ogg/README +++ /dev/null @@ -1,5 +0,0 @@ -For how, place any ogg track that you like as 1.ogg under this directory. -Eventually there shall be some of my own composed music, when I have time -and care enough to add it. - -Matt diff --git a/tests/sdl-client/packets.c b/tests/sdl-client/packets.c deleted file mode 100644 index 0a46921..0000000 --- a/tests/sdl-client/packets.c +++ /dev/null @@ -1,327 +0,0 @@ -/* $Id: packets.c,v 1.1 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * To validate a received packet, we'll make sure that it's larger than - * sizeof(int), and that the first integer consists of a valid expected packet - * type ID within range. If so, we verify if packet length really corresponds - * to the packet type, and then can interpret the packet information. - * An actual network packet may contain a number of these packets. - * We thus must be able to efficiently determine each packet's length. - * Since we're using TCP, it should be enough. However, on the server side - * especially, proper sanity checking on input must be done to avoid crashing - * the server because of unexpected data processing. - */ - - - -#include - -#include -#include - -#include "packets.h" -#include "client.h" -#include "sendq.h" -#include "conf.h" - - - -static int cpacket_auth_handler(client_t *, uint16_t *); -static int cpacket_ping_handler(client_t *, uint16_t *); -static int cpacket_pong_handler(client_t *, uint16_t *); -static int cpacket_direction_handler(client_t *, uint16_t *); -static int cpacket_thrust_handler(client_t *, uint16_t *); -static int cpacket_torp_handler(client_t *, uint16_t *); -static int cpacket_quit_handler(client_t *, uint16_t *); - - - -static struct packet_index cpacket_index[CPACKET_MAX] = { - {sizeof(struct cpacket_auth), cpacket_auth_handler}, - {sizeof(struct cpacket_ping), cpacket_ping_handler}, - {sizeof(struct cpacket_pong), cpacket_pong_handler}, - {sizeof(struct cpacket_direction), cpacket_direction_handler}, - {sizeof(struct cpacket_thrust), cpacket_thrust_handler}, - {sizeof(struct cpacket_torp), cpacket_torp_handler}, - {sizeof(struct cpacket_quit), cpacket_quit_handler} -}; - - - -void -update(void) -{ - node_t *nod, *next; - client_t *c; - uint8_t *data; - size_t size, off; - - for (nod = DLIST_TOP(&clients_list); nod != NULL; nod = next) { - next = DLIST_NEXT(nod); - c = (client_t *)nod; - - if (c->todestroy || c->toclose) - continue; - - /* Reset ping request throttling flag */ - c->askedping = 0; - - /* First process incomming packets */ - recvq_content(&c->recvq, &data, &size); - for (off = 0; off < size; ) { - int16_t *id; - - /* - * Verify packet type ID. It already has been - * converted to host endian byte order, unlike other - * packet fields. - */ - id = (int16_t *)&data[off]; - *id = BYTEORDER_HOST16(*id); - if (*id < 0 || *id > CPACKET_MAX) { - client_destroy_mark(c); - break; - } - - /* There must be enough data for packet size */ - if (size - off < cpacket_index[*id].size) { - /* - * Kill authentucated client if other packets - * than CPACKET_AUTH - */ - if (!c->authenticated && *id != CPACKET_AUTH) - goto k; - - /* - * XXX We'll need to also do special - * processing for chat packets, since they'll - * have arbitrary length. They'll still need - * to be 16-bit aligned, too. - */ - - /* Kill client on packet processing error */ - if (cpacket_index[*id].handler(c, - (uint16_t *)off) == -1) - goto k; - } else - goto k; - - /* Process next packet if any */ - off += cpacket_index[*id].size; - continue; - -k: - client_destroy_mark(c); - break; - } - - /* - * XXX I don't like having to run the clients list all over, - * to then run through all objects (including clients) to - * update them, and then yet again through all objects to send - * updates to all clients. - */ - - /* Run game frame on all objects */ - DLIST_FOREACH(&clients_list, nod) { - client_t *c = (client_t *)nod; - - /* - if (!c->authenticated) - continue; - */ - - /* - * First update direction and thrust. - * XXX I could do a small function or macro to deal - * with similar situations, i.e. - * change_update(int goal, int *current, int steps); - */ - if (c->object.direction < c->object.i_direction) - c->object.direction++; - else if (c->object.direction > c->object.i_direction) - c->object.direction--; - if (c->object.thrust < c->object.i_thrust) - c->object.thrust++; - else if (c->object.thrust > c->object.i_thrust) - c->object.thrust--; - - /* - * Translate object x/y position according to - * trust/direction. When reaching borders we simply - * bounce for now. - * (I need to review my trigonometry a bit again :) - */ - /* XXX */ - c->object.x += 1 - (random() & 2); - if (c->object.x < 0) - c->object.x = 0; - else if (c->object.x > WORLD_X_MAX - 1) - c->object.x = WORLD_X_MAX - 1; - c->object.y += 1 - (random() & 2); - if (c->object.y < 0) - c->object.y = 0; - else if (c->object.y > WORLD_Y_MAX - 1) - c->object.y = WORLD_Y_MAX - 1; - } - - /* Send update frame information packets */ - DLIST_FOREACH(&clients_list, nod) { - client_t *c = (client_t *)nod; - node_t *nod2; - - /* - if (!c->authenticated) - continue; - */ - - DLIST_FOREACH(&clients_list, nod2) { - if (spacket_position_send(c, - &((client_t *)nod2)->object) == -1) - break; - } - (void) sendq_flush(&c->sendq, -1); - } - } -} - - -int -spacket_auth_send(client_t *c) -{ - struct spacket_auth p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_AUTH); - mm_memclr(p.string, 32); - mm_strncpy(p.string, SERVER_STRING, 31); - p.protocol_version = BYTEORDER_NETWORK16(SERVER_VERSION); - /* XXX */ - - return client_write(c, (uint8_t *)&p, sizeof(p), 0); -} - -int -spacket_pong_send(client_t *c) -{ - struct spacket_pong p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_PONG); - - return client_write(c, (uint8_t *)&p, sizeof(p), 0); -} - -int -spacket_position_send(client_t *c, object_t *o) -{ - struct spacket_position p; - - p.packet_type = BYTEORDER_NETWORK16(SPACKET_POSITION); - p.object_id = p.object_type = BYTEORDER_NETWORK16(0); /* XXX */ - p.x = BYTEORDER_NETWORK16(o->x); - p.y = BYTEORDER_NETWORK16(o->y); - p.direction - BYTEORDER_NETWORK16(o->direction); - - return client_write(c, (uint8_t *)&p, sizeof(p), 1); -} - - -/* Note that only the packet_type field is endian converted yet. */ - -static int -cpacket_auth_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_auth *p = (struct cpacket_auth *)ptr; - - p->protocol_version = BYTEORDER_HOST16(p->protocol_version); - - if (c->authenticated || p->protocol_version < SERVER_VERSION) - return -1; - - /* - * XXX For now. Eventually also check user/password - * We could use APOP-like authentication where server sends random - * data as part of the authentication greeting/request, and expect - * client to append password to random data and send hashed result. - * We also should do user concurrency checking here. - */ - c->authenticated = 1; - - return 0; -} - -/* - * Note: Following function is never used, since pings are handled in the - * kqueue main loop code. - */ -/* ARGSUSED */ -static int -cpacket_ping_handler(client_t *c, uint16_t *ptr) -{ - /* NOOP */ - - return 0; -} - -static int -cpacket_pong_handler(client_t *c, uint16_t *ptr) -{ -/* struct cpacket_pong *p = (struct cpacket_pong *)ptr;*/ - - /* XXX */ - - return 0; -} - -static int -cpacket_direction_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_direction *p = (struct cpacket_direction *)ptr; - - p->direction = BYTEORDER_HOST16(p->direction); - - /* Radians */ - if (p->direction < 0 || p->direction > 1000) - return -1; - - c->object.i_direction = p->direction; - - return 0; -} - -static int -cpacket_thrust_handler(client_t *c, uint16_t *ptr) -{ - struct cpacket_thrust *p = (struct cpacket_thrust *)ptr; - - p->thrust = BYTEORDER_HOST16(p->thrust); - - if (p->thrust < 0 || p->thrust > 20) - return -1; - - c->object.i_thrust = p->thrust; - - return 0; -} - -static int -cpacket_torp_handler(client_t *c, uint16_t *ptr) -{ -/* struct cpacket_torp *p = (struct cpacket_torp *)ptr;*/ - - /* XXX */ - - return 0; -} - -/* ARGSUSED */ -static int -cpacket_quit_handler(client_t *c, uint16_t *ptr) -{ - - return -1; -} diff --git a/tests/sdl-client/packets.h b/tests/sdl-client/packets.h deleted file mode 100644 index 4db2425..0000000 --- a/tests/sdl-client/packets.h +++ /dev/null @@ -1,151 +0,0 @@ -/* $Id: packets.h,v 1.1 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * All packets must begin with an int16_t packet_type. All fields of a packet - * must either be [u]int8_t, [u]int16_t, [u]int32+t or [u]int64_t. Moreover, - * all fields will be passed in network/big endian byte order when sent over - * the network. We could have used a union, but this would have resulted in - * larger, fixed sized packets wasting bandwidth. Since a server to client - * update will generally involve sending more than one such packet in a row, - * it is important to minimize their size. - * Note: If using 32-bit fields within a packet, make sure that they are - * 32-bit aligned. - */ - - - -#ifndef _PACKETS_H_ -#define _PACKETS_H_ - - - -#include - - - -/* - * For every server packet type we support, an index array will be used - * with this structure to call the associated handler function, which will - * perform sanity checking and process the packet, returning 0 on success or - * -1 on error. The size field will allow to perform sanity checking on - * data size prior to calling the handler function, as well as to increase the - * buffer pointer. - */ -struct packet_index { - size_t size; - int (*handler)(uint16_t *); -}; - - - -/* - * Server to client packets - */ - -enum spacket_types { - SPACKET_AUTH = 0, - SPACKET_PING, - SPACKET_PONG, - SPACKET_POSITION, - SPACKET_COLLISION, - SPACKET_MAX -}; - -/* Used to request client authentication and respond success/failure */ -struct spacket_auth { - int16_t packet_type; - int16_t protocol_version; - char string[32]; - /* XXX */ -} __attribute__((__packed__)); - -/* And for server to test idle connections */ -struct spacket_ping { - int16_t packet_type; -} __attribute__((__packed__)); - -/* And clients to test latency */ -struct spacket_pong { - int16_t packet_type; -} __attribute__((__packed__)); - -/* Object position/direction update to client */ -struct spacket_position { - int16_t packet_type; - int16_t object_id, object_type; - int16_t x, y, direction; -} __attribute__((__packed__)); - -/* Collision/detonation update to client */ -struct spacket_collision { - int16_t packet_type; - int16_t collision_type; - int16_t object1_id, object2_id; -} __attribute__((__packed__)); - - - -/* - * Client to server packets - */ - -enum cpacket_tyoes { - CPACKET_AUTH = 0, - CPACKET_PING, - CPACKET_PONG, - CPACKET_DIRECTION, - CPACKET_THRUST, - CPACKET_TORP, - CPACKET_QUIT, - CPACKET_MAX -}; - -/* Used to respond to server authentication request */ -struct cpacket_auth { - int16_t packet_type; - int16_t protocol_version; - char string[32]; - /* XXX */ -} __attribute__((__packed__)); - -/* To ping server for latency mesurement */ -struct cpacket_ping { - int16_t packet_type; -} __attribute__((__packed__)); - -/* To respond to server ping requests */ -struct cpacket_pong { - int16_t packet_type; -} __attribute__((__packed__)); - -/* Angle/direction change request */ -struct cpacket_direction { - int16_t packet_type; - int16_t direction; -} __attribute__((__packed__)); - -/* Speed change request */ -struct cpacket_thrust { - int16_t packet_type; - int16_t thrust; -} __attribute__((__packed__)); - -/* Torpedo fire request */ -struct cpacket_torp { - int16_t packet_type; - int16_t direction; -} __attribute__((__packed__)); - -/* Game quit request */ -struct cpacket_quit { - int16_t packet_type; -} __attribute__((__packed__)); - - - -#endif diff --git a/tests/sdl-client/pool.c b/tests/sdl-client/pool.c deleted file mode 100644 index 23d7d25..0000000 --- a/tests/sdl-client/pool.c +++ /dev/null @@ -1,417 +0,0 @@ -/* $Id: pool.c,v 1.3 2006/05/19 09:36:57 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2006, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - -#include -#include -#include - -#include -#include -#include - - - -/* DEFINITIONS */ - -#define BPAGE_SIZE ((size_t)OALIGN_CEIL(sizeof(bpage_t), long)) - - - -/* STATIC FUNCTION PROTOTYPES */ - -static bpage_t * pool_page_create(const char *, pool_t *); -static bpage_t * pool_page_destroy(bpage_t *); - - - -/* STATIC FUNCTIONS */ - -/* - * Creates a new page of objects, and calls the constructor function for each - * object of the new page if needed. Returns NULL on failure, or the new - * bpage_t pointer on success. - */ -static bpage_t * -pool_page_create(const char *func, pool_t *pool) -{ - register size_t nodesize = pool->nodesize; - register uint8_t *ptr, *toptr; - register bpage_t *page; - register list_t *list; - - if ((page = pool->malloc(pool->pagesize)) == NULL) - return NULL; - - /* Initialize bpage_t */ - page->magic = MAGIC_PAGE; - page->pool = pool; - DLIST_INIT(&page->objects); - - /* - * Create all objects of that bpage_t, inserting them into it's list_t. - * If any object creation fails (it's optional construtor function can - * fail), destroy the page and return NULL. - */ - if (pool->create != NULL) { - for (ptr = toptr = (uint8_t *)page, ptr += BPAGE_SIZE, - toptr += pool->pagesize, list = &page->objects; - ptr + nodesize < toptr; ptr += nodesize) { - ((pnode_t *)ptr)->magic = 0; - ((pnode_t *)ptr)->page = page; - if (pool->create((pnode_t *)ptr) != 0) - return pool_page_destroy(page); - DLIST_APPEND(list, (node_t *)ptr); - } - } else { - for (ptr = toptr = (uint8_t *)page, ptr += BPAGE_SIZE, - toptr += pool->pagesize, list = &page->objects; - ptr + nodesize < toptr; ptr += nodesize) { - ((pnode_t *)ptr)->magic = 0; - ((pnode_t *)ptr)->page = page; - DLIST_APPEND(list, (node_t *)ptr); - } - } - - return page; -} - -/* - * Destroys a page previously created using pool_page_create(), calling the - * destructor function for each object of the page if necessary. - * Returns NULL. - */ -static bpage_t * -pool_page_destroy(bpage_t *page) -{ - register pnode_t *pnode; - register void (*destroy)(pnode_t *); - - if ((destroy = (page->pool->destroy)) != NULL) { - /* We need to destroy all objects */ - DLIST_FOREACH(&page->objects, pnode) - destroy(pnode); - } - - page->pool->free(page); - - return NULL; -} - - - -/* PUBLIC FUNCTIONS */ - -/* - * Initializes a memory pool for efficient management of fixed sized nodes. - * Returns 0 on success or -1 on failure. - */ -int -pool_init(pool_t *pool, const char *label, void *(*mallocfunc)(size_t), - void (*freefunc)(void *), int (*create)(pnode_t *), - void (*destroy)(pnode_t *), size_t nodesize, uint32_t nodesperpage, - uint32_t minpages, uint32_t maxpages) -{ - int ok = -1; - register size_t ns, ps; - - ASSERT(!POOL_VALID(pool)); - ASSERT(pool != NULL && mallocfunc != NULL && freefunc != NULL && - ((create != NULL && destroy != NULL) || - (void *)create == (void *)destroy) && - nodesize != 0 && nodesperpage > 0); - - ns = (size_t)OALIGN_CEIL(nodesize, long); - ps = (BPAGE_SIZE + ((nodesperpage + 1) * ns)); - - pool->magic = 0; - pool->label = label; - pool->malloc = mallocfunc; - pool->free = freefunc; - pool->create = create; - pool->destroy = destroy; - pool->nodesize = ns; - pool->minpages = minpages; - pool->maxpages = maxpages; - pool->nodesperpage = nodesperpage; - pool->pagesize = ps; - pool->avgtotal = pool->avgcnt = minpages; - DLIST_INIT(&pool->pages); - DLIST_INIT(&pool->fpages); - DLIST_INIT(&pool->epages); - - /* - * Allocate minimum number of pages, if needed. We insert them into - * the empty pages list, but minpages will be honored as such to - * never free pages below it. - */ - for (; minpages > 0; minpages--) { - register bpage_t *p; - - if ((p = pool_page_create("pool_init", pool)) == NULL) - break; - DLIST_APPEND(&pool->epages, (node_t *)p); - } - - /* Validate this pool */ - pool->magic = MAGIC_POOL; - - /* - * Have we failed to allocate any needed pages? If so, destroy pool - * and return -1. - */ - if (minpages == 0) - ok = 0; - else if (minpages < pool->minpages) - (void) pool_destroy(pool); - - return ok; -} - - -/* - * Destroys a pool which previously has been created by pool_init(), and frees - * any resources it uses (all the nodes it created become invalid). - */ -void -pool_destroy(pool_t *pool) -{ - register bpage_t *p, *t; - - ASSERT(POOL_VALID(pool)); - - /* Destroy all pages of all lists */ - for (p = DLIST_TOP(&pool->pages); p != NULL; p = t) { - t = DLIST_NEXT(p); - (void) pool_page_destroy(p); - } - for (p = DLIST_TOP(&pool->fpages); p != NULL; p = t) { - t = DLIST_NEXT(p); - (void) pool_page_destroy(p); - } - for (p = DLIST_TOP(&pool->epages); p != NULL; p = t) { - t = DLIST_NEXT(p); - (void) pool_page_destroy(p); - } - - /* Invalidate pool_t */ - pool->magic = 0; -} - - -/* - * Allows to very efficiently allocate a single node from the specified pool, - * optionally initializing it's memory to zeros. Returns the newly allocated - * node pointer on success, or NULL on error. - */ -pnode_t * -pool_alloc(pool_t *pool, int zero) -{ - pnode_t *pnode = NULL; - register bpage_t *page; - - ASSERT(POOL_VALID(pool)); - ASSERT(!zero || pool->create == NULL); - - /* Are there any partially used pages? */ - if ((page = DLIST_TOP(&pool->pages)) == NULL) { - /* - * No, we thus attempt to move a page from our empty pages - * cache back into our usable pages list. The order of the - * usable page list becomes irrelevant at DLIST_SWAP() since - * it will be the only node. - */ - if ((page = DLIST_TOP(&pool->epages)) == NULL) { - /* - * No more free pages in our cache neither. - * If maxpages is set and not yet reached, we need - * to create a new page. If we can't, return NULL - * for error. - */ - if (pool->maxpages == 0 || - DLIST_NODES(&pool->fpages) < pool->maxpages) { - if ((page = pool_page_create("pool_alloc", - pool)) == NULL) - return NULL; - DLIST_APPEND(&pool->pages, (node_t *)page); - } else - return NULL; - } else - DLIST_SWAP(&pool->pages, &pool->epages, (node_t *)page, - 0); - } - - /* - * now points to a page we know we can at least get a free - * object node from. Obtain one and unlink it. - */ - pnode = DLIST_TOP(&page->objects); - DLIST_UNLINK(&page->objects, (node_t *)pnode); - - /* - * Have we obtained the last available object from this page? - * If so, move the page to the full pages list. The order of the - * full pages list nodes is irrelevant, since we don't know which - * of those pages are more likely to be swapped to the usable - * pages list first, and we won't run through that list, except at - * pool_destroy(). - */ - if (DLIST_NODES(&page->objects) == 0) - DLIST_SWAP(&pool->fpages, &pool->pages, (node_t *)page, 0); - - /* - * If requested, zero object. This is stupid if a constructor and - * destructor are used, but can be useful otherwise. - */ - if (zero) { - page = pnode->page; - (void) memset(pnode, 0, pool->nodesize); - pnode->page = page; - } - - /* Mark this node as a valid allocated object */ - pnode->magic = MAGIC_PNODE; - - return pnode; -} - - -/* - * Efficiently frees the specified node back to the pool it was allocated from. - * Returns NULL. Uses heuristics keeping statistics to determine when to - * actually shrink the memory blocks internally used by the pool, so that - * frequently growing and shrinking pools will remain large for scalability. - * This also makes a big difference when constructors and destructors are used - * and need to execute a significant amount of code. - */ -pnode_t * -pool_free(pnode_t *pnode) -{ - register bpage_t *page = pnode->page; - register pool_t *pool = page->pool; - register uint32_t count; - - ASSERT(PNODE_VALID(pnode)); - - /* Invalidate object */ - pnode->magic = 0; - - /* - * Record how many nodes there currently are in our page's object - * list, to be used later on - */ - count = DLIST_NODES(&page->objects); - - /* - * Add node back to it's page's object list. Insert it so that we - * favor reuse of recently used objects soon. - */ - DLIST_INSERT(&page->objects, (node_t *)pnode); - - /* - * Was this page full before we inserted our node? If so, page is in - * full pages list. Move it to the usable pages list. Insert it to - * favor reuse of recently used pages soon (this page will soon return - * back to the full pages list). - */ - if (count == 0) - DLIST_SWAP(&pool->pages, &pool->fpages, (node_t *)page, 1); - else { - /* - * Did we cause our node insertion to totally free back the - * page? If so, the page is on the usable free list, but move - * it back to the empty pages list. Insert it to favor reuse - * of recently used pages soon (this page will be the first to - * get used again when the usable pages list needs pages). - */ - if (++count == pool->nodesperpage) { - DLIST_SWAP(&pool->epages, &pool->pages, (node_t *)page, - 1); - } - } - - if ((pool->minpages < pool->maxpages) || - (pool->minpages == 0 && pool->maxpages == 0)) { - register int exceeding; - - /* - * This pool_t is allowed to shrink. Maintain average pages - * usage to prevent destroying our pages in the empty pages - * list unless we should. - */ - count = DLIST_NODES(&pool->pages) + DLIST_NODES(&pool->fpages); - pool->avgtotal += count; - pool->avgcnt++; - - /* - * Using * 8 here means that pool_free() needs to at least be - * called to release as much objects as can fit into eight full - * pages in order to execute the following block. But of - * course, this does not mean that eight pages will recently - * have been freed, since allocations probably also occured - * meanwhile. - */ - if (pool->avgcnt > pool->nodesperpage * 8) { - /* - * Do statistics suggest that we should shrink the - * pool? If so, free pages from our empty pages - * cache back to the system, destroying their objects - * if necessary. We'll make sure to at least leave a - * one page hysterisis for better performance. - */ - if ((exceeding = (count + DLIST_NODES(&pool->epages) - - 1) - (pool->avgtotal / pool->avgcnt)) > 0) { - register list_t *epages = &pool->epages; - - /* - * Preferably free pages which haven't been - * used recently. - */ - for (; exceeding > 0 && - (page = DLIST_BOTTOM(epages)) != NULL; - exceeding--) { - DLIST_UNLINK(epages, (node_t *)page); - (void) pool_page_destroy(page); - } - } - /* Reset statistics */ - pool->avgcnt = 1; - pool->avgtotal = count; - } - } - - return NULL; -} diff --git a/tests/sdl-client/pool.h b/tests/sdl-client/pool.h deleted file mode 100644 index f132c3c..0000000 --- a/tests/sdl-client/pool.h +++ /dev/null @@ -1,122 +0,0 @@ -/* $Id: pool.h,v 1.1 2006/04/27 10:59:19 mmondor Exp $ */ - -/* - * Copyright (C) 2001-2006, Matthew Mondor - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Matthew Mondor. - * 4. The name of Matthew Mondor may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * 5. Redistribution of source code may not be released under the terms of - * any GNU Public License derivate. - * - * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - - - -#ifndef MPOOL_H -#define MPOOL_H - - - -#include - -#include - - - -/* Useful to o-align a value relative to v (sizes and pointers) */ -#define OALIGN_CEIL(v, o) \ - ((((size_t)(v)) + (sizeof(o)) - 1) / (sizeof(o)) * (sizeof(o))) -#define OALIGN_FLOOR(v, o) ((size_t)(v) - (((size_t)(v) % sizeof(o)))) - -/* Useful to byte align a value with supplied size */ -#define BALIGN_CEIL(v, s) ((((size_t)(v)) + (s) - 1) / (s) * (s)) -#define BALIGN_FLOOR(v, s) ((size_t)(v) - (((size_t)(v) % (s)))) - - - -typedef struct pnode pnode_t; -typedef struct bpage bpage_t; -typedef struct pool pool_t; - - - -#define MAGIC_POOL 0x504f4f4c /* POOL */ -#define MAGIC_PAGE 0x50414745 /* PAGE */ -#define MAGIC_PNODE 0x504e4f44 /* PNOD */ - -#define POOL_VALID(p) ((p) != NULL && (p)->magic == MAGIC_POOL) -#define PNODE_VALID(p) ((p) != NULL && (p)->magic == MAGIC_PNODE && \ - (p)->page != NULL && (p)->page->magic == MAGIC_PAGE && \ - (p)->page->pool != NULL && (p)->page->pool->magic == MAGIC_POOL) - - - -/* Header structure of internally allocated/prepared page/blocks */ -struct bpage { - node_t node; - uint32_t magic; - pool_t *pool; - list_t objects; -}; - -/* Header structure of individual pool objects */ -struct pnode { - node_t node; - uint32_t magic; - bpage_t *page; -}; - -/* Pool control structure */ -struct pool { - pnode_t node; /* Hey, we never know, a pool_t of pool_t */ - uint32_t magic; - const char *label; - void *(*malloc)(size_t); - void (*free)(void *); - int (*create)(pnode_t *); - void (*destroy)(pnode_t *); - size_t nodesize, pagesize; - uint32_t minpages, maxpages, nodesperpage; - uint32_t avgtotal, avgcnt; - /* Usable pages, totally full/busy pages, totally empty/free pages */ - list_t pages, fpages, epages; -}; - - - -/* Public API prototypes */ -extern int pool_init(pool_t *, const char *, void *(*)(size_t), - void (*)(void *), int (*)(pnode_t *), - void (*)(pnode_t *), size_t, - uint32_t, uint32_t, uint32_t); -extern void pool_destroy(pool_t *); -extern pnode_t * pool_alloc(pool_t *, int); -extern pnode_t * pool_free(pnode_t *); - - - -#endif diff --git a/tests/sdl-client/rawobjs.h b/tests/sdl-client/rawobjs.h deleted file mode 100644 index 89d59bc..0000000 --- a/tests/sdl-client/rawobjs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* $Id: rawobjs.h,v 1.4 2006/05/10 00:48:40 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* XXX This file should probably be auto-generated */ - - - -#ifndef RAWOBJS_H -#define RAWOBJS_H - - - -/* - * On win32, binary objects must be referenced without the underscore prefix. - * Let's then define a few aliases. - */ -#ifdef WIN32 - -#define _binary_bmp_FedCA_bmp_enc_size binary_bmp_FedCA_bmp_enc_size -#define _binary_bmp_FedCA_bmp_enc_start binary_bmp_FedCA_bmp_enc_start -#define _binary_bmp_RomDD_bmp_enc_size binary_bmp_RomDD_bmp_enc_size -#define _binary_bmp_RomDD_bmp_enc_start binary_bmp_RomDD_bmp_enc_start - -#define _binary_wav_nt_cloaked_wav_enc_size binary_wav_nt_cloaked_wav_enc_size -#define _binary_wav_nt_cloaked_wav_enc_start binary_wav_nt_cloaked_wav_enc_start -#define _binary_wav_nt_explosion_other_wav_enc_size binary_wav_nt_explosion_other_wav_enc_size -#define _binary_wav_nt_explosion_other_wav_enc_start binary_wav_nt_explosion_other_wav_enc_start -#define _binary_wav_nt_fire_torp_other_wav_enc_size binary_wav_nt_fire_torp_other_wav_enc_size -#define _binary_wav_nt_fire_torp_other_wav_enc_start binary_wav_nt_fire_torp_other_wav_enc_start -#define _binary_wav_nt_plasma_hit_wav_enc_size binary_wav_nt_plasma_hit_wav_enc_size -#define _binary_wav_nt_plasma_hit_wav_enc_start binary_wav_nt_plasma_hit_wav_enc_start -#define _binary_wav_nt_shield_down_wav_enc_size binary_wav_nt_shield_down_wav_enc_size -#define _binary_wav_nt_shield_down_wav_enc_start binary_wav_nt_shield_down_wav_enc_start -#define _binary_wav_nt_shield_up_wav_enc_size binary_wav_nt_shield_up_wav_enc_size -#define _binary_wav_nt_shield_up_wav_enc_start binary_wav_nt_shield_up_wav_enc_start -#define _binary_wav_nt_uncloak_wav_enc_size binary_wav_nt_uncloak_wav_enc_size -#define _binary_wav_nt_uncloak_wav_enc_start binary_wav_nt_uncloak_wav_enc_start - -#define _binary_fnt_7x13_fnt_enc_start binary_fnt_7x13_fnt_enc_start -#define _binary_fnt_7x13_fnt_enc_size binary_fnt_7x13_fnt_enc_size - -#endif - - - -/* - * And export symbols to other modules - */ - -extern void *_binary_bmp_FedCA_bmp_enc_size; -extern void *_binary_bmp_FedCA_bmp_enc_start; -extern void *_binary_bmp_RomDD_bmp_enc_size; -extern void *_binary_bmp_RomDD_bmp_enc_start; - -extern void *_binary_wav_nt_cloaked_wav_enc_size; -extern void *_binary_wav_nt_cloaked_wav_enc_start; -extern void *_binary_wav_nt_explosion_other_wav_enc_size; -extern void *_binary_wav_nt_explosion_other_wav_enc_start; -extern void *_binary_wav_nt_fire_torp_other_wav_enc_size; -extern void *_binary_wav_nt_fire_torp_other_wav_enc_start; -extern void *_binary_wav_nt_plasma_hit_wav_enc_size; -extern void *_binary_wav_nt_plasma_hit_wav_enc_start; -extern void *_binary_wav_nt_shield_down_wav_enc_size; -extern void *_binary_wav_nt_shield_down_wav_enc_start; -extern void *_binary_wav_nt_shield_up_wav_enc_size; -extern void *_binary_wav_nt_shield_up_wav_enc_start; -extern void *_binary_wav_nt_uncloak_wav_enc_size; -extern void *_binary_wav_nt_uncloak_wav_enc_start; - -extern void *_binary_fnt_7x13_fnt_enc_start; -extern void *_binary_fnt_7x13_fnt_enc_size; - - - -#endif diff --git a/tests/sdl-client/screen.c b/tests/sdl-client/screen.c deleted file mode 100644 index 4cf25f2..0000000 --- a/tests/sdl-client/screen.c +++ /dev/null @@ -1,65 +0,0 @@ -/* $Id: screen.c,v 1.11 2006/05/08 21:05:17 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Display related initialization. - */ - - - -#include -#include - -#include - -#include -#include - - - -#define SCREEN_WIDTH 1024 -#define SCREEN_HEIGHT 768 - - - -SDL_Surface *screen_surface; -int screen_width, screen_height; -SDL_Joystick *gamepad; - - - -void -screen_init(void) -{ - - if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { - (void) fprintf(stderr, "main() - SDL_Init() - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if ((screen_surface = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, - SDL_DOUBLEBUF | SDL_FULLSCREEN)) == NULL) { - (void) fprintf(stderr, "main() - SDL_SetVideoMode() - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - - if (SDL_NumJoysticks > 0) - gamepad = SDL_JoystickOpen(0); - - screen_width = SCREEN_WIDTH; - screen_height = SCREEN_HEIGHT; - - (void) atexit(screen_destroy); -} - -void -screen_destroy(void) -{ - - SDL_Quit(); -} diff --git a/tests/sdl-client/screen.h b/tests/sdl-client/screen.h deleted file mode 100644 index d98322f..0000000 --- a/tests/sdl-client/screen.h +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id: screen.h,v 1.3 2006/05/08 08:17:00 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Screen related initialization. - */ - - - -#ifndef SCREEN_H -#define SCREEN_H - - - -#include - - - -extern SDL_Surface *screen_surface; -extern int screen_width, screen_height; -extern SDL_Joystick *gamepad; - - - -void screen_init(void); -void screen_destroy(void); - - - -#endif diff --git a/tests/sdl-client/tests/draw.c b/tests/sdl-client/tests/draw.c deleted file mode 100644 index da2c393..0000000 --- a/tests/sdl-client/tests/draw.c +++ /dev/null @@ -1,948 +0,0 @@ -/* $Id: draw.c,v 1.1 2006/05/03 14:20:47 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * XXX TODO XXX - * - Fix most all code using multiplication to locate x,y pixel positions into - * the display to use the screen_lines array for optimization. - * This however could cause a problem for SDL surfaces other than the screen - * which are involved. A possibility to fix this would be to wrap the - * SDL_Surface into a custom structure, which could also hold the optimized - * line position array for each... - * - Implement a diff function, to fill a surface with the difference between - * two other surfaces... This might be good for some type of effects and - * animations. Hmm there possibly would be a problem with the 0 transparent - * color though... Consider following situation: - * - Diff detects new 0 color pixels in second image, how would we effect - * transformation of first image to second one, since we can't blit zero - * color images? If we did blit zero color, how would we detect what - * pixels consist in the difference? Perhaps that we would need a special - * diff format rather than just blitting differences into a zero color - * surface. Diff format could be very similar to runlength-style encoding - * format, if not the same, perhaps. I would only need to add section - * support, other than just compression... I.E. section starting at x,y, - * of total length l, followed by runlength compressed section... - * Such diffs might also be nice to send over the network when images change - * or such... - * - Implement simple runlength compression and decompression support, with - * possibly load/save image support. - * - Maybe implement simple animation format based on above diff and runlength - * support. It would be enough to implement small animated sets with limited - * motion. - * - Implement ellipse and ellipse arc support - * - Splines support would be great but I would need to read about it. - * If really required, SDL_gfx might be worth using. - * - Once all required primitives have been implemented, allow support for - * parallel postscript commands output, so that it would be possible to - * print results. This would allow to have consistent on-screen and printer - * results (this is not game related, it could be used for applications). - * * Postscript has all of the above. It actually would be nice if I could - * have my application draw postscript in real time while internally keeping - * the necessary information in memory of the screen state to be able to - * also print to a postscript printer. It seems that ghostscript has a - * graphics library. Can it be used by a third party application easily? - * Also, if I used postscript, how would I allow bitmap images to be - * supported? Especially as the relative scaling of everything would have - * to be respected? - * - It also would be possible to simply use X11R6. However, this would - * limit client applications to run on unix systems in most cases. - * Moreover, I probably would still require some kind of hack to - * internally keep track of postscript equivalents for printing, or the - * contrary, to process using postscript and draw using X11, etc... - * I of course still would need to provide my own toolkit. - * - The main problem I would have with both above techniques is dealing - * with fonts. Obviously, fonts would need to be vectorial, and in a way - * which is useful for postscript output. I would need to have an onscreen - * WYSIWYG renderer for the same type of fonts. X11 can supposedly output - * GS fonts to screen, using the X Font Server (XFS)... But this requires - * clients to have a special configuration, once more. - * NOTE: This is fixed, SDL_ttf can be used. - * - It would be possible to use bitmap fonts, as long as they are of the - * right size to be equivalent to the postscript output, and that the - * screen has proper visual to represent the page... If we support - * proportional fonts, some new code would need to be added. Moreover, we - * probably would not want the proportional fonts to be used where the - * user types text, to ease the editor's tasks... We would need to at - * least support fixed/courrier, times and helvetica. We would need a font - * format which can specify the size of each character of proportional - * fonts. Maybe an aditionnal data file along with the bitmap file... - */ - - - -/* HEADERFILES */ - -#include -#include -#include - -#include - -#include -#include -#include - - - -/* DEFINITIONS */ - -#ifdef ANTIALIASING /* conf.h */ -#define DRAW_PIXEL draw_pixel_antialias -#else -#define DRAW_PIXEL draw_pixel -#endif - - - -/* STATIC FUNCTIONS PROTOTYPES */ - - - -/* GLOBALS */ - -static draw_point_t *stack_start, *stack_pos, pen; -static double sin_table[1000], cos_table[1000]; -static uint32_t **screen_lines; - - - -/* PRIVATE FUNCTIONS */ - - - -/* PUBLIC FUNCTIONS */ - -int -draw_init(void) -{ - - /* Allocate memory for draw_fill_*() stack */ - if ((stack_start = malloc(sizeof(draw_point_t) * - (screen_width * screen_height) * 4)) == NULL) - return -1; - - /* - * Allocate and initialize fast screen display line index lookup table, - * which can be used by pixel drawing routines without the need for - * multiplications. - */ - { - uint32_t *lptr; - int i; - - if ((screen_lines = malloc(sizeof(uint32_t *) * - screen_height)) == NULL) - return -1; - - for (lptr = (uint32_t *)(screen_surface->pixels), i = 0; - i < screen_height; i++, lptr += screen_width) - screen_lines[i] = lptr; - } - - /* - * Initialize our sin/cos trigonometric functions arrays for - * performance when mesuring rotations in radians. - * XXX We should add pixel ratio modifyer too here. - */ - { - int i; - double f; - - for (i = 0; i < 1000; i++) { - f = ((2 * M_PI) / 1000) * (i - 250); - sin_table[i] = sin(f); - cos_table[i] = cos(f); - } - } - - return 0; -} - -/* The following functions require that screen_surface be locked. */ - -/* Draws a vertical line at specified position and of specified height */ -inline void -draw_vline(draw_point_t *p, int height, uint32_t col) -{ - register uint32_t *ptr; - register int i; - - assert(p != NULL); - assert(!(p->x < 0 || p->x >= screen_width || - p->y < 0 || p->y + height > screen_height)); - - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (p->y * screen_width) + p->x], i = height; i > 0; - i--, ptr = &ptr[screen_width]) - *ptr = col; -} - -/* Draws an horizontal line at specified position and of specified width */ -inline void -draw_hline(draw_point_t *p, int width, uint32_t col) -{ - register uint32_t *ptr, *tptr; - - assert(p != NULL); - assert(!(p->x < 0 || p->x + width > screen_width || - p->y < 0 || p->y >= screen_height)); - - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (p->y * screen_width + p->x)], tptr = &ptr[width]; ptr < tptr; ) - *ptr++ = col; -} - -/* - * Draws a rectangle of specified colors. Two colors can be specified for a - * special 3d-like effect (although both can be the same if wanted). - */ -inline void -draw_rect(draw_rect_t *r, uint32_t hicol, uint32_t locol) -{ - draw_point_t p; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - p.x = r->x; - p.y = r->y; - draw_hline(&p, r->w, hicol); - p.y++; - draw_vline(&p, r->h - 1, hicol); - p.x = r->x + r->w - 1; - p.y--; - draw_vline(&p, r->h, locol); - p.x = r->x + 1; - p.y = r->y + r->h - 1; - draw_hline(&p, r->w - 1, locol); -} - -/* - * Draws rectangular box at (x,y) to (x+w-1,y+h-1), using lcol for the 3d - * border light color, dcol for 3d border dark color, filled with fcol (or 0 - * for transparent interior) and of specified 3d depth. - */ -void -draw_rect_3d(draw_rect_t *r, uint32_t hicol, uint32_t locol, uint32_t fillcol, - int depth) -{ - draw_rect_t rect; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - if (fillcol != 0) { - rect.x = r->x + 1; - rect.y = r->y + 1; - rect.w = r->w - 2; - rect.h = r->h - 2; - draw_rect_fill(&rect, fillcol); - } - rect = *r; - for (; depth > 0; depth--, rect.x += 1, rect.y += 1, - rect.w -= 2, rect.h -= 2) - draw_rect(&rect, hicol, locol); -} - -/* Allows to fill specified rectangle with specified color */ -inline void -draw_rect_fill(draw_rect_t *r, uint32_t col) -{ - register uint32_t *ptr, *tptr = NULL, *lptr; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - if (r->w == screen_width) { - /* - * Even better optimization, setting an entire single block of - * multiple lines together. - * XXX Should use lines array - */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (r->y * screen_width) + r->x], - tptr = &ptr[screen_width * r->h]; - ptr < tptr; ) - *ptr++ = col; - } else { - /* Use line-based optimizations */ - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (r->y * screen_width) + r->x], - tptr = &((uint32_t *)screen_surface->pixels)[ - ((r->y + r->h - 1) * screen_width) + (r->x + r->w)]; - ptr < tptr; ptr = &ptr[screen_width - r->w]) { - for (lptr = &ptr[r->w]; ptr < lptr; ) - *ptr++ = col; - } - } -} - -/* - * Similar to draw_rect_fill(), but causes pixels to be XORed against m, - * to toggle their bits. This is reversable by another call to this function - * on the same area again. This can be useful for the implementation of a - * block cursor. However, because of the disposition of the current 256 color - * palette, the effect might not be what is expected (some colors will render - * too bright or too dark to be considered an inversing effect). - */ -void -draw_rect_fill_xor(draw_rect_t *r, uint32_t mask) -{ - register uint32_t *ptr, *toptr, *lptr; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (r->y * screen_width) + r->x], - toptr = &((uint32_t *)screen_surface->pixels)[ - ((r->y + r->h - 1) * screen_width) + (r->x + r->w)]; - ptr < toptr; ptr = &ptr[screen_width - r->w]) { - for (lptr = &ptr[r->w]; ptr < lptr; ) - *ptr++ ^= mask; - } -} - -/* - * Similar to draw_rect_fill(), but causes pixels which are not of the bgcol - * to be reversed to the bgcol. Other pixels, which already were of bgcol are - * set to col. This function is useful for the implementation of a block - * cursor. - */ -void -draw_rect_fill_inverse(draw_rect_t *r, uint32_t col, uint32_t bgcol) -{ - register uint32_t *ptr, *toptr, *lptr; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (r->y * screen_width) + r->x], - toptr = &((uint32_t *)screen_surface->pixels)[ - ((r->y + r->h - 1) * screen_width) + (r->x + r->w)]; - ptr < toptr; ptr = &ptr[screen_width - r->w]) { - for (lptr = &ptr[r->w]; ptr < lptr; ptr++) - *ptr = (*ptr == bgcol ? col : bgcol); - } -} - -/* - * Very similar to draw_rect_fill(), but causes empty/transparent pixels to be - * left at 50%. Can be used to simulate transparency without the need for - * alpha values. Especially useful with restricted palettes, or simply to - * create an effect. - */ -void -draw_rect_fill_transparent(draw_rect_t *r, uint32_t col) -{ - register uint32_t *ptr, *toptr, *lptr; - int even; - - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > screen_width || - r->y < 0 || r->y + r->h > screen_height)); - - /* XXX Should use lines array */ - for (ptr = &((uint32_t *)screen_surface->pixels)[ - (r->y * screen_width) + r->x], - toptr = &((uint32_t *)screen_surface->pixels)[ - ((r->y + r->h - 1) * screen_width) + (r->x + r->w)], even = 0; - ptr < toptr; - ptr = &ptr[screen_width - r->w], even = (even == 0 ? 1 : 0)) { - ptr += even; - for (lptr = &ptr[r->w]; ptr < lptr; ptr += 2) - *ptr = col; - ptr -= even; - } -} - -/* - * Similar to SDL_BlitSurface(), but less efficient, it allows to blit the - * specified image in one color. All non-zero pixels are copied, while others - * are output as fg. In the case where bg is non-zero, zero pixels output bg. - * The screen surface should be locked when calling this function. - */ -void -draw_surface_color(SDL_Surface *surface, draw_rect_t *r, draw_point_t *p, - uint32_t fg, uint32_t bg) -{ - register uint32_t *dstptr, *tdstptr, *srcptr, *tptr; - - assert(surface != NULL); - assert(r != NULL); - assert(p != NULL); - assert(!(r->x < 0 || r->x + r->w > surface->w || - r->y < 0 || r->y + r->h > surface->h)); - assert(!(p->x < 0 || p->x + r->w > surface->w)); - - /* - * For performance we want to avoid having to include the bg color - * check every loop iteration. We prefer to have two loops instead. - * Moreover, we optimize the loop as such to avoid multiplications - * and divisions, using a line-based algorithm with additions only. - */ - if (bg == 0) { - /* XXX Should use lines array */ - for (dstptr = &((uint32_t *)screen_surface->pixels)[ - (p->y * screen_width) + p->x], - tdstptr = &((uint32_t *)screen_surface->pixels)[ - ((p->y + r->h - 1) * screen_width) + (p->x + r->w)], - srcptr = &((uint32_t *)surface->pixels)[ - (r->y * surface->w) + r->x]; - dstptr < tdstptr; - dstptr = &dstptr[screen_width - r->w], - srcptr = &srcptr[surface->w - r->w]) { - for (tptr = &dstptr[r->w]; dstptr < tptr; - dstptr++, srcptr++) { - if ((*srcptr & 0xff000000) != 0) - *dstptr = fg; - } - } - } else { - /* XXX Should use lines array */ - for (dstptr = &((uint32_t *)screen_surface->pixels)[ - (p->y * screen_width) + p->x], - tdstptr = &((uint32_t *)screen_surface->pixels)[ - ((p->y + r->h - 1) * screen_width) + (p->x + r->w)], - srcptr = &((uint32_t *)surface->pixels)[ - (r->y * surface->w) + r->x]; - dstptr < tdstptr; - dstptr = &dstptr[screen_width - r->w], - srcptr = &srcptr[surface->w - r->w]) { - for (tptr = &dstptr[r->w]; dstptr < tptr; ) - *dstptr++ = ((*srcptr++ & 0xff000000) == 0 ? - bg : fg); - } - } -} - -void -draw_surface_color_antialias(SDL_Surface *surface, draw_rect_t *r, - draw_point_t *p, uint32_t fg, uint32_t bg) -{ - register uint32_t *srcptr, *tsrcptr, *tptr; - register int x, y; - - assert(surface != NULL); - assert(r != NULL); - assert(p != NULL); - assert(!(r->x < 0 || r->x + r->w > surface->w || - r->y < 0 || r->y + r->h > surface->h)); - assert(!(p->x < 0 || p->x + r->w > screen_width || - p->y < 0 || p->y + r->h > screen_height)); - - /* XXX Should use lines array */ - for (tsrcptr = &((uint32_t *)surface->pixels)[ - ((r->y + r->h - 1) * surface->w) + (r->x + r->w)], - srcptr = &((uint32_t *)surface->pixels)[ - (r->y * surface->w) + r->x], - y = p->y; - srcptr < tsrcptr; - srcptr = &srcptr[surface->w - r->w], y++) { - for (x = p->x, tptr = &srcptr[r->w]; srcptr < tptr; - srcptr++, x++) { - if (bg == 0) { - if ((*srcptr & 0xff000000) != 0) - draw_pixel_antialias(x, y, fg); - } else - draw_pixel_antialias(x, y, - ((*srcptr & 0xff000000) == 0 ? bg : fg)); - } - } -} - -/* - * Similar to SDL_BlitSurface(), but less efficient, it allows to blit a - * perfect copy of a surface area to another surface area. This is most useful - * when colors have been setup as transparent and that an opaque identical - * copy is wanted. - */ -void -draw_surface_copy(SDL_Surface *dstsurface, draw_point_t *p, - SDL_Surface *srcsurface, draw_rect_t *r) -{ - uint32_t *dstptr, *tdstptr, *srcptr, *tptr; - - assert(dstsurface != NULL); - assert(p != NULL); - assert(srcsurface != NULL); - assert(r != NULL); - assert(!(r->x < 0 || r->x + r->w > srcsurface->w || - r->y < 0 || r->y + r->h > srcsurface->h)); - assert(!(p->x < 0 || p->x + r->w > dstsurface->w || - p->y < 0 || p->y + r->h > dstsurface->h)); - - /* XXX Should use lines array */ - for (dstptr = &((uint32_t *)dstsurface->pixels)[ - (p->y * dstsurface->w) + p->x], - tdstptr = &((uint32_t *)dstsurface->pixels)[ - ((p->y + r->h - 1) * dstsurface->w) + (p->x + r->w)], - srcptr = &((uint32_t *)srcsurface->pixels)[ - (r->y * srcsurface->w) + r->x]; - dstptr < tdstptr; - dstptr = &dstptr[dstsurface->w - r->w], - srcptr = &srcptr[srcsurface->w - r->w]) { - for (tptr = &dstptr[r->w]; dstptr < tptr; ) - *dstptr++ = *srcptr++; - } -} - -/* - * Blits a single pixel of specified color to screen at specified position. - * Note that this function does not consider color 0 to be transparent. - * This function, by exception, does not require the use of a draw_point_t. - * This allows to use register based optimizations in functions calling us - * (They do not need to keep counters in a memory structure when looping). - */ -inline void -draw_pixel(int x, int y, uint32_t col) -{ - - /* - * Instead of using this alternative, which requires multiplication: - * ((uint32_t *)screen_surface->pixels)[(y * screen_width) + x] = col; - * Use the advantage of our screen_lines array for indexing - * optimization. - */ - screen_lines[y][x] = col; -} - -inline void -draw_pixel_transparent(int x, int y, uint32_t col, int alpha) -{ - uint32_t ccol; - - /* This condition can happen because we are called for antialiasing */ - if (x >= screen_width || x < 0 || y >= screen_height || y < 0) - return; - - alpha &= 0xff; - - /* First optimize possible cases */ - if (alpha == 0x00) - return; - if (alpha == 0xff) { - draw_pixel(x, y, col); - return; - } - - /* Transparently blit pixel if necessary */ - if ((ccol = draw_getpixel2(x, y)) != col) { - int r, g, b, nr, ng, nb; - - /* - * Decompose into r, g, b levels, first current screen pixel - * color - */ - r = ((ccol & 0x00ff0000) >> 16); - g = ((ccol & 0x0000ff00) >> 8); - b = (ccol & 0x000000ff); - /* Then supplied color */ - nr = ((col & 0x00ff0000) >> 16); - ng = ((col & 0x0000ff00) >> 8); - nb = (col & 0x000000ff); - - /* - * Apply opacity modification on supplied color according to - * alpha - */ - nr = nr * alpha / 0xff; - ng = ng * alpha / 0xff; - nb = nb * alpha / 0xff; - - /* - * XXX bug here! Works fine when blitting lighter colors on - * darker ones, but not for dark colors over brighter - * background. I probably need something as simple as reverse - * proportional function or such... - */ - /* Mix supplied color with pixel color */ - if ((r = (r + nr) / 2) > 0xff) - r = 0xff; - if ((g = (g + ng) / 2) > 0xff) - g = 0xff; - if ((b = (b + nb) / 2) > 0xff) - b = 0xff; - - /* Recompose into a 32-bit color */ - ccol = (((r << 16) & 0x00ff0000) | ((g << 8) & 0x0000ff00) | - (b & 0x000000ff)); - - /* Finally blit resulting pixel back to screen */ - draw_pixel(x, y, ccol); - } -} - -/* - * XXX Test. - */ -inline void -draw_pixel_antialias(int x, int y, uint32_t col) -{ -#define AA_T 0xd0 /*0x60*/ - - assert(!(x >= screen_width || x < 0 || y >= screen_height || y < 0)); - - draw_pixel(x, y, col); - draw_pixel_transparent(x, y - 1, col, AA_T); - draw_pixel_transparent(x + 1, y, col, AA_T); - draw_pixel_transparent(x, y + 1, col, AA_T); - draw_pixel_transparent(x - 1, y, col, AA_T); - -#undef AA_T -} - -/* Returns the color of pixel at specified location on screen. */ -inline uint32_t -draw_getpixel(draw_point_t *p) -{ - - assert(p != NULL); - - return screen_lines[p->y][p->x]; -} - -inline uint32_t -draw_getpixel2(int x, int y) -{ - - return screen_lines[y][x]; -} - -/* - * Blits a line on screen of specified color (x,y)->(x2,y2). Note that color 0 - * is not considered transparent. Probably does not use the best algorithm, - * but SDL doesn't provide hardware line blitting support, and I at least - * needed such a function... This seems to be fast enough, using this - * home-rolled algorithm for now. - */ -/* XXX Modify so that it performs a gradient using draw_pixel_transparent() - * with various alpha values when lines are nor vertical, horizontal or - * diagonal. I.E. - * --++-- - * --++-- - * This is apparently a known antialiasing algorithm for lines and would - * probably be faster than using my current method. - */ -void -draw_line(draw_point_t *p1, draw_point_t *p2, uint32_t col) -{ - int ix, iy; - register int x, y, tx, ty; - double f, fa; - - assert(p1 != NULL); - assert(p2 != NULL); - assert(!(p1->x < 0 || p1->x >= screen_width || - p1->y < 0 || p1->y >= screen_height)); - assert(!(p2->x < 0 || p2->x >= screen_width || - p2->y < 0 || p2->y >= screen_height)); - - /* - * Convert quadrant 1 to 3, and quadrant 2 to 4. This ensures that we - * only need to blit the line from top to bottom. - */ - if (p1->y > p2->y) { - draw_point_t *p; - - p = p1; - p1 = p2; - p2 = p; - } - - /* Test for cases which can easily be optimized */ - if (p1->x == p2->x) { - if (p1->y == p2->y) { - /* Only a single pixel to blit */ - draw_pixel(p1->x, p1->y, col); - return; - } - /* We can use draw_vline() */ - draw_vline(p1, (p2->y - p1->y), col); - return; - } - if (p1->y == p2->y) { - /* We can use draw_hline() */ - if (p1->x < p2->x) - draw_hline(p1, (p2->x - p1->x), col); - else - draw_hline(p2, (p1->x - p2->x), col); - return; - } - - if (p1->x < p2->x) { - /* Left to right blitting, quadrant 4 */ - - /* Obtain width/height ratio */ - ix = p2->x - p1->x; - iy = p2->y - p1->y; - if (ix == iy) { - /* - * Equal ratio, no need to use floating point - * arithmetic - */ - for (x = p1->x, y = p1->y, tx = p2->x, ty = p2->y; - x <= tx && y <= ty; x++, y++) - DRAW_PIXEL(x, y, col); - } else if (ix > iy) { - /* - * XXX Use tf double instead of converting f to int - * in comparision and test if speed is gained - */ - /* X ratio larger, use floating point for Y count */ - for (fa = (double)iy / (double)ix, - f = (double)p1->y, x = p1->x, tx = p2->x; - (int)f <= p2->y && x <= tx; x++, f += fa) - DRAW_PIXEL(x, (int)f, col); - } else { - /* Y ratio larger, use floating point for X count */ - for (fa = (double)ix / (double)iy, - f = (double)p1->x, y = p1->y, ty = p2->y; - (int)f <= p2->x && y <= ty; y++, f += fa) - DRAW_PIXEL((int)f, y, col); - } - } else { - /* Right to left blitting, quadrant 3 */ - - /* Obtain width/height ratio */ - ix = p1->x - p2->x; - iy = p2->y - p1->y; - if (ix == iy) { - /* - * Equal ratio, no need to use floating point - * arithmetic - */ - for (x = p1->x, y = p1->y, tx = p2->x, ty = p2->y; - x >= tx && y <= ty; x--, y++) - DRAW_PIXEL(x, y, col); - } else if (ix > iy) { - /* X ratio larger, use floating point for Y count */ - for (fa = (double)iy / (double)ix, - f = (double)p1->y, x = p1->x, tx = p2->x; - (int)f <= p2->y && x >= tx; x--, f += fa) - DRAW_PIXEL(x, (int)f, col); - } else { - /* Y ratio larger, use floating point for X count */ - for (fa = (double)ix / (double)iy, - f = (double)p1->x, y = p1->y, ty = p2->y; - (int)f >= p2->x && y <= ty; y++, f -= fa) - DRAW_PIXEL((int)f, y, col); - } - } -} - -inline void -draw_moveto(draw_point_t *p) -{ - - assert(p != NULL); - assert(!(p->x < 0 || p->x >= screen_width || - p->y < 0 || p->y >= screen_height)); - - pen = *p; -} - -inline void -draw_lineto(draw_point_t *p, uint32_t col) -{ - - assert(p != NULL); - assert(!(p->x < 0 || p->x >= screen_width || - p->y < 0 || p->y >= screen_height)); - - draw_line(&pen, p, col); - pen = *p; -} - -/* - * Fills the specified region, as long as pixels are bgcol, in all directions. - * This implementation uses a custom stack with iteration to avoid overflowing - * the stack. SDL can internally be compiled against various threading - * libraries, several of which have a fixed stack size (I.E. Pth). Thus, - * filling rather large areas crashes using the previous implementation. - * With this one, we don't need to worry about stack room, since we are using - * the process heap instead. It however may be slower on some architectures - * than implementations using the actual stack. - */ -void -draw_fill_bg(draw_point_t *p, uint32_t col, uint32_t bgcol) -{ - draw_point_t node; - - assert(p != NULL); - assert(!(p->x < 0 || p->x >= screen_width || - p->y < 0 || p->y >= screen_height)); - - stack_pos = stack_start; - *stack_pos++ = *p; - - while (stack_pos > stack_start) { - node = *--stack_pos; - if (!(node.x < 0 || node.y > screen_width - 1 || - node.y < 0 || node.y > screen_height - 1)) { - if (draw_getpixel(&node) == bgcol) { - draw_pixel(node.x, node.y, col); - *stack_pos++ = - (draw_point_t){node.x + 1, node.y}; - *stack_pos++ = - (draw_point_t){node.x, node.y + 1}; - *stack_pos++ = - (draw_point_t){node.x - 1, node.y}; - *stack_pos++ = - (draw_point_t){node.x, node.y - 1}; - } - } - } -} - -/* - * This implementation varies in that all pixels which are not of specified - * colors are filled. This is only useful if you know the borders of your - * surface to fill has the same color. It then allows to perform opaque - * filling over a variety of colors, contrary to the last function. - */ -void -draw_fill_fg(draw_point_t *p, uint32_t col) -{ - draw_point_t node; - - assert(p != NULL); - assert(!(p->x < 0 || p->x >= screen_width || - p->y < 0 || p->y >= screen_height)); - - stack_pos = stack_start; - *stack_pos++ = *p; - - while (stack_pos > stack_start) { - node = *--stack_pos; - if (!(node.x < 0 || node.y > screen_width - 1 || - node.y < 0 || node.y > screen_height - 1)) { - if (draw_getpixel(&node) != col) { - draw_pixel(node.x, node.y, col); - *stack_pos++ = - (draw_point_t){node.x + 1, node.y}; - *stack_pos++ = - (draw_point_t){node.x, node.y + 1}; - *stack_pos++ = - (draw_point_t){node.x - 1, node.y}; - *stack_pos++ = - (draw_point_t){node.x, node.y - 1}; - } - } - } -} - -/* - * Draws a perfect circle pixel-wise, radius , expressed in pixels. - * What it does is draw in four sections, adding pixels at both sides of each - * section until the sections close the circle. - */ -void -draw_circle(draw_point_t *p, int radius, uint32_t col) -{ - int x = 0, y = radius, u = 1, v = 2 * radius - 1, e = 0; - - assert(p != NULL); - assert(!(p->x < 0 || p->x + radius > screen_width || - p->y < 0 || p->y + radius > screen_height || - p->x - radius < 0 || p->y - radius < 0)); - - while (x < y) { - DRAW_PIXEL(p->x + x, p->y + y, col); - DRAW_PIXEL(p->x + y, p->y - x, col); - DRAW_PIXEL(p->x - x, p->y - y, col); - DRAW_PIXEL(p->x - y, p->y + x, col); - x++; - e += u; - u += 2; - if (v < (2 * e)) { - y--; - e -= v; - v -= 2; - } - if (x > y) - break; - DRAW_PIXEL(p->x + y, p->y + x, col); - DRAW_PIXEL(p->x + x, p->y - y, col); - DRAW_PIXEL(p->x - y, p->y - x, col); - DRAW_PIXEL(p->x - x, p->y + y, col); - } -} - -/* - * Returns x/y position in (xp,yp), for point at (x,y) of radius at - * angle (in radians). Uses an array suitable for onscreen resolution - * for efficiency instead of having to always call sin()/cos() functions. - */ -inline void -draw_get_vector(draw_point_t *tp, draw_point_t *p, draw_vect_t *v) -{ - int angle; - - assert(tp != NULL); - assert(p != NULL); - assert(v != NULL); - assert(!(p->x < 0 || p->x + v->r > screen_width || - p->y < 0 || p->y + v->r > screen_height || - p->x - v->r < 0 || p->y - v->r < 0)); - - if ((angle = v->a) < 0) - angle = 1000 - (-angle); - else if (angle > 999) - angle %= 1000; - - tp->x = (int)(p->x + (cos_table[angle] * v->r)); - tp->y = (int)(p->y + (sin_table[angle] * v->r)); -} - -/* - * Slower implementation of draw_circle() using floating point, but which - * can draw arcs. - */ -void draw_circle_arc(draw_point_t *p, int radius, int a1, int a2, int step, - uint32_t col) -{ - register int i; - draw_point_t tp; - draw_vect_t v; - - assert(p != NULL); - assert(!(p->x < 0 || p->x + radius > screen_width || - p->y < 0 || p->y + radius > screen_height || - p->x - radius < 0 || p->y - radius < 0)); - - if (a2 < a1) { - i = a1; - a1 = a2; - a2 = i; - } - v.r = radius; - v.a = a1; - draw_get_vector(&tp, p, &v); - draw_moveto(&tp); - for (i = a1; i <= a2; i += step) { - v.a = i; - draw_get_vector(&tp, p, &v); - draw_lineto(&tp, col); - } - if (i > a2) { - v.a = a2; - draw_get_vector(&tp, p, &v); - draw_lineto(&tp, col); - } -} diff --git a/tests/sdl-client/tests/draw.h b/tests/sdl-client/tests/draw.h deleted file mode 100644 index 2cb3647..0000000 --- a/tests/sdl-client/tests/draw.h +++ /dev/null @@ -1,75 +0,0 @@ -/* $Id: draw.h,v 1.1 2006/05/03 14:22:06 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - -#ifndef DRAW_H -#define DRAW_H - - - -#include - - - -#define SCREEN_LOCK() if (SDL_LockSurface(screen_surface) != 0) \ - abort(); -#define SCREEN_UNLOCK() SDL_UnlockSurface(screen_surface) - - - -typedef struct draw_point { - int x, y; -} draw_point_t; - -typedef struct draw_vect { - int a, r; -} draw_vect_t; - -typedef struct draw_rect { - int x, y; - int w, h; -} draw_rect_t; - - - -extern int draw_init(void); -extern inline void draw_vline(draw_point_t *, int, uint32_t); -extern inline void draw_hline(draw_point_t *, int, uint32_t); -extern inline void draw_rect(draw_rect_t *, uint32_t, uint32_t); -extern void draw_rect_3d(draw_rect_t *, uint32_t, uint32_t, - uint32_t, int); -extern inline void draw_rect_fill(draw_rect_t *, uint32_t); -extern void draw_rect_fill_xor(draw_rect_t *, uint32_t); -extern void draw_rect_fill_inverse(draw_rect_t *, uint32_t, - uint32_t); -extern void draw_rect_fill_transparent(draw_rect_t *, uint32_t); -extern void draw_surface_color(SDL_Surface *, draw_rect_t *, - draw_point_t *, uint32_t, uint32_t); -extern void draw_surface_color_antialias(SDL_Surface *, - draw_rect_t *, draw_point_t *, uint32_t, - uint32_t); -extern void draw_surface_copy(SDL_Surface *, draw_point_t *, - SDL_Surface *, draw_rect_t *); -extern inline void draw_pixel(int, int, uint32_t); -extern inline void draw_pixel_transparent(int, int, uint32_t, int); -extern inline void draw_pixel_antialias(int, int, uint32_t); -extern inline uint32_t draw_getpixel(draw_point_t *); -extern inline uint32_t draw_getpixel2(int, int); -extern void draw_line(draw_point_t *, draw_point_t *, uint32_t); -extern void draw_moveto(draw_point_t *); -extern void draw_lineto(draw_point_t *, uint32_t); -extern void draw_fill_bg(draw_point_t *, uint32_t, uint32_t); -extern void draw_fill_fg(draw_point_t *, uint32_t); -extern void draw_circle(draw_point_t *, int, uint32_t); -extern inline void draw_get_vector(draw_point_t *, draw_point_t *, - draw_vect_t *); -extern void draw_circle_arc(draw_point_t *, int, int, int, int, - uint32_t); - - - -#endif diff --git a/tests/sdl-client/tests/fonts.c b/tests/sdl-client/tests/fonts.c deleted file mode 100644 index fc6b96f..0000000 --- a/tests/sdl-client/tests/fonts.c +++ /dev/null @@ -1,318 +0,0 @@ -/* $Id: fonts.c,v 1.1 2006/05/03 14:20:47 mmondor Exp $ */ - -/* - * Copyright (c) 2004-2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -/* HEADERFILES */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - - - -/* DEFINITIONS */ - -#ifdef ANTIALIASING /* conf,h */ -#define DRAW_SURFACE_COLOR draw_surface_color_antialias -#else -#define DRAW_SURFACE_COLOR draw_surface_color -#endif - - - -/* STATIC FUNCTIONS PROTOTYPES */ - -inline static void font_rectangle(font_t *, draw_rect_t *, int); - - - -/* GLOBALS */ - -font_t *font_small, *font_small_bold, - *font_large, *font_large_bold; - - - -/* PRIVATE FUNCTIONS */ - -/* - * Fills the rectangle coordinates for the specified character of specified - * font within the font's surface - */ -inline static void -font_rectangle(font_t *font, draw_rect_t *rect, int c) -{ - assert(font != NULL); - assert(rect != NULL); - - /* Make sure that c is within 0-255 */ - c &= 0xff; - - /* Map c (0-255) to 0-15 x/y coordinates */ - rect->x = font->x * (c & 0x0f); - rect->y = font->y * (c / 16); - rect->w = font->x; - rect->h = font->y; -} - - - -/* PUBLIC FUNCTIONS */ - -/* Load fonts */ -int -font_init(void) -{ - - font_small = font_load( - "bmp/misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1.bmp"); - font_small_bold = font_load( - "bmp/misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp"); - font_large = font_load( - "bmp/misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1.bmp"); - font_large_bold = font_load( - "bmp/misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1.bmp"); - - /* - * On error, we don't free any successfully loaded fonts, and expect - * the application to exit. - */ - if (font_small == NULL || font_small_bold == NULL || - font_large == NULL || font_large_bold == NULL) - return -1; - - return 0; -} - -/* - * Allows to load a 256 characters (16x16 tiled) font map from an image. - * This image usually is in 1 bit depth, but it internally gets converted to - * 32-bit depth, and we then create a per-pixel alpha blending enabled surface - * for it. - */ -font_t * -font_load(const char *file) -{ - font_t *font; - SDL_Surface *surface1 = NULL, *surface2 = NULL, *surface3 = NULL; - int ok; - - assert(file != NULL); - - /* Load 1 bit depth bitmap */ - if ((surface1 = SDL_LoadBMP(file)) == NULL) - goto err; - - /* - * Convert loaded surface to screen_surface's depth, into new surface. - * bits 0 become 0x00000000 and 1 0x00ffffff. Remember that surface2 - * is the one we'll copy to the final destination one. - */ - if ((surface2 = SDL_ConvertSurface(surface1, screen_surface->format, - SDL_SWSURFACE)) == NULL) - goto err; - SDL_FreeSurface(surface1); - surface1 = NULL; - - /* - * Create new surface suitable for source alpha blending blitting. - * I previously attempted to use the converted surface and create an - * alpha blending enabled copy, but this seemed to fail. I thus must - * explicitely create a new surface myself (which proved to work in a - * test program). - */ - if ((surface1 = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, - surface2->w, surface2->h, 32, 0, 0, 0, 0)) == NULL) - goto err; - - /* - * Convert newly created surface to support per-pixel alpha blending - * with hardware support. Resulting surface3 is the one we'll copy - * surface2 to. - */ - (void) SDL_SetAlpha(surface1, SDL_SRCALPHA | SDL_RLEACCEL, 128); - if ((surface3 = SDL_DisplayFormatAlpha(surface1)) == NULL) - goto err; - SDL_FreeSurface(surface1); - surface1 = NULL; - - /* - * We now have both our 32-bit depth font surface (surface2) and our - * destination alpha surface (surface3). Copy surface2 data to - * surface3, making sure to set the alpha color to 0x00 for pixels - * which originally were 0 bits, that is, now 0x00000000, and to 0xff - * for pixels which were 1 bits, now being 0x00ffffff. - */ - ok = -1; - if (SDL_LockSurface(surface2) == 0) { - if (SDL_LockSurface(surface3) == 0) { - uint32_t *sptr, *dptr, *dtptr; - - for (sptr = (uint32_t *)surface2->pixels, - dptr = (uint32_t *)surface3->pixels, - dtptr = &dptr[surface3->w * surface3->h]; - dptr < dtptr; - sptr++, dptr++) - *dptr = (*sptr == 0 ? 0x00000000 : 0xffffffff); - ok = 0; - SDL_UnlockSurface(surface3); - } - SDL_UnlockSurface(surface2); - } - SDL_FreeSurface(surface2); - surface2 = NULL; - if (ok == -1) - goto err; - - /* Allocate font structure */ - if ((font = malloc(sizeof(font_t))) == NULL) - goto err; - - /* Everything successful, fill font structure and return it. */ - font->x = surface3->w / 16; - font->y = surface3->h / 16; - font->surface = surface3; - - return font; - -err: - if (surface1 != NULL) - SDL_FreeSurface(surface1); - if (surface2 != NULL) - SDL_FreeSurface(surface2); - if (surface3 != NULL) - SDL_FreeSurface(surface3); - - return NULL; -} - -/* Frees previously loaded font using font_load() */ -void -font_free(font_t *font) -{ - - assert(font != NULL); - assert(font->surface != NULL); - - SDL_FreeSurface(font->surface); - free(font); -} - -/* - * Efficiently draws a character to screen at specified position. The output - * color however can only be white using this function. - */ -void -font_draw_char(font_t *font, draw_point_t *p, int c) -{ - SDL_Rect screen_rect, font_rect; - draw_rect_t r; - - assert(font != NULL); - assert(p != NULL); - - screen_rect.x = p->x; - screen_rect.y = p->y; - font_rectangle(font, &r, c); - font_rect = (SDL_Rect){r.x, r.y, r.w, r.h}; - (void) SDL_BlitSurface(font->surface, &font_rect, - screen_surface, &screen_rect); -} - -/* - * Efficiently draws a character string to screen at specified position. - * The output color however can only be white using this function. - */ -void -font_draw_string(font_t *font, draw_point_t *p, const char *string) -{ - register const char *ptr; - SDL_Rect screen_rect, font_rect; - draw_rect_t r; - - assert(font != NULL); - assert(p != NULL); - assert(string != NULL); - - screen_rect.x = p->x; - screen_rect.y = p->y; - for (ptr = string; *ptr != '\0'; ptr++, screen_rect.x += font->x) { - font_rectangle(font, &r, *ptr); - font_rect = (SDL_Rect){r.x, r.y, r.w, r.h}; - (void) SDL_BlitSurface(font->surface, &font_rect, - screen_surface, &screen_rect); - } -} - -/* - * Returns the necessary number of horizontal pixels required to blit the - * specified string. - */ -int -font_string_width(font_t *font, const char *string) -{ - - assert(font != NULL); - assert(string != NULL); - - return (strlen(string) * font->x); -} - - -/* The following functions require that the screen surface be locked. */ - -/* - * font_draw_char() variant which is a slightly less efficient but allows to - * blit a character on screen at specified position with specified color. - * If bg color is 0, font is drawn in overlay mode. Otherwise, it is drawn - * overstrike with specified color. Note that if calling this function, the - * screen_surface SDL_Surface should be locked using SDL_LockSurface(). - */ -void -font_draw_char_color(font_t *font, uint32_t fg, uint32_t bg, draw_point_t *p, - int c) -{ - draw_rect_t rect; - - assert(font != NULL); - assert(p != NULL); - - font_rectangle(font, &rect, c); - DRAW_SURFACE_COLOR(font->surface, &rect, p, fg, bg); -} - -/* - * font_draw_string() variant which is a little less efficient but allows to - * blit a character string on screen at specified position with specified - * color. If bg is 0, string is drawn in overlay mode. Otherwise, it is drawn - * in overstrike mode with specified background color. - */ -void -font_draw_string_color(font_t *font, uint32_t fg, uint32_t bg, draw_point_t *p, - const char *string) -{ - register const char *ptr; - draw_rect_t rect; - - assert(font != NULL); - assert(p != NULL); - assert(string != NULL); - - for (ptr = string; *ptr != '\0'; ptr++, p->x += font->x) { - font_rectangle(font, &rect, *ptr); - DRAW_SURFACE_COLOR(font->surface, &rect, p, fg, bg); - } -} diff --git a/tests/sdl-client/tests/fonts.h b/tests/sdl-client/tests/fonts.h deleted file mode 100644 index 2edbccd..0000000 --- a/tests/sdl-client/tests/fonts.h +++ /dev/null @@ -1,46 +0,0 @@ -/* $id$ */ - -/* - * Copyright (c) 2004-2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#ifndef FONTS_H -#define FONTS_H - - - -#include - -#include - - - -typedef struct font { - int x, y; - SDL_Surface *surface; -} font_t; - - - -extern int font_init(void); -extern font_t *font_load(const char *); -extern void font_free(font_t *); -extern void font_draw_char(font_t *, draw_point_t *, int); -extern void font_draw_string(font_t *, draw_point_t *, - const char *); -extern int font_string_width(font_t *, const char *); -extern void font_draw_char_color(font_t *, uint32_t, uint32_t, - draw_point_t *, int); -extern void font_draw_string_color(font_t *, uint32_t, uint32_t, - draw_point_t *, const char *); - - -extern font_t *font_small, *font_small_bold, - *font_large, *font_large_bold; - - - -#endif diff --git a/tests/sdl-client/tests/msg.c b/tests/sdl-client/tests/msg.c deleted file mode 100644 index dc4a14a..0000000 --- a/tests/sdl-client/tests/msg.c +++ /dev/null @@ -1,189 +0,0 @@ -/* $Id: msg.c,v 1.1 2006/04/27 13:26:51 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include - -#include -#include - -#include - - - -#define CLIENTS 16 -#define ROUNDS 32 - - - -struct client { - SDL_Thread *thread; - int id; -}; - -struct client_msg { - thread_msg_t msg; - struct client *c; - int rounds; -}; - - - -int main(int, char **); - -static void done(int); -static int thread_client(void *); - - - -thread_port_t server_port; - - - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - struct client clients[CLIENTS]; - int i; - thread_ring_t server_ring; - - if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { - (void) fprintf(stderr, "main() - SDL_Init() - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - - /* - * We're already the server thread. - * Initialize our message port and notification ring. - */ - if (thread_ring_init(&server_ring) == -1) { - (void) fprintf(stderr, - "main() - thread_ring_init(server_port) - %s\n", - SDL_GetError()); - done(EXIT_FAILURE); - } - if (thread_port_init(&server_port) == -1) { - (void) fprintf(stderr, - "main() - thread_port_init(server_port) - %s\n", - SDL_GetError()); - done(EXIT_FAILURE); - } - thread_port_set_ring(&server_port, &server_ring); - - /* Launch client threads */ - for (i = 0; i < CLIENTS; i++) { - clients[i].id = i; - if ((clients[i].thread = SDL_CreateThread(thread_client, - &clients[i])) == NULL) { - (void) fprintf(stderr, - "main() - SDL_CreateThread(%d) - %s\n", - i, SDL_GetError()); - done(EXIT_FAILURE); - } - } - - /* - * Listen for messages from our client threads with a one second - * timeout delay and display them. - */ - for (;;) { - struct client_msg *msg; - - while ((msg = (struct client_msg *)thread_msg_get( - &server_port)) != NULL) { - (void) printf("Message from client %d: %d\n", - msg->c->id, msg->rounds); - if (thread_msg_reply(&msg->msg) != 0) { - (void) fprintf(stderr, - "main() - thread_msg_reply() - %s\n", - SDL_GetError()); - break; - } - } - (void) printf("Server polling\n"); - if (thread_ring_wait(&server_ring, 1000) != 0) { - (void) fprintf(stderr, - "main() - thread_ring_wait() - %s\n", - SDL_GetError()); - break; - } - } - - thread_port_set_ring(&server_port, NULL); - thread_port_destroy(&server_port); - thread_ring_destroy(&server_ring); - - exit(EXIT_SUCCESS); -} - -static void -done(code) -{ - - SDL_Quit(); - exit(code); -} - -static int -thread_client(void *data) -{ - struct client *c = (struct client *)data; - struct client_msg msg, *rmsg; - thread_ring_t client_ring; - thread_port_t client_port; - int i; - - /* Initialize reply port and ring */ - if (thread_ring_init(&client_ring) == -1) { - (void) fprintf(stderr, - "thread_client(%d) - thread_ring_init(server_port) - %s\n", - c->id, SDL_GetError()); - done(EXIT_FAILURE); - } - if (thread_port_init(&client_port) == -1) { - (void) fprintf(stderr, - "thread_client(%d) - thread_port_init(server_port) - %s\n", - c->id, SDL_GetError()); - done(EXIT_FAILURE); - } - thread_port_set_ring(&client_port, &client_ring); - - /* Initialize message with our reply port */ - thread_msg_init(&msg.msg, &client_port); - msg.c = c; - - for (i = 0; i < ROUNDS; i++) { - msg.rounds = i; - if (thread_msg_put(&server_port, &msg.msg) == -1) { - (void) fprintf(stderr, - "thread_client(%d) - thread_msg_put(%d) - %s\n", - c->id, i, SDL_GetError()); - break; - } - while ((rmsg = (struct client_msg *)thread_msg_get( - &client_port)) == NULL) { - (void) printf("Client polling\n"); - if (thread_ring_wait(&client_ring, 1000) != 0) { - (void) fprintf(stderr, - "thread_client(%d) - thread_ring_wait(%d)" - "- %s\n", c->id, i, SDL_GetError()); - break; - } - } - if (rmsg != NULL) - (void) printf("Received reply for %d: %d\n", - rmsg->c->id, rmsg->rounds); - else - break; - } - - return 0; -} diff --git a/tests/sdl-client/tests/netrek-like.c b/tests/sdl-client/tests/netrek-like.c deleted file mode 100644 index dbf9e11..0000000 --- a/tests/sdl-client/tests/netrek-like.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id: netrek-like.c,v 1.1 2006/05/03 08:58:01 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include - -#include -#include -#include - -#include -#include - - - -int main(int, char **); - -static int surface_blit_angle(SDL_Surface *, int, int, - double, int); -static SDL_Surface *bmp_load_key(const char *); - - - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - int i; - SDL_Surface *rship, *fship; - - screen_init(); - draw_init(); - if (font_init() != 0) { - (void) fprintf(stderr, "Could not load font bitmaps\n"); - screen_destroy(); - } - - rship = bmp_load_key("bmp/RomDD.bmp"); - fship = bmp_load_key("bmp/FedCA.bmp"); - - (void) rectangleRGBA(screen_surface, 0, 0, 750, 750, - 0xff, 0xff, 0xff, 0xff); - (void) rectangleRGBA(screen_surface, 750, 0, 1023, 274, - 0xff, 0xff, 0xff, 0xff); - (void) rectangleRGBA(screen_surface, 750, 274, 1023, 506, - 0xff, 0xff, 0xff, 0xff); - (void) rectangleRGBA(screen_surface, 750, 274, 1023, 767, - 0xff, 0xff, 0xff, 0xff); - (void) rectangleRGBA(screen_surface, 0, 750, 1023, 767, - 0xff, 0xff, 0xff, 0xff); - - for (i = 0; i < 1440; i += 2) { - if (surface_blit_angle(rship, 100, 100, (double)i, 1) == -1 || - surface_blit_angle(fship, 200, 100, (double)i, 1) == -1) - (void) fprintf(stderr, "surface_blit_angle()\n"); - SDL_Flip(screen_surface); - SDL_Delay(10); - } - - SDL_Delay(1000); - - /* Attempt to connect to server */ - - screen_destroy(); - /* NOTREACHED */ - - exit(EXIT_SUCCESS); -} - -static SDL_Surface * -bmp_load_key(const char *file) -{ - SDL_Surface *s; - Uint32 c; - - if ((s = SDL_LoadBMP(file)) == NULL) - goto err; - - c = SDL_MapRGB(s->format, 0, 0, 0); - if (SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, c) == -1) - goto err; - - return s; - -err: - (void) fprintf(stderr, "bmp_load_key(%s) - %s\n", file, SDL_GetError()); - screen_destroy(); - /* NOTREACHED */ - return NULL; -} - -static int -surface_blit_angle(SDL_Surface *s, int x, int y, double a, int clean) -{ - SDL_Surface *t; - SDL_Rect d; - int r; - - if (clean) { - int cx, cy, c; - - cx = s->w / 2 + 2; - cy = s->h / 2 + 2; - c = (cx >= cy ? cx : cy); - (void) boxRGBA(screen_surface, x - c, y - c, - x + c, y + c, 0x00, 0x00, 0x00, 0xff); - } - - if ((t = rotozoomSurface(s, a, 0.75, 1)) == NULL) - return -1; - - d = (SDL_Rect){x - (t->w / 2), y - (t->h / 2), 0, 0}; - r = SDL_BlitSurface(t, NULL, screen_surface, &d); - SDL_FreeSurface(t); - - return r; -} diff --git a/tests/sdl-client/tests/rot.c b/tests/sdl-client/tests/rot.c deleted file mode 100644 index 18448e8..0000000 --- a/tests/sdl-client/tests/rot.c +++ /dev/null @@ -1,182 +0,0 @@ -/* $Id: rot.c,v 1.3 2006/05/03 08:09:37 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - - - -typedef struct angle_cache { - SDL_Surface *source; - SDL_Surface *angles[360]; -} angle_cache_t; - - - -int main(int, char **); - -static angle_cache_t *angle_cache_init(SDL_Surface *); -static void angle_cache_destroy(angle_cache_t *); -static int surface_blit_angle(struct angle_cache *, int, int, - double, int); -static SDL_Surface *bmp_load_key(const char *); - - - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - int i, i2; - SDL_Surface *rship, *fship; - angle_cache_t *rshipc, *fshipc; - - screen_init(); - draw_init(); - if (font_init() != 0) { - (void) fprintf(stderr, "Could not load font bitmaps\n"); - screen_destroy(); - } - - rship = bmp_load_key("bmp/RomDD.bmp"); - fship = bmp_load_key("bmp/FedCA.bmp"); - if ((rshipc = angle_cache_init(rship)) == NULL || - (fshipc = angle_cache_init(fship)) == NULL) { - (void) fprintf(stderr, "Could not initialize angle caches\n"); - screen_destroy(); - } - - for (i2 = 0; i2 < 2; i2++) { - for (i = 0; i < 360; i += 5) { - if (surface_blit_angle(rshipc, 100, 100, (double)i, 1) - == -1 || surface_blit_angle(fshipc, 200, 100, - (double)i, 1) == -1) - (void) fprintf(stderr, - "surface_blit_angle()\n"); - SDL_Flip(screen_surface); - SDL_Delay(33); - } - } - - SDL_Delay(1000); - - /* Attempt to connect to server */ - - screen_destroy(); - /* NOTREACHED */ - - exit(EXIT_SUCCESS); -} - -static SDL_Surface * -bmp_load_key(const char *file) -{ - SDL_Surface *s; - Uint32 c; - - if ((s = SDL_LoadBMP(file)) == NULL) - goto err; - - c = SDL_MapRGB(s->format, 0, 0, 0); - if (SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, c) == -1) - goto err; - - return s; - -err: - (void) fprintf(stderr, "bmp_load_key(%s) - %s\n", file, SDL_GetError()); - screen_destroy(); - /* NOTREACHED */ - return NULL; -} - -static angle_cache_t * -angle_cache_init(SDL_Surface *s) -{ - angle_cache_t *ac; - int i; - - assert(s != NULL); - - if ((ac = malloc(sizeof(angle_cache_t))) != NULL) { - ac->source = s; - for (i = 0; i < 360; i++) - ac->angles[i] = NULL; - - return ac; - } - - return NULL; -} - -static void -angle_cache_destroy(angle_cache_t *ac) -{ - int i; - - assert(ac != NULL); - - for (i = 0; i < 360; i++) { - if (ac->angles[i] != NULL) - SDL_FreeSurface(ac->angles[i]); - } - - free(ac); -} - -static int -surface_blit_angle(angle_cache_t *ac, int x, int y, double a, int clean) -{ - SDL_Surface *t, *s = ac->source; - SDL_Rect d; - int r, i; - - assert(a > -1 && a < 360); - assert(((int)a) == a); - - if (clean) { - int cx, cy, c; - - cx = s->w / 2 + 2; - cy = s->h / 2 + 2; - c = (cx >= cy ? cx : cy); - (void) boxRGBA(screen_surface, x - c, y - c, - x + c, y + c, 0x00, 0x00, 0x00, 0xff); - } - - if ((t = ac->angles[(int)a]) == NULL) { - for (r = 0; r < 2; r++) { - if ((t = rotozoomSurface(s, a, 1.0, 1)) != NULL) { - ac->angles[(int)a] = t; - break; - } - /* Free some room and retry */ - for (i = 0; i < 360; i++) { - if (ac->angles[i] != NULL) { - SDL_FreeSurface(ac->angles[i]); - ac->angles[i] = NULL; - } - } - } - if (t == NULL) - return -1; - } - - d = (SDL_Rect){x - (t->w / 2), y - (t->h / 2), 0, 0}; - return SDL_BlitSurface(t, NULL, screen_surface, &d); -} diff --git a/tests/sdl-client/tests/snd.c b/tests/sdl-client/tests/snd.c deleted file mode 100644 index eceaa3c..0000000 --- a/tests/sdl-client/tests/snd.c +++ /dev/null @@ -1,159 +0,0 @@ -/* $Id: snd.c,v 1.1 2006/05/01 03:52:45 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include -#include -#include - -#include -#include - - - -int main(int, char **); - -static void done(int); -static Mix_Chunk *sample_load(const char *); - - - -static SDL_Surface *surface_screen = NULL; -static Mix_Chunk *cloak, *uncloak, *shield, *unshield, *torp, *hit, - *explode; - -static int iscloaked, isshielded; - - - -/* ARGSUSED */ -int -main(int argc, char **argv) -{ - Mix_Music *mus; - SDL_Event ev; - - if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { - (void) fprintf(stderr, "main() - SDL_Init() - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if ((surface_screen = SDL_SetVideoMode(640, 480, 32, - SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF/* | SDL_FULLSCREEN*/)) - == NULL) { - (void) fprintf(stderr, "main() - SDL_SetVideoMode() - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - - if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) != 0) { - (void) fprintf(stderr, "main() - Mix_OpenAudio() - %s\n", - Mix_GetError()); - done(EXIT_FAILURE); - } - - cloak = sample_load("wav/nt_cloaked.wav"); - uncloak = sample_load("wav/nt_uncloak.wav"); - shield = sample_load("wav/nt_shield_up.wav"); - unshield = sample_load("wav/nt_shield_down.wav"); - torp = sample_load("wav/nt_fire_torp_other.wav"); - hit = sample_load("wav/nt_plasma_hit.wav"); - explode = sample_load("wav/nt_explosion_other.wav"); - - (void) Mix_AllocateChannels(16); - (void) Mix_ReserveChannels(2); - - if ((mus = Mix_LoadMUS("ogg/1.ogg")) == NULL) { - (void) fprintf(stderr, "main() - Mix_LoadMUS() - %s\n", - Mix_GetError()); - done(EXIT_FAILURE); - } - - if (Mix_PlayMusic(mus, -1) != 0) { - (void) fprintf(stderr, "main() - Mix_PlayMusic() - %s\n", - Mix_GetError()); - done(EXIT_FAILURE); - } - - for (iscloaked = isshielded = 0; SDL_WaitEvent(&ev) != 0; ) { - int ch; - - if (ev.type == SDL_KEYUP && ev.key.keysym.sym == SDLK_ESCAPE) - break; - if (ev.type == SDL_KEYDOWN) { - switch (ev.key.keysym.sym) { - case SDLK_SPACE: - /* Torp */ - if ((ch = Mix_PlayChannel(-1, torp, 0)) == -1) - (void) fprintf(stderr, "main() - " - "Mix_PlayChannel(torp) - %s\n", - SDL_GetError()); - else - Mix_SetPosition(ch, rand() % 359, - 255 - (200 + (rand() % 54))); - break; - case SDLK_w: - /* Cloak toggle */ - iscloaked = (iscloaked == 0 ? 1 : 0); - if (Mix_PlayChannel(0, - (iscloaked == 1 ? cloak : uncloak), 0) - == -1) - (void) fprintf(stderr, "main() - " - "Mix_PlayChannel(cloack) - %s\n", - SDL_GetError()); - break; - case SDLK_s: - /* Shield toggle */ - isshielded = (isshielded == 0 ? 1 : 0); - if (Mix_PlayChannel(1, - (isshielded == 1 ? shield : unshield), 0) - == -1) - (void) fprintf(stderr, "main() - " - "Mix_PlayChannel(shield) - %s\n", - SDL_GetError()); - break; - default: - break; - } - } - } - - if (Mix_FadeOutMusic(2000)) - SDL_Delay(2000); - - Mix_HaltMusic(); - Mix_CloseAudio(); - - done(EXIT_SUCCESS); - /* NOTREACHED */ - exit(EXIT_SUCCESS); -} - -static void -done(code) -{ - - SDL_Quit(); - exit(code); -} - -static Mix_Chunk * -sample_load(const char *file) -{ - Mix_Chunk *c; - - if ((c = Mix_LoadWAV(file)) == NULL) { - (void) fprintf(stderr, - "sample_load() - Mix_LoadWAV(%s) - %s\n", - file, SDL_GetError()); - done(EXIT_FAILURE); - } - - return c; -} diff --git a/tests/sdl-client/thread_msg.c b/tests/sdl-client/thread_msg.c deleted file mode 100644 index 3652617..0000000 --- a/tests/sdl-client/thread_msg.c +++ /dev/null @@ -1,432 +0,0 @@ -/* $Id: thread_msg.c,v 1.12 2006/05/19 10:14:35 mmondor Exp $ */ - -/* - * Copyright (C) 2006, Matthew Mondor - * All rights reserved. - * - * Adapted from older code intended for use with POSIX threads, - * for use within SDL. - */ - - - -#include - -#include -#include -#include - - - -static int amsg_create(pnode_t *); -static void amsg_destroy(pnode_t *); - - - -static pool_t amsg_pool; -static SDL_mutex *amsg_mutex; -static int amsg_initialized = 0; - - - -/* - * Allows to initialize a polling notification handle. When attached to a - * port, a message arriving on an empty port causes the associated ring to - * wake the thread from thread_ring_wait(). - */ -int -thread_ring_init(thread_ring_t *ring) -{ - - ASSERT(ring != NULL && ring->magic != PRING_MAGIC); - - if ((ring->cond = SDL_CreateCond()) != NULL) { - if ((ring->mutex = SDL_CreateMutex()) != NULL) { - ring->event = 0; - ring->magic = PRING_MAGIC; - - return 0; - } - SDL_DestroyCond(ring->cond); - } - - return -1; -} - -/* - * Returns TRUE if the supplied ring is a valid/usable one, or FALSE - * otherwise. Useful to conditionally destroy it. - */ -int -thread_ring_valid(thread_ring_t *ring) -{ - - ASSERT(ring != NULL); - - return (ring != NULL && ring->magic == PRING_MAGIC); -} - -/* - * Destroys a ring. Note that all message ports attached to this ring should - * first be detached or destroyed. - */ -void -thread_ring_destroy(thread_ring_t *ring) -{ - - ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - SDL_DestroyMutex(ring->mutex); - SDL_DestroyCond(ring->cond); - ring->magic = 0; -} - -/* - * Causes the current thread to sleep until a message arrives on an empty port - * associated with this ring. In normal operation, a thread only goes in wait - * mode after it processed all queued messages on all interesting ports. - * The ring is only notified when the port is empty and that a message is - * queued into it. - */ -int -thread_ring_wait(thread_ring_t *ring, Uint32 ms) -{ - int error = 0; - - ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - /* We must hold the condition variable's mutex */ - if (SDL_LockMutex(ring->mutex) != 0) { - error = -1; - goto err; - } - - /* As long as we don't have confirmation that we must stop waiting */ - for (ring->event = 0; !ring->event && error == 0; ) { - /* - * Wait on conditional variable, which will automatically - * and atomically release the mutex and return with the mutex - * locked again, as soon as the conditional variable gets - * signaled. - */ - if (ms != 0) - error = SDL_CondWaitTimeout(ring->cond, ring->mutex, - ms); - else - error = SDL_CondWait(ring->cond, ring->mutex); - } - - /* - * And we know that conditional waiting functions returned with mutex - * locked, so now release it back. - */ - (void) SDL_UnlockMutex(ring->mutex); - -err: - return error; -} - -/* - * Allows to wake up waiter(s) on the specified ring, which are sleeping - * threads within thread_ring_wait(). This can be used to simulate the - * arrival of a message on an empty port. Also useful to use rings as a - * notification system only when no message passing is needed. - */ -int -thread_ring_notify(thread_ring_t *ring) -{ - - ASSERT(ring != NULL && ring->magic == PRING_MAGIC); - - if (SDL_LockMutex(ring->mutex) != 0) - return -1; - - ring->event = 1; - (void) SDL_CondSignal(ring->cond); - - (void) SDL_UnlockMutex(ring->mutex); - - return 0; -} - -/* - * Allows to initialize/create a message port. - */ -int -thread_port_init(thread_port_t *port) -{ - - ASSERT(port != NULL && port->magic != PPORT_MAGIC); - - if ((port->lock = SDL_CreateMutex()) == NULL) - return -1; - - port->magic = PPORT_MAGIC; - port->ring = NULL; - DLIST_INIT(&port->messages); - - return 0; -} - -/* - * Returns TRUE if the supplied port is valid/usable, or FALSE otherwise. - * Useful to conditionally destroy a port, for instance. - */ -int -thread_port_valid(thread_port_t *port) -{ - - return (port != NULL && port->magic == PPORT_MAGIC); -} - -/* - * Destroys the specified port, previously created using thread_port_init(). - */ -void -thread_port_destroy(thread_port_t *port) -{ - - ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - port->magic = 0; - SDL_DestroyMutex(port->lock); -} - -/* - * Attaches a port to a ring. Multiple ports may be attached to a ring. A - * message arriving on an empty port will cause the attached ring to be - * notified, if any, and as such to cause a thread waiting on the ring to - * be awakened. - */ -void -thread_port_set_ring(thread_port_t *port, thread_ring_t *ring) -{ - - ASSERT(port != NULL && port->magic == PPORT_MAGIC && - (ring == NULL || ring->magic == PRING_MAGIC)); - - port->ring = ring; -} - -/* - * Allows to initialize a message before it can be sent over a port. The - * message only needs to be initialized once in general, even if it will be - * used for bidirectional transmission for synchronous operation. If the - * reply port needs to be changed, however, this function should be used again - * to set the new reply port. - */ -void -thread_msg_init(thread_msg_t *msg, thread_port_t *rport) -{ - - ASSERT(msg != NULL && msg->magic != PMESG_MAGIC && - (rport == NULL || rport->magic == PPORT_MAGIC)); - - msg->magic = PMESG_MAGIC; - msg->reply = rport; -} - -/* - * Returns TRUE if supplied message is valid/usable or FALSE otherwise. - */ -int -thread_msg_valid(thread_msg_t *msg) -{ - - return (msg != NULL && msg->magic == PMESG_MAGIC); -} - -/* - * Invalidates a message, so that it can no longer be sent over ports. - */ -void -thread_msg_destroy(thread_msg_t *msg) -{ - - ASSERT(msg != NULL && msg->magic == PMESG_MAGIC); - - msg->magic = 0; -} - -/* - * If any message exists in the queue of the specified port, unqueues it and - * returns it. Otherwise, NULL is returned. In normal operation, all messages - * queued to a port are processed before putting the thread back into sleep, - * mainly for efficiency, but also because it eases synchronization. - */ -thread_msg_t * -thread_msg_get(thread_port_t *port) -{ - thread_msg_t *msg = NULL; - - ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - if (SDL_LockMutex(port->lock) != 0) - goto err; - - if ((msg = DLIST_TOP(&port->messages)) != NULL) { - ASSERT(msg->magic == PMESG_MAGIC); - DLIST_UNLINK(&port->messages, (node_t *)msg); - } - - (void) SDL_UnlockMutex(port->lock); - -err: - return (thread_msg_t *)msg; -} - -/* - * Queues the specified message to the specified port, returning 0 on success. - * Note that the message data is not copied or moved, but that a pointer - * system is used to queue the message. Thus, the message's shared memory - * region is leased temporarily to the other end. One has to be careful to - * not allocate this message space on the stack when asynchroneous operation - * is needed. In synchroneous operation mode, it is not a problem, since the - * sender does not have to modify the data until the other end replies back - * with the same message after modifying the message if necessary. In - * synchroneous mode, we simply delegate that message memory region to the - * other end until it notifies us with a reply that it is done working with - * it. Returns 0 on success, or -1 on error. - */ -int -thread_msg_put(thread_port_t *port, thread_msg_t *msg) -{ - - ASSERT(port != NULL && port->magic == PPORT_MAGIC && - msg != NULL && msg->magic == PMESG_MAGIC); - - if (SDL_LockMutex(port->lock) != 0) - return -1; - - DLIST_APPEND(&port->messages, (node_t *)msg); - if (port->ring != NULL) { - if (DLIST_NODES(&port->messages) == 1) { - /* - * We know that there previously were no messages, - * and that the reading thread then waits for any - * message to be available. Signal it that there at - * least is one message ready. The other end should - * normally process all available messages before - * going back into waiting. - */ - if (SDL_LockMutex(port->ring->mutex) == 0) { - port->ring->event = 1; - (void) SDL_CondSignal(port->ring->cond); - (void) SDL_UnlockMutex(port->ring->mutex); - } - } - } - - (void) SDL_UnlockMutex(port->lock); - - return 0; -} - -/* - * Meant to be used in synchroneous message transfer mode. The initial sender - * sends a message to the other end, which then uses this function to notify - * back the initial sender that it is done, often with a success/failure - * result as part of the message. Returns 0 on success, or -1 on error. - */ -int -thread_msg_reply(thread_msg_t *msg) -{ - - ASSERT(msg != NULL && msg->magic == PMESG_MAGIC && msg->reply != NULL); - - return thread_msg_put(msg->reply, msg); -} - -/* - * Returns the number of pending messages tied to the port, if any, or -1 - * on error. - */ -int -thread_port_pending(thread_port_t *port) -{ - int pending = -1; - - ASSERT(port != NULL && port->magic == PPORT_MAGIC); - - if (SDL_LockMutex(port->lock) == 0) { - pending = (int)DLIST_NODES(&port->messages); - (void) SDL_UnlockMutex(port->lock); - } - - return pending; -} - -/* - * Initializes the asynchroneous messages pool and mutex. Must be called - * before thread_amsg_create() and thread_amsg_destroy() can be used. - * Returns 0 on success or -1 on error. - */ -int -thread_amsg_pool_init(void) -{ - - if (pool_init(&amsg_pool, "amsg_pool", malloc, free, amsg_create, - amsg_destroy, sizeof(thread_amsg_t), 64, 1, 0) == -1) - return -1; - - if ((amsg_mutex = SDL_CreateMutex()) == NULL) { - pool_destroy(&amsg_pool); - return -1; - } - - amsg_initialized = 1; - - return 0; -} - -static int -amsg_create(pnode_t *p) -{ - - thread_msg_init((thread_msg_t *)p, NULL); - - return 0; -} - -static void -amsg_destroy(pnode_t *p) -{ - - thread_msg_destroy((thread_msg_t *)p); -} - -/* - * Creates an amsg and returns a pointer to it, or NULL on failure. - * This is useful to efficiently create/send asynchroneous messages to - * another thread which is expected to receive/destroy it asynchroneously - * without replying, in which case a pool of distinct messages must be used. - */ -thread_amsg_t * -thread_amsg_create(void) -{ - thread_amsg_t *amsg = NULL; - - ASSERT(amsg_initialized); - - if (SDL_LockMutex(amsg_mutex) == 0) { - amsg = (thread_amsg_t *)pool_alloc(&amsg_pool, 0); - SDL_UnlockMutex(amsg_mutex); - } - - return amsg; -} - -/* - * Destroys an amsg previously created with thread_amsg_create(). - */ -void -thread_amsg_destroy(thread_amsg_t *amsg) -{ - - ASSERT(amsg_initialized && amsg != NULL); - - if (SDL_LockMutex(amsg_mutex) == 0) { - (void) pool_free((pnode_t *)amsg); - SDL_UnlockMutex(amsg_mutex); - } -} diff --git a/tests/sdl-client/thread_msg.h b/tests/sdl-client/thread_msg.h deleted file mode 100644 index 157cad8..0000000 --- a/tests/sdl-client/thread_msg.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $Id: thread_msg.h,v 1.9 2006/05/19 10:14:35 mmondor Exp $ */ - -/* - * Copyright (C) 2006, Matthew Mondor - * All rights reserved. - * - * Adapted from older code intended for use with POSIX threads, - * for use within SDL. - */ - - - -#ifndef THREAD_MSG_H -#define THREAD_MSG_H - - - -#include - -#include -#include - -#include -#include - - - -#define PRING_MAGIC 0x50524e47 -#define PPORT_MAGIC 0x50505254 -#define PMESG_MAGIC 0x504d5347 - -#define AMSG_MAXSIZE 256 - -typedef struct { - uint32_t magic; - SDL_cond *cond; - SDL_mutex *mutex; - int event; -} thread_ring_t; - -typedef struct { - uint32_t magic; - thread_ring_t *ring; - SDL_mutex *lock; - list_t messages; -} thread_port_t; - -typedef struct { - pnode_t node; - uint32_t magic; - thread_port_t *reply; -} thread_msg_t; - -typedef struct { - thread_msg_t msg; - size_t size; - uint32_t data[AMSG_MAXSIZE / 4]; -} thread_amsg_t; - - - -extern int thread_ring_init(thread_ring_t *); -extern int thread_ring_valid(thread_ring_t *); -extern void thread_ring_destroy(thread_ring_t *); -extern int thread_ring_wait(thread_ring_t *, Uint32); -extern int thread_ring_notify(thread_ring_t *); - -extern int thread_port_init(thread_port_t *); -extern int thread_port_valid(thread_port_t *); -extern void thread_port_destroy(thread_port_t *); -extern void thread_port_set_ring(thread_port_t *, thread_ring_t *); -extern void thread_msg_init(thread_msg_t *, thread_port_t *); -extern int thread_msg_valid(thread_msg_t *); -extern void thread_msg_destroy(thread_msg_t *); -extern thread_msg_t *thread_msg_get(thread_port_t *); -extern int thread_msg_put(thread_port_t *, thread_msg_t *); -extern int thread_msg_reply(thread_msg_t *); -extern int thread_port_pending(thread_port_t *); - -extern int thread_amsg_pool_init(void); -extern thread_amsg_t *thread_amsg_create(void); -extern void thread_amsg_destroy(thread_amsg_t *); - - - -#endif diff --git a/tests/sdl-client/thread_net_recv.c b/tests/sdl-client/thread_net_recv.c deleted file mode 100644 index efa0da0..0000000 --- a/tests/sdl-client/thread_net_recv.c +++ /dev/null @@ -1,191 +0,0 @@ -/* $Id: thread_net_recv.c,v 1.4 2006/05/19 14:54:38 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * User events polling thread. Reports all events to the master thread - * via efficient inter-thread messages. - */ - - - -#include -#include - -#include -#include -#include - - - -static void ssend(thread_msg_t *); -static int state_connect(void); -static void state_recv(void); -static ssize_t server_recv(void *, size_t); - - - -static thread_ring_t recv_ring; -static thread_port_t recv_port; - - - -TCPsocket server_socket = NULL; - - - -int -thread_net_recv(void *data) -{ - - /* Initialize reply port and ring */ - if (thread_ring_init(&recv_ring) == -1) { - (void) fprintf(stderr, - "thread_net_recv() - thread_ring_init(recv_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if (thread_port_init(&recv_port) == -1) { - (void) fprintf(stderr, - "thread_net_recv() - thread_port_init(recv_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - thread_port_set_ring(&recv_port, &recv_ring); - - if (state_connect() == 0) - state_recv(); - - /* Wait peacefully until our process exits */ - for (;;) - (void) thread_ring_wait(&recv_ring, -1); - - /* NOTREACHED */ - - return 0; -} - -/* - * Sends a message synchroneously, that is, sends and waits for a reply. - */ -static void -ssend(thread_msg_t *msg) -{ - thread_msg_t *rmsg; - - if (thread_msg_put(&main_port, msg) == -1) - (void) fprintf(stderr, - "ssend() - thread_msg_put()\n"); - while ((rmsg = thread_msg_get(&recv_port)) == NULL) { - if (thread_ring_wait(&recv_ring, -1) != 0) - (void) fprintf(stderr, - "ssend() - thread_ring_wait()\n"); - } -} - -/* - * Attempts to connect to server. On success, 0 is returned and a success - * reply packet is sent synchroneously to the main thread. On error, a - * failure packet is sent instead and we return -1. - */ -static int -state_connect(void) -{ - struct msg_connect msg; - IPaddress addr; - - thread_msg_init(&msg.msg, &recv_port); - msg.status = 0; - msg.error = NULL; - - if (SDLNet_ResolveHost(&addr, SERVER_HOST, SERVER_PORT) != 0) { - msg.status = -1; - msg.error = "Could not resolve server hostname"; - goto end; - } - - if ((server_socket = SDLNet_TCP_Open(&addr)) == NULL) { - msg.status = -1; - msg.error = "Could not connect to server"; - } - -end: - ssend(&msg.msg); - - return 0; -} - -/* - * We endlessly read packets from the server and queue them asynchroneously to - * the main thread's port, unless a read error occurs, in which case we queue - * an empty/error special packet and return. - */ -static void -state_recv(void) -{ - thread_amsg_t *amsg = NULL; - - for (;;) { - uint8_t type, length; - - /* - * We must already have an allocated message since we'll read - * data directly into its buffer. If this operation fails, - * it's fatal since the receiving main thread will never be - * notified. - */ - if ((amsg = thread_amsg_create()) == NULL) { - (void) fprintf(stderr, - "state_recv() - thread_amsg_create()\n"); - exit(EXIT_FAILURE); - } - - /* - * Start reading a single byte, the message type, and evaluate - * the message size. For variable packets, we also must read - * another byte for the legth. Then read the remaining of the - * message. On any invalid message, we error and stop as if - * the connection had problems, but we log it. Upon - * successful reception of a complete message, directly - * transmit it to the main thread asynchroneously and - * continue for another packet. These read operations are - * blocking automatically when no data is available to read. - */ - if (server_recv(amsg->data, 16) == -1) - break; - type = *(amsg->data); - - /* XXX */ - amsg->size = 16; - - /* Valid fixed length packet type? If so, set length */ - /* Valid variable length packet type? Obtain length */ - - /* Read remaining of packet */ - - /* Asynchroneously send packet to the main thread */ - (void) thread_msg_put(&main_port, &amsg->msg); - } - - /* Send the end of stream message to the main thread */ - amsg->size = -1; - (void) thread_msg_put(&main_port, &amsg->msg); -} - -static ssize_t -server_recv(void *data, size_t size) -{ - size_t len; - int res; - - for (len = 0; len < size; len += res) { - if ((res = SDLNet_TCP_Recv(server_socket, data + len, - size - len)) < 1) - return -1; - } - - return len; -} diff --git a/tests/sdl-client/thread_net_recv.h b/tests/sdl-client/thread_net_recv.h deleted file mode 100644 index 7a977e2..0000000 --- a/tests/sdl-client/thread_net_recv.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $Id: thread_net_recv.h,v 1.1 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * User events polling thread. Reports all events to the master thread - * via efficient inter-thread messages. - */ - - - -#ifndef THREAD_NET_RECV_H -#define THREAD_NET_RECV_H - - - -#include -#include - -#include - - - -/* - * The initial message we're waiting for from the read thread. The read - * thread will attempt to connect to the server, initiate authentication and - * then reply using this message with the connection status. Afterwards, we - * only expect msg_read packets from that thread. - * will be 0 on success or -1 on failure, in which case the error - * message string will be found into . - */ -struct msg_connect { - thread_msg_t msg; - int status; - const char *error; -}; - -/* - * We receive such a message when a packet was successfully read from the - * server. We reply in a synchroneous manner, however the reply delay should - * be very short compared to the possible delay of the read thread during a - * blocking read (SDL_net does not support non-blocking I/O operations). - * If -1 is received for the size, with a NULL pointer, it means - * that the connection status was lost or that a timeout occurred. - */ -struct msg_recv { - thread_msg_t msg; - void *data; - size_t size; -}; - - - -int thread_net_recv(void *); - - - -extern TCPsocket server_socket; - - - -#endif diff --git a/tests/sdl-client/thread_net_send.c b/tests/sdl-client/thread_net_send.c deleted file mode 100644 index 4fe7e21..0000000 --- a/tests/sdl-client/thread_net_send.c +++ /dev/null @@ -1,71 +0,0 @@ -/* $Id: thread_net_send.c,v 1.1 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Server socket writing thread. We post all asynchroneous messages - * (thread_amsg_t) we receive from the main thread to the server socket. - */ - - - -#include -#include - -#include -#include - - - -static thread_ring_t send_ring; - - - -thread_port_t send_port; - - - -int -thread_net_send(void *data) -{ - thread_amsg_t *amsg; - - /* Initialize reply port and ring */ - if (thread_ring_init(&send_ring) == -1) { - (void) fprintf(stderr, - "thread_net_recv() - thread_ring_init(send_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - if (thread_port_init(&send_port) == -1) { - (void) fprintf(stderr, - "thread_net_send() - thread_port_init(send_port) - %s\n", - SDL_GetError()); - exit(EXIT_FAILURE); - } - thread_port_set_ring(&send_port, &send_ring); - - /* - * Simply process all incomming messages, sending their data to - * the server port, and discarding the messages. When the port is - * empty, wait polling until messages become available. - */ - for (;;) { - while ((amsg = (thread_amsg_t *)thread_msg_get(&send_port)) - != NULL) { - if (SDLNet_TCP_Send(server_socket, - amsg->data, amsg->size) != amsg->size) - (void) fprintf(stderr, - "Error writing to server socket\n"); - thread_amsg_destroy(amsg); - } - (void) thread_ring_wait(&send_ring, -1); - } - - /* NOTREACHED */ - - return 0; -} diff --git a/tests/sdl-client/thread_net_send.h b/tests/sdl-client/thread_net_send.h deleted file mode 100644 index f1ae02f..0000000 --- a/tests/sdl-client/thread_net_send.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: thread_net_send.h,v 1.1 2006/05/19 09:13:42 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - -/* - * Server socket writing thread. We post all asynchroneous messages - * (thread_amsg_t) we receive from the main thread to the server socket. - */ - - - -#ifndef THREAD_NET_SEND_H -#define THREAD_NET_SEND_H - - - -#include -#include - -#include - - - -int thread_net_send(void *); - - - -extern thread_port_t send_port; - - - -#endif diff --git a/tests/sdl-client/wav/README b/tests/sdl-client/wav/README deleted file mode 100644 index 8c7a92a..0000000 --- a/tests/sdl-client/wav/README +++ /dev/null @@ -1 +0,0 @@ -For now these have been borrowed from the netrekxp client. diff --git a/tests/sdl-client/wav/nt_cloaked.wav b/tests/sdl-client/wav/nt_cloaked.wav deleted file mode 100755 index 3e010dd162f08a4ea14a8ce1e0bf36078eb7cd9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198704 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

    U$dpU>Of~^!vM- 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

    LFI>V(w-MTRW3BvH)Di_MPW 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 -#include - -#include - - - -#define RBUF_SIZE 4096 -#define DBUF_SIZE (RBUF_SIZE * 2) - - - -int main(void); - - - -int -main(void) -{ - z_stream s; - char rbuf[RBUF_SIZE], dbuf[DBUF_SIZE]; - size_t size; - - if (setvbuf(stdin, NULL, _IONBF, 0) == EOF) - perror("setvbuf(stdin)"); - if (setvbuf(stdout, NULL, _IONBF, 0) == EOF) - perror("setvbuf(stdout)"); - - s.next_in = s.next_out = NULL; - s.avail_in = s.avail_out = 0; - s.zalloc = NULL; - s.zfree = NULL; - s.opaque = NULL; - - if (deflateInit(&s, Z_DEFAULT_COMPRESSION) != Z_OK) { - perror("deflateInit()"); - exit(EXIT_FAILURE); - } - - while (!feof(stdin) && !ferror(stdin)) { - if ((size = fread(rbuf, 1, RBUF_SIZE, stdin)) < 1) - continue; - s.next_in = rbuf; - s.avail_in = size; - s.next_out = dbuf; - s.avail_out = DBUF_SIZE; - if (deflate(&s, Z_NO_FLUSH/*Z_SYNC_FLUSH*/) != Z_OK) { - perror("deflate()"); - exit(EXIT_FAILURE); - } - if (fwrite(dbuf, 1, DBUF_SIZE - s.avail_out, stdout) - != DBUF_SIZE - s.avail_out) { - perror("fwrite()"); - exit(EXIT_FAILURE); - } - } - - s.next_in = rbuf; - s.avail_in = 0; - s.next_out = dbuf; - s.avail_out = DBUF_SIZE; - if (deflate(&s, Z_FINISH) != Z_STREAM_END) { - perror("deflate()"); - exit(EXIT_FAILURE); - } - if (fwrite(dbuf, 1, DBUF_SIZE - s.avail_out, stdout) - != DBUF_SIZE - s.avail_out) { - perror("fwrite()"); - exit(EXIT_FAILURE); - } - - if (deflateEnd(&s) != Z_OK) { - perror("deflateEnd()"); - exit(EXIT_FAILURE); - } - - exit(feof(stdin) ? EXIT_SUCCESS : EXIT_FAILURE); -} diff --git a/tests/zlib/inflate.c b/tests/zlib/inflate.c deleted file mode 100644 index 59b807b..0000000 --- a/tests/zlib/inflate.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $Id: inflate.c,v 1.1 2006/06/15 14:23:24 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -#include -#include - -#include - - - -#define RBUF_SIZE 4096 -#define IBUF_SIZE (RBUF_SIZE * 64) - - - -int main(void); - - - -int -main(void) -{ - z_stream s; - char rbuf[RBUF_SIZE], ibuf[IBUF_SIZE]; - size_t size; - int ret; - - if (setvbuf(stdin, NULL, _IONBF, 0) == EOF) - perror("setvbuf(stdin)"); - if (setvbuf(stdout, NULL, _IONBF, 0) == EOF) - perror("setvbuf(stdout)"); - - s.next_in = s.next_out = NULL; - s.avail_in = s.avail_out = 0; - s.zalloc = NULL; - s.zfree = NULL; - s.opaque = NULL; - - if (inflateInit(&s) != Z_OK) { - perror("inflateInit()"); - exit(EXIT_FAILURE); - } - - while (!feof(stdin) && !ferror(stdin)) { - if ((size = fread(rbuf, 1, RBUF_SIZE, stdin)) < 1) - continue; - s.next_in = rbuf; - s.avail_in = size; - s.next_out = ibuf; - s.avail_out = IBUF_SIZE; - if ((ret = inflate(&s, Z_SYNC_FLUSH)) != Z_OK && - ret != Z_STREAM_END) { - perror("inflate()"); - exit(EXIT_FAILURE); - } - if (fwrite(ibuf, 1, IBUF_SIZE - s.avail_out, stdout) - != IBUF_SIZE - s.avail_out) { - perror("fwrite()"); - exit(EXIT_FAILURE); - } - if (ret == Z_STREAM_END) - break; - } - - s.next_in = rbuf; - s.avail_in = 0; - s.next_out = ibuf; - s.avail_out = IBUF_SIZE; - if (inflate(&s, Z_FINISH) != Z_STREAM_END) { - perror("inflate()"); - exit(EXIT_FAILURE); - } - if (fwrite(ibuf, 1, IBUF_SIZE - s.avail_out, stdout) - != IBUF_SIZE - s.avail_out) { - perror("fwrite()"); - exit(EXIT_FAILURE); - } - - if (inflateEnd(&s) != Z_OK) { - perror("inflateEnd()"); - exit(EXIT_FAILURE); - } - - exit(feof(stdin) ? EXIT_SUCCESS : EXIT_FAILURE); -} -- 2.9.0