From: Matthew Mondor Date: Tue, 13 Mar 2007 20:28:23 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'mysql-branch'. X-Git-Tag: pgsql-branch-merge~1 X-Git-Url: http://git.pulsar-zone.net/?a=commitdiff_plain;h=cec6f687cab65d8ee65212ed7361fd6ae5bbfe3d;p=mmondor.git This commit was manufactured by cvs2svn to create branch 'mysql-branch'. --- 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 dcac835..0000000 Binary files a/site/favicon.ico and /dev/null differ diff --git a/site/images/CVS.jpg b/site/images/CVS.jpg deleted file mode 100644 index 4e382fc..0000000 Binary files a/site/images/CVS.jpg and /dev/null differ diff --git a/site/images/key.jpg b/site/images/key.jpg deleted file mode 100644 index 6b3f9df..0000000 Binary files a/site/images/key.jpg and /dev/null differ diff --git a/site/images/sigil.jpg b/site/images/sigil.jpg deleted file mode 100644 index d6f6ace..0000000 Binary files a/site/images/sigil.jpg and /dev/null differ 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 be3a562..0000000 Binary files a/tests/sdl-client/bmp/FedCA.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/README b/tests/sdl-client/bmp/README deleted file mode 100644 index 4f0b49d..0000000 --- a/tests/sdl-client/bmp/README +++ /dev/null @@ -1 +0,0 @@ -For these tests, the winxp ships library were borrowed temporarily. diff --git a/tests/sdl-client/bmp/RomDD.bmp b/tests/sdl-client/bmp/RomDD.bmp deleted file mode 100644 index 50e429a..0000000 Binary files a/tests/sdl-client/bmp/RomDD.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/fedship.bmp b/tests/sdl-client/bmp/fedship.bmp deleted file mode 100755 index 465806f..0000000 Binary files a/tests/sdl-client/bmp/fedship.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/indship.bmp b/tests/sdl-client/bmp/indship.bmp deleted file mode 100755 index 1a7e39b..0000000 Binary files a/tests/sdl-client/bmp/indship.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/kliship.bmp b/tests/sdl-client/bmp/kliship.bmp deleted file mode 100755 index cf52598..0000000 Binary files a/tests/sdl-client/bmp/kliship.bmp and /dev/null differ 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 c55b172..0000000 Binary files a/tests/sdl-client/bmp/misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1.bmp and /dev/null differ 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 5c2ab05..0000000 Binary files a/tests/sdl-client/bmp/misc-fixed-bold-r-normal--15-120-100-100-c-90-iso8859-1.bmp and /dev/null differ 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 e8ac5d4..0000000 Binary files a/tests/sdl-client/bmp/misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-1.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1.bmp b/tests/sdl-client/bmp/misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1.bmp deleted file mode 100644 index 9e1d9f2..0000000 Binary files a/tests/sdl-client/bmp/misc-fixed-medium-r-normal--15-120-100-100-c-90-iso8859-1.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/oriship.bmp b/tests/sdl-client/bmp/oriship.bmp deleted file mode 100755 index 166fb1a..0000000 Binary files a/tests/sdl-client/bmp/oriship.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/romship.bmp b/tests/sdl-client/bmp/romship.bmp deleted file mode 100755 index 753d38a..0000000 Binary files a/tests/sdl-client/bmp/romship.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/sbexpl.bmp b/tests/sdl-client/bmp/sbexpl.bmp deleted file mode 100755 index b06ffcf..0000000 Binary files a/tests/sdl-client/bmp/sbexpl.bmp and /dev/null differ diff --git a/tests/sdl-client/bmp/shexpl.bmp b/tests/sdl-client/bmp/shexpl.bmp deleted file mode 100755 index 72a62c4..0000000 Binary files a/tests/sdl-client/bmp/shexpl.bmp and /dev/null differ 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 99b3486..0000000 Binary files a/tests/sdl-client/fnt/10x20.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/5x7.fnt b/tests/sdl-client/fnt/5x7.fnt deleted file mode 100644 index 3612165..0000000 Binary files a/tests/sdl-client/fnt/5x7.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/5x8.fnt b/tests/sdl-client/fnt/5x8.fnt deleted file mode 100644 index 01add72..0000000 Binary files a/tests/sdl-client/fnt/5x8.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x10.fnt b/tests/sdl-client/fnt/6x10.fnt deleted file mode 100644 index 3c49f20..0000000 Binary files a/tests/sdl-client/fnt/6x10.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x12.fnt b/tests/sdl-client/fnt/6x12.fnt deleted file mode 100644 index 156865b..0000000 Binary files a/tests/sdl-client/fnt/6x12.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x13.fnt b/tests/sdl-client/fnt/6x13.fnt deleted file mode 100644 index e259f1a..0000000 Binary files a/tests/sdl-client/fnt/6x13.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x13B.fnt b/tests/sdl-client/fnt/6x13B.fnt deleted file mode 100644 index 503b773..0000000 Binary files a/tests/sdl-client/fnt/6x13B.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x13O.fnt b/tests/sdl-client/fnt/6x13O.fnt deleted file mode 100644 index cb5a27f..0000000 Binary files a/tests/sdl-client/fnt/6x13O.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/6x9.fnt b/tests/sdl-client/fnt/6x9.fnt deleted file mode 100644 index cca4689..0000000 Binary files a/tests/sdl-client/fnt/6x9.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/7x13.fnt b/tests/sdl-client/fnt/7x13.fnt deleted file mode 100644 index d20852e..0000000 Binary files a/tests/sdl-client/fnt/7x13.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/7x13B.fnt b/tests/sdl-client/fnt/7x13B.fnt deleted file mode 100644 index 9f3fbed..0000000 Binary files a/tests/sdl-client/fnt/7x13B.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/7x13O.fnt b/tests/sdl-client/fnt/7x13O.fnt deleted file mode 100644 index e5b7732..0000000 Binary files a/tests/sdl-client/fnt/7x13O.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/7x14.fnt b/tests/sdl-client/fnt/7x14.fnt deleted file mode 100644 index fdcd752..0000000 Binary files a/tests/sdl-client/fnt/7x14.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/7x14B.fnt b/tests/sdl-client/fnt/7x14B.fnt deleted file mode 100644 index 939aa63..0000000 Binary files a/tests/sdl-client/fnt/7x14B.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/8x13.fnt b/tests/sdl-client/fnt/8x13.fnt deleted file mode 100644 index 9de72b4..0000000 Binary files a/tests/sdl-client/fnt/8x13.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/8x13B.fnt b/tests/sdl-client/fnt/8x13B.fnt deleted file mode 100644 index 96179a0..0000000 Binary files a/tests/sdl-client/fnt/8x13B.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/8x13O.fnt b/tests/sdl-client/fnt/8x13O.fnt deleted file mode 100644 index a38a371..0000000 Binary files a/tests/sdl-client/fnt/8x13O.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/9x15.fnt b/tests/sdl-client/fnt/9x15.fnt deleted file mode 100644 index 349e5bd..0000000 Binary files a/tests/sdl-client/fnt/9x15.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/9x15B.fnt b/tests/sdl-client/fnt/9x15B.fnt deleted file mode 100644 index 23bc97e..0000000 Binary files a/tests/sdl-client/fnt/9x15B.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/9x18.fnt b/tests/sdl-client/fnt/9x18.fnt deleted file mode 100644 index 0651c97..0000000 Binary files a/tests/sdl-client/fnt/9x18.fnt and /dev/null differ diff --git a/tests/sdl-client/fnt/9x18B.fnt b/tests/sdl-client/fnt/9x18B.fnt deleted file mode 100644 index d93d09d..0000000 Binary files a/tests/sdl-client/fnt/9x18B.fnt and /dev/null differ diff --git a/tests/sdl-client/main.c b/tests/sdl-client/main.c deleted file mode 100644 index 100de1c..0000000 --- a/tests/sdl-client/main.c +++ /dev/null @@ -1,872 +0,0 @@ -/* $Id: main.c,v 1.73 2006/05/23 01:32:50 mmondor Exp $ */ - -/* - * Copyright (c) 2006, Matthew Mondor - * ALL RIGHTS RESERVED. - */ - - - -/* STANDARD HEADERS */ -#include -#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 3e010dd..0000000 Binary files a/tests/sdl-client/wav/nt_cloaked.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_explosion_other.wav b/tests/sdl-client/wav/nt_explosion_other.wav deleted file mode 100755 index b7ba8cb..0000000 Binary files a/tests/sdl-client/wav/nt_explosion_other.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_fire_torp_other.wav b/tests/sdl-client/wav/nt_fire_torp_other.wav deleted file mode 100755 index dddf2c6..0000000 Binary files a/tests/sdl-client/wav/nt_fire_torp_other.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_plasma_hit.wav b/tests/sdl-client/wav/nt_plasma_hit.wav deleted file mode 100755 index 73ecd7c..0000000 Binary files a/tests/sdl-client/wav/nt_plasma_hit.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_shield_down.wav b/tests/sdl-client/wav/nt_shield_down.wav deleted file mode 100755 index 0888f08..0000000 Binary files a/tests/sdl-client/wav/nt_shield_down.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_shield_up.wav b/tests/sdl-client/wav/nt_shield_up.wav deleted file mode 100755 index 909f72c..0000000 Binary files a/tests/sdl-client/wav/nt_shield_up.wav and /dev/null differ diff --git a/tests/sdl-client/wav/nt_uncloak.wav b/tests/sdl-client/wav/nt_uncloak.wav deleted file mode 100755 index e4df979..0000000 Binary files a/tests/sdl-client/wav/nt_uncloak.wav and /dev/null differ diff --git a/tests/zlib/README b/tests/zlib/README deleted file mode 100644 index aa38152..0000000 --- a/tests/zlib/README +++ /dev/null @@ -1,3 +0,0 @@ -$Id: README,v 1.1 2006/06/15 14:23:24 mmondor Exp $ - -Simple zlib compression/decompression tests. diff --git a/tests/zlib/deflate.c b/tests/zlib/deflate.c deleted file mode 100644 index 7eff3e4..0000000 --- a/tests/zlib/deflate.c +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id: deflate.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 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); -}