+++ /dev/null
-/* $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.
- */
+++ /dev/null
-$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
+++ /dev/null
-$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 */
-};
+++ /dev/null
-# $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
+++ /dev/null
-# $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 *~
+++ /dev/null
-#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 <file>.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
-<common/types.h>
-\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
-<common/types.h>
-\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
-<common/types.h>
-\emph default
- and
-\emph on
-<common/kernlib/list.h>
-\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
-<common/types.h>
-\emph default
- and
-\emph on
-<common/kernlib/hash.h>
-\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
-<common/types.h>
-\emph default
- and
-\emph on
-<common/kernlib/fifo.h>
-\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
-<common/types.h>
-\emph default
- and
-\emph on
-<common/kernlib/lifo.h>
-\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/<directory>
-\emph default
- and
-\emph on
-src/ports/<directory>
-\emph default
- and
-\emph on
-src/ports/<directory>/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/<name>
-\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 ~
-<value>
-\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 ~
-<value>
-\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 ~
-<value>
-\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 ~
-<value>
-\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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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 ..
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/debug.h>
-#include <common/kernel/main.h>
-#include <common/kernlib/fifo.h>
-#include <common/kernlib/string.h>
-#include <config.h>
-
-
-
-#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("<NULL>", 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 %<c>, 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <config.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-#include <common/kernel/device.h>
-#include <common/kernel/main.h>
-#include <common/kernel/object.h>
-#include <common/kernel/port.h>
-#include <common/kernel/signal.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/debug.h>
-#include <common/kernlib/string.h>
-#include <common/kernlib/hash.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/port.h>
-#include <common/kernel/task.h>
-#include <common/kernel/memory.h>
-#include <common/kernlib/list.h>
-#include <common/kernlib/hash.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/main.h>
-#include <common/kernel/exception.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernlib/list.h>
-#include <processor/support.h>
-#include <port/support.h>
-
-
-
-/* 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);
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernlib/list.h>
-#include <processor/support.h>
-#include <port/support.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/main.h>
-#include <common/kernel/syscall.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/task.h>
-#include <common/kernel/port.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernlib/list.h>
-#include <common/kernlib/hash.h>
-#include <common/kernlib/string.h>
-#include <port/support.h>
-#include <processor/support.h>
-#include <config.h>
-
-
-
-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);
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/task.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/exception.h>
-#include <common/kernlib/list.h>
-#include <common/kernlib/string.h>
-#include <common/kernlib/fifo.h>
-#include <common/kernlib/hash.h>
-#include <processor/support.h>
-#include <port/support.h>
-#include <config.h>
-
-
-
-/* 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
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/main.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/syscall.h>
-#include <common/kernel/task.h>
-#include <common/kernel/object.h>
-#include <common/kernel/port.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/device.h>
-#include <common/kernel/debug.h>
-#include <common/kernlib/list.h>
-#include <common/kernlib/string.h>
-#include <port/support.h>
-#include <processor/support.h>
-#include <config.h>
-
-
-
-/* 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 <reserved>, and has little
- * more room than required to store all the control data. We have to
- * setup <pages> pages, starting at <begin> and ending at <end>.
- * 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 <zero> 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 <many> 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;
-
- /* <many> 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/list.h>
-#include <processor/support.h>
-#include <port/support.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/kernel/main.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-#include <common/kernel/port.h>
-#include <common/kernel/main.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/object.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernlib/hash.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-#include <common/kernel/signal.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/main.h>
-#include <common/kernel/memory.h>
-#include <common/kernlib/hash.h>
-#include <common/kernlib/string.h>
-
-
-
-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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/main.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/task.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/object.h>
-#include <processor/support.h>
-
-
-
-/* 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);
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-#include <processor/support.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/signal.h>
-#include <common/kernel/task.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/main.h>
-#include <common/kernel/syscall.h>
-#include <common/kernel/object.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-
-
-
-/* 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);
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernel/main.h>
-#include <common/kernlib/string.h>
-#include <config.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <config.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/main.h>
-#include <common/kernel/syscall.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/exception.h>
-#include <common/kernel/memory.h>
-#include <port/support.h> /* 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);
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/exception.h>
-#include <common/kernel/memory.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/task.h>
-#include <common/kernel/port.h>
-#include <common/kernel/main.h>
-#include <common/kernel/scheduler.h>
-#include <common/kernel/object.h>
-#include <common/kernel/statistic.h>
-#include <common/kernel/debug.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/syscall.h>
-#include <port/support.h>
-#include <processor/support.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/signal.h>
-#include <common/kernel/port.h>
-#include <common/kernel/device.h>
-#include <common/kernlib/string.h>
-#include <common/kernlib/list.h>
-#include <processor/support.h>
-/*#include <kern/handler.h> 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
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/debug.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/object.h>
-#include <common/kernlib/list.h>
-#include <common/kernlib/hash.h>
-
-
-
-/* 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 <freeall> 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;
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernlib/list.h>
-
-
-
-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
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-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
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/rand.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-int rand(void);
-void srand(unsigned int);
-int rand_r(unsigned int *);
-
-
-
-#endif
+++ /dev/null
-/* $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, <processor/support.h>. These are the C89/ANSI
- * setjmp()/longjmp().
- */
-
-
-
-#include <common/types.h>
-#include <processor/support.h>
-
-
-
-typedef _ctx_t jmp_buf[1];
-
-
-
-int setjmp(jmp_buf);
-void longjmp(jmp_buf, int);
-
-
-
-#endif
+++ /dev/null
-/* $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 <common/types.h>
-#include <processor/support.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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);
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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);
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/main.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/main.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/main.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-#include <common/kernel/memory.h>
-
-
-
-bstr_t *bstr_free(bstr_t *bstr)
-{
- if (bstr != NULL)
- FREE(bstr);
-
- return NULL;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/main.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-#include <port/support.h>
-
-
-
-/* Faster than memset(), but assumes that <mem> 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-char *strchr(const char *str, int c)
-{
- for (; *str != '\0' && *str != c; str++) ;
-
- return (*str != '\0' ? (char *)str : NULL);
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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));
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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));
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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));
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <common/kernlib/string.h>
-
-
-
-/* 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;
-}
-
-
+++ /dev/null
-#!/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 ..
+++ /dev/null
-/* $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 <processor/support.h>
-/* 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
+++ /dev/null
-/* $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
+++ /dev/null
-#!/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
-}
+++ /dev/null
-#!/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 <target>'
- $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 ..
+++ /dev/null
-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
+++ /dev/null
-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.
+++ /dev/null
-/* $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 <common/types.h>
-
-#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 */
-}
+++ /dev/null
-/* $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
+++ /dev/null
-OUTPUT_FORMAT("binary", "binary", "binary")
-OUTPUT_ARCH(m68k)
-
-ENTRY(_start)
-
-SECTIONS {
- . = 0x0020b660;
- .text : {
- *(.text)
- *(.rodata)
- *(.data)
- *(.bss)
- }
-}
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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)
+++ /dev/null
-OUTPUT_FORMAT("binary", "binary", "binary")
-OUTPUT_ARCH(m68k)
-
-ENTRY(_start)
-
-SECTIONS {
- .text : {
- *(.text)
- *(.rodata)
- *(.data)
- *(.bss)
- }
-}
+++ /dev/null
-/* $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 <common/types.h>
-#include <processors/m68k/support.h>
-#include <ports/amiga/support.h>
-#include <common/kernel/main.h>
-#include <common/kernel/memory.h>
-#include <common/kernel/exception.h>
-#include <common/kernel/syscall.h>
-#include <common/kernel/task.h>
-#include <common/kernel/port.h>
-
-#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.
- * <intreq> 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;
-}
+++ /dev/null
-#!/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 ===
+++ /dev/null
-/* $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 <sys/types.h>
-#include <stdio.h>
-
-
-
-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 <file>\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;
-}
+++ /dev/null
-/* $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 <stdio.h>
-#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;
-}
+++ /dev/null
-/* $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 <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-
-
-
-#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 <file> <kernel>\n");
-
- exit(0);
-}
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
-}
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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 <common/types.h>
-#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;
-}
+++ /dev/null
-/* $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<n>(u_int16_t intreqmask)
-| where <intreqmask> 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<n>() 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
+++ /dev/null
-#!/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
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-#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
+++ /dev/null
-/* $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
-
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-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.
+++ /dev/null
-/* $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@
+++ /dev/null
-/* $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@
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <common/types.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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@
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: contributors.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 - Contributors</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html"><em>Contributors</em></a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">MMSoftware Contributors</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-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
-<a href="software.html">software</a> area.
-</p><p>
-I personally thank the contributors for their interest in my projects.
-</p>
-<table border="1" bgcolor="#d0d0f0" width="100%">
-<tr><td align="center">
-<a href="software/contributors/joostendorp/index.html">Jeroen Oostendorp</a>
-</td></tr>
-<tr><td align="center">
-<a href="software/contributors/ddemaggio/index.html">Daniel DeMaggio</a>
-</td></tr>
-<tr><td align="center">
-<a href="software/contributors/aschlett/index.html">Alexander Schlett</a>
-</td></tr>
-<tr><td align="center">
-<a href="software/contributors/jkbentzen/index.html">Jonas Koch Bentzen</a>
-</td></tr>
-<tr><td align="center">
-<a href="software/contributors/vigityan/index.html">Vahram Igityan</a>
-</td></tr>
-</table>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: contributors.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: cvs.html,v 1.7 2003/12/10 20:33:58 mmondor Exp $
- Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED.
--->
-<title>Matthew Mondor's Software Site - CVS</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html"><em>CVS</em></a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">MMSoftware CVS Repository</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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:
-</p><p><font face="times" size="-1">
-% cvs -z6 -d:pserver:anoncvs@cvs.accela.net:/cvsroot co mmondor
-</font></p><p>
-To only obtain the Xisop kernel, <em>mmondor/Xisop</em> may be used as the
-module name. To only retreive the mmsoftware directory,
-<em>mmondor/mmsoftware</em> will be used.</p><p>
-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.
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: cvs.html,v 1.7 2003/12/10 20:33:58 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: donations.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $
- Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED.
--->
-<title>Matthew Mondor's Software Site - Donations</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html"><em>Donations</em></a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">Donations to support MMSoftware</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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).
-</p><p>
-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.
-</p><p>
-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.
-</p><p><font size="-1">
-Matthew Mondor
-</p>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: donations.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: index.html,v 1.9 2003/09/30 05:34:53 mmondor Exp $
- Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED.
--->
-<title>Matthew Mondor's Software Site - Main</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<p><td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>Main</em></a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="5">The MMSoftware Project</font><br>
-<a href="http://mmondor.gobot.ca">
-<img border="0" src="images/key.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</a>
-</center>
-<font face="helvetica, arial">
-<p>
-<b>NOTE:</b> The french version is not yet available. Additionally, only
-the master site currently works, mirrors should be up soon.
-</p><p>
-This site provides various opensource <a href="software.html">software</a>
-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
-<a href="contributors.html">contributors</a> worldwide who wanted to make
-their related work freely available.
-</p><p>
-The hosting and bandwidth for the <a href="mirrors.html">mirrors</a> is
-provided by various <a href="donations.html">donators</a> 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 <a href="philosophy.html">philosophy</a>
-will describe our goals with more details.
-</p><p>
-Matthew Mondor can be contacted via email at
-<a href="mailto:mmondor@gobot.ca">mmondor@gobot.ca</a> for suggestions,
-contributions, donations, flames, thanks, business and bug reports.
-</p>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<p><table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: index.html,v 1.9 2003/09/30 05:34:53 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: mirrors.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 - Mirrors</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html"><em>Mirrors</em></a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">MMSoftware Mirrors</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-Here are the current site mirrors and their generous providers, appearing
-in setup chronological order (first setup to last):
-</p>
-<table border="1" bgcolor="#d0d0f0" width="100%">
-<tr><th>Location</th><th>Provider</th><th>URL</th></tr>
-<tr>
-<td align="center">United-States</td>
-<td align="center">Matthew J Backes</td>
-<td align="center"><font size="-1"><a href="http://gobot.accela.net">http://gobot.accela.net</a></font></td>
-</tr><tr>
-<td align="center">Holland</td>
-<td align="center">Jeroen Oostendorp</td>
-<td align="center"><font size="-1"><a href="http://mmondor.oostendorp-ict.nl">http://mmondor.oostendorp-ict.nl</a></font></td>
-</tr><tr>
-<td align="center">Canada</td>
-<td align="center">Ryan Werber</td>
-<td align="center"><font size="-1"><a href="http://mmondor.dynup.net">http://mmondor.dynup.net</a></font></td>
-</tr>
-</table>
-<p>
-If you would like to provide hosting space and bandwidth for a new mirror,
-this would consist of a service donation, please consult the
-<a href="donations.html">donations</a> area for more information about the
-requirements and suggestions.
-</p>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: mirrors.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-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:
-
-"<Menu title>
-"<Filename>" "<Menu description>"
-
-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_<filename>.txt
-file.
-
-The format of the languages.txt file would be as follows:
-
-<Suffix> <Directory>
-
-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 <name> <show>
-.mirrors
-
-A similar system for FAQs:
-
-.faq <name>
-
-
-TODO
-====
-
-- Verify apache multilingual support to use the same convention for
- page storage...
+++ /dev/null
-# $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)
+++ /dev/null
-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.
+++ /dev/null
-- 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
+++ /dev/null
-# First line consists of FAQ .title
-# Then following are .section <num> <title> 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!?
+++ /dev/null
-# One line per entry, two columns:
-# <language> <description>
-#
-MENU Languages
-english English
-french French
+++ /dev/null
-MENU Sections
-index Main
-software Software
-donations Donations
-contributors Contributors
-philosophy Philosophy
-cvs CVS
-projects Projects
-mirrors Mirrors
-contact Contact
+++ /dev/null
-# One line per entry, two columns:
-# <name> <description>
-#
-MENU Mirrors
-canada Canada
-united-states United-States
-holland Holland
+++ /dev/null
-<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>
+++ /dev/null
-# 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
-
+++ /dev/null
-/* $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;
-}
+++ /dev/null
-# 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
+++ /dev/null
-# One FAQ entry per line, one column:
-# <faq>
-#
-mmftpd
-mmmail
-mmstatd
+++ /dev/null
-# One language description per line, one column:
-# <language>
-#
-english
-french
+++ /dev/null
-# 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"
+++ /dev/null
-# One entry per line, one column:
-# <name>
-#
-index
-software
-donations
-contributors
-philosophy
-cvs
-projects
-mirrors
-contact
+++ /dev/null
-# Each software category, one entry per line, two columns:
-# <category> <location>
-#
-stable software/stable
-development software/devl
-old software/old
+++ /dev/null
-# One project per line, three columns per project:
-# <projname> <status> <version>
-#
-mmftpd devl 1.0
+++ /dev/null
-# One project per line, three columns per project:
-# <projname> <status> <version>
-#
-ginseng-ftpd devl 1.0
+++ /dev/null
-# One project per line, three columns per project:
-# <projname> <status> <version>
-#
-ginseng-ftpd devl 1.0
+++ /dev/null
-<!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</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html"><em>Philosophy</em></a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">Philosophy behind mmsoftware</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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:
-</p><p><font face="times">
- This product includes software written by Matthew Mondor.
-</font></p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-Matthew Mondor
-</p>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br>
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: philosophy.html,v 1.5 2003/06/04 12:17:47 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: projects.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $
- Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED.
--->
-<title>Matthew Mondor's Software Site - Projects</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html">Software</a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html"><em>Projects</em></a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="4">Various Projects and Background</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-Here first follows an overview of my computer-related background
-</p><p>
-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).
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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).
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-Matt
-</p>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: projects.html,v 1.6 2003/06/04 12:17:47 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html><head>
-<!-- $Id: software.html,v 1.15 2003/12/12 15:58:39 mmondor Exp $
- Copyright (c) 2002-2003 Matthew Mondor, ALL RIGHTS RESERVED.
--->
-<title>Matthew Mondor's Software Site - Software</title>
-<link rel="shortcut icon" href="/favicon.ico">
-</head>
-
-<!-- Begin -->
-<body bgcolor="#f0f0ff" text="#000000" link="#3535c5" vlink="#700080">
-<table border="0" cellspacing="5" cellpadding="5" width="100%">
-<tbody><tr>
-
-<!-- Left column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Sections</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<p><font face="helvetica, arial" size="-1">
- <a href="index.html">Main</a> <br>
- <a href="software.html"><em>Software</em></a> <br>
- <a href="donations.html">Donations</a> <br>
- <a href="contributors.html">Contributors</a> <br>
- <a href="philosophy.html">Philosophy</a> <br>
- <a href="cvs.html">CVS</a> <br>
- <a href="projects.html">Projects</a> <br>
- <a href="mirrors.html">Mirrors</a> <br>
- <a href="mailto:mmondor@gobot.ca">Contact</a> <br>
-</font></td></tr></tbody></table>
-<br><img src="images/sigil.jpg" alt="Image Copyright (c) 2002-2003, Matthew Mondor">
-</td></p>
-
-<!-- Middle column -->
-<td valign="top">
-<center>
-<font face="helvetica, arial" size="5">The Software</font><br>
-</center>
-<font face="helvetica, arial">
-<p>
-This page contains the various official mmsoftware sources. The third-party
-software provided by the contributors can be found in the
-<a href="contributors.html">contributors</a> area. Access to the current
-official mmsoftware sources CVS repository is available (via pserver). Details
-about CVS can be found under the <a href="cvs.html">CVS</a> section. It is
-also possible to obtain the source archives of the old releases for reference
-only, in the software archive: <a href="software/">software/</a>.
-</p><p><center><b>Featured software:</b></center></p><p>
-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.
-</p>
-</font>
-<table border="1" bgcolor="#d0d0f0" width="100%">
-<font face="helvetica, arial">
-<tr>
-<th><a href="software/devl/mmftpd-0.0.17.tgz">mmftpd</a></th>
-<td align="center">0.0.17</td>
-<td align="center">Devl</td>
-<td align="center">
-<a href="software/misc/mmftpd-changelog.txt">ChangeLog</a></td>
-<td align="center">
-<a href="software/devl/mmftpd-0.0.17.tgz.md5.txt">MD5</a></td>
-</tr>
-<tr><td align="center" colspan="5">
-Unprivileged virtual users FTP server
-</td></tr>
-<tr><td bgcolor="#c6e0e0" colspan="5"><font face="helvetica, arial" size="-1">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</font></td></tr>
-</table><br><table border="1" bgcolor="#d0d0f0" width="100%">
-<th><a href="software/devl/mmmail-0.0.23.tgz">mmmail</a></th>
-<td align="center">0.0.23</td>
-<td align="center">Devl</td>
-<td align="center">
-<a href="software/misc/mmmail-changelog.txt">ChangeLog</a></td>
-<td align="center">
-<a href="software/devl/mmmail-0.0.23.tgz.md5.txt">MD5</a></td>
-</tr>
-<tr><td align="center" colspan="5">
-Unprivileged virtual SMTP+POP3 server suite using MySQL
-</td></tr>
-<tr><td bgcolor="#c6e0e0" colspan="5"><font face="helvetica, arial" size="-1">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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
-<a href="software/devl/mmmail-design.pdf">mmmail-design.pdf</a> document.
-</td></tr>
-</table><br>
-<table border="1" bgcolor="#d0d0f0" width="100%">
-<th><a href="software/devl/mmstatd-0.0.8.tgz">mmstatd</a></th>
-<td align="center">0.0.8</td>
-<td align="center">Devl</td>
-<td align="center">
-<a href="software/misc/mmstatd-changelog.txt">ChangeLog</a></td>
-<td align="center">
-<a href="software/devl/mmstatd-0.0.8.tgz.md5.txt">MD5</a></td>
-</tr>
-<tr><td align="center" colspan="5">
-Statistics maintenance server daemon and client library
-</td></tr>
-<tr><td bgcolor="#c6e0e0" colspan="5"><font face="helvetica, arial" size="-1">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</td></tr>
-</table><br><p><center><b>Unmaintained software:</b></center></p>
-<p>
-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.
-</p>
-<table border="1" bgcolor="#d0d0f0" width="100%">
-<th><a href="software/stable/mmtcpfwd-0.1.0.tar.gz">mmtcpfwd</a></th>
-<td align="center">0.1.0</td>
-<td align="center">Stable</td>
-<td align="center">
-<a href="software/misc/mmtcpfwd-changelog.txt">ChangeLog</a></td>
-<td align="center">
-<a href="software/stable/mmtcpfwd-0.1.0.tar.gz.md5.txt">MD5</a></td>
-</tr>
-<tr><td align="center" colspan="5">
-Port forwarder, MASQ fake identd and FTP proxy for Linux
-</td></tr>
-<tr><td bgcolor="#c6e0e0" colspan="5"><font face="helvetica, arial" size="-1">
-<p>
-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).
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p>
-</font></td></tr>
-</table><br><table border="1" bgcolor="#d0d0f0" width="100%">
-<th><a href="software/devl/ginseng-ftpd-1.6.tar.gz">ginseng-ftpd</a></th>
-<td align="center">1.6</td>
-<td align="center">Devl</td>
-<td align="center">
-<a href="software/misc/ginseng-ftpd-changelog.txt">ChangeLog</a></td>
-<td align="center">
-<a href="software/devl/ginseng-ftpd-1.6.tar.gz.md5.txt">MD5</a></td>
-</tr>
-<tr><td align="center" colspan="5">
-Security-enhanced Linux ftpd based on bsd-ftpd (NetBSD)
-</td></tr>
-<tr><td bgcolor="#c6e0e0" colspan="5"><font face="helvetica, arial" size="-1">
-<p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p><p>
-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.
-</p>
-</font></td></tr>
-</table>
-</font>
-</td>
-
-<!-- Right column -->
-<td valign="top" bgcolor="#d0d0f0">
-<font face="helvetica, arial" color="#000066"><b>Languages</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="index.html"><em>English</em></a> <br>
- <a href="index_fr.html">French</a> <br>
-</font></td></tr></tbody></table></p>
-<p><font face="helvetica, arial" color="#000066"><b>Mirrors</b></font><br>
-<table border="0" cellspacing="4" cellpadding="2"><tbody><tr><td>
-<font face="helvetica, arial" size="-1">
- <a href="http://mmondor.dynup.net/index.html">Canada</a> <br>
- <a href="http://gobot.accela.net/index.html"><nobr>United-States</nobr></a> <br>
- <a href="http://mmondor.oostendorp-ict.nl/index.html">Holland</a> <br
->
-</font></td></tr></tbody></table></td></p>
-
-<!-- End -->
-</tr><tr><td valign="bottom" align="left" colspan="3">
-<font face="helvetica, arial" size="-2">
-$Id: software.html,v 1.15 2003/12/12 15:58:39 mmondor Exp $<br>
-This site Copyright (c) 2002-2003, Matthew Mondor, ALL RIGHTS RESERVED.
-</font></td></tr></tbody></table>
-</body></html>
+++ /dev/null
-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.
+++ /dev/null
-/* $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 <sys/mman.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
-#include <sys/queue.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-
-/*
- * 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,
- "<maxdisks> must be between 1 and 100\n");
- return EXIT_FAILURE;
- }
- break;
- case '?':
- /* FALLTHROUGH */
- default:
- (void) fprintf(stderr,
- "Usage: %s [-p <pidfile>] [-n <maxdisks>]\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);
-}
+++ /dev/null
-$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
+++ /dev/null
-/* $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();
+++ /dev/null
-/* $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();
+++ /dev/null
-/* $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);
+++ /dev/null
-/* $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('<html><head><title>' + code + ' ' + desc +
- '</title></head><body><h1>' + code + ' ' + desc + '</h1>' +
- '<p>' + ldesc + '</p><br>');
-
- res.addContent(fd.httpDebug());
-
- res.addContent('<br><sub>' + SERVER_VERSION + '<br>' + SERVER_CVSID +
- '</sub></body></html>');
-
- 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('<html><head>' +
- '<title>Unsupported Old-Style Request</title></head>' +
- '<body><h1>Unsupported Old-Style Request</h1><p>' +
- '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.</p></body></html>' + "\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.<br>At least ' +
- '<b>upgrade</b> to a <a href="http://netbsd.org">' +
- 'decent</a> OS to survive on these grounds.<br>');
- return true;
- } else if (evil_browser) {
- http_error(this, 666, 'Evil Browser Banished!',
- 'Your browser is evil born.<br>At least ' +
- '<b>upgrade</b> to a <a href="http://mozilla.org">' +
- 'decent</a> browser to survive on these grounds.<br>');
- 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('<html><head><META HTTP-EQUIV="refresh" ' +
- 'CONTENT="5; URL=' + path.virtual + '"><title>Cookies' +
- '</title></head><body><h1>Cookies</h1><p>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.</p>' +
- ' <p>If it doesn\'t, please ensure that HTTP cookies ' +
- 'are enabled on your HTTP client and are accepted ' +
- 'from this server.</p>' +
- '<p>If the page still does not load properly after a ' +
- 'few seconds, please click on <a href="' + path.virtual +
- '">this link</a>.</p><br><sub>' + SERVER_VERSION +
- '<br>' + SERVER_CVSID + '</sub>');
- 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);
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) +
- '</' + this.tag + ">\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;
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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 += '</' + this.tag + ">";
-
- 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;
-}
+++ /dev/null
-/* $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" ]
-};
+++ /dev/null
-/* $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:
- *
- * <real> System-wide absolute real fullpath, to be used by the
- * application to access the files/directories in
- * question.
- * <virtual> 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 <real> 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;
- }
-
-};
+++ /dev/null
-/* $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;
-}
+++ /dev/null
-/* $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) + '</' + this.attr + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) + '</' + this.tag + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) + '</' + this.tag + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) + '</' + this.tag + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) + '</' + this.tag + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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) + '</' +
- this.tag + ">\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));
-
-}
+++ /dev/null
-/* $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. <tab> consists of tag name, and
- * <close> of a boolean specifying of the tag requires a corresponding closing
- * tag (i.e. <p>[body]</p>. 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 += '</' + this.tag + ">";
-
- 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 <a> and <img>, 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));
+++ /dev/null
-/* $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();
+++ /dev/null
-/* $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" +
- "<HTML><HEAD><TITLE>Detected!</TITLE></HEAD>\n" +
- "<BODY><PRE>\n" +
- "You are: " + fd.client_addr + ":" + fd.client_port +
- "\n" + "ID: " + fd.index + "\n\n" +
- "You sent:\n" + fd.request + "\n" +
- "</PRE>\n" + "<P>Tracing in progress...</P>\n" +
- "</BODY></HTML>\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();
+++ /dev/null
-/* $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("<HTML><HEAD><TITLE>Detected!</TITLE></HEAD>" +
- "<BODY><PRE>\n");
- fd.put("You are: " + fd.client_addr + ":" +
- fd.client_port + "\n\nYou sent:\n" + req + "\n");
- fd.put("</PRE>\n" + "<P>Tracing in progress...</P>\n" +
- "</BODY></HTML>\r\n");
- } catch (y) {
- err.put(y + "\n");
- }
- fd.close();
- } catch (x) {
- err.put(x + "\n");
- }
-}
-
-sock.close();
-err.close();
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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");
+++ /dev/null
-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");
+++ /dev/null
-# $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)
+++ /dev/null
-/* $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 <sys/types.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsapi.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsapi.h>
-
-#include <js_fd.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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 <jsapi.h>
-
-extern JSObject *js_InitFDClass(JSContext *, JSObject *);
-
-#endif
+++ /dev/null
-/* $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 <stdint.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsapi.h>
-
-#include <js_global.h>
-
-
-
-#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;
-}
+++ /dev/null
-/* $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 <jsapi.h>
-
-extern JSObject *js_InitGlobalClass(JSContext *, JSObject *);
-
-#endif
+++ /dev/null
-/* $Id: js_mysql.c,v 1.1 2006/07/09 00:30:30 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <stdint.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsapi.h>
-
-#include <libpq-fe.h>
-
-#include <js_pgsql.h>
-
-
-
-/*
- * 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;
-}
+++ /dev/null
-/* $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 <jsapi.h>
-
-extern JSObject *js_InitPGClass(JSContext *, JSObject *);
-
-#endif
+++ /dev/null
-/* $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 <sys/types.h>
-
-#include <assert.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsapi.h>
-
-
-
-/* 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;
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <jsapi.h>
-
-#include <js_fd.h>
-#include <js_errno.h>
-#include <js_signal.h>
-#include <js_pgsql.h>
-
-
-
-/*
- * 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 <scriptfile>\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);
-}
+++ /dev/null
-#!/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
+++ /dev/null
-# $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)
+++ /dev/null
-$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.
+++ /dev/null
-/* $Id: client.c,v 1.9 2006/04/23 04:40:14 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#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);
-}
+++ /dev/null
-/* $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 <sys/types.h>
-#include <sys/socket.h>
-
-#include <mmpool.h>
-#include <mmlist.h>
-
-#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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <mmstring.h>
-
-#include <conf.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $Id: kqueue.c,v 1.11 2006/04/03 21:06:08 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <errno.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <mmarch.h>
-
-#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++;
-}
+++ /dev/null
-/* $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 <sys/event.h>
-#include <sys/time.h>
-
-
-
-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
+++ /dev/null
-/* $Id: main.c,v 1.10 2006/04/01 00:46:24 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/socket.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <mmpool.h>
-#include <mmlist.h>
-
-#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;
-}
+++ /dev/null
-/* $Id: net.c,v 1.2 2006/04/01 00:46:24 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <sys/types.h>
-#include <syslog.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#include <mmstring.h>
-
-#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;
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <stdlib.h>
-
-#include <mmstring.h>
-#include <mmarch.h>
-
-#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;
-}
+++ /dev/null
-/* $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 <sys/types.h>
-
-#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
+++ /dev/null
-/* $Id: recvq.c,v 1.5 2006/04/05 09:19:16 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#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;
-}
+++ /dev/null
-/* $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 <sys/types.h>
-
-
-
-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
+++ /dev/null
-/* $Id: sendq.c,v 1.5 2006/04/03 20:37:51 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <mmlist.h>
-#include <mmstring.h>
-
-#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;
-}
+++ /dev/null
-/* $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 <sys/types.h>
-
-#include <mmlist.h>
-
-
-
-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
+++ /dev/null
-$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.
+++ /dev/null
-$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.
+++ /dev/null
-# $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)
+++ /dev/null
-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.
+++ /dev/null
-/* $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 <pthread.h>
-#include <syslog.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <pthread.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include <mmtypes.h>
-#include <mmlog.h>
-
-#include <mm_pthread_debug.h>
-#include <mm_pthread_msg.h>
-/*#include <mm_pthread_poll.h>*/
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <pthread.h>
-
-#include <mmtypes.h>
-#include <mmlist.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <sys/types.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <poll.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <mmtypes.h>
-#include <mmlog.h>
-#include <mmlist.h>
-
-#include <mm_pthread_debug.h>
-#include <mm_pthread_msg.h>
-#include <mm_pthread_pool.h>
-#include <mm_pthread_poll.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <pthread.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <poll.h>
-
-#include <mm_pthread_msg.h>
-
-
-
-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
+++ /dev/null
-/* $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 <pthread.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <mm_pthread_debug.h>
-#include <mm_pthread_pool.h>
-
-
-
-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.
- * <initial> threads are launched, and more will be launched in increments
- * of <initial> whenever necessary. These will also only be destroyed in
- * decrements of <initial> whenever that many threads have not been in use for
- * some time, and a minimum of <initial> threads will always be kept.
- * Setting <initial> 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;
-}
+++ /dev/null
-/* $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 <pthread.h>
-
-#include <mmtypes.h>
-#include <mmpool.h>
-
-#include <mm_pthread_msg.h>
-
-
-
-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
+++ /dev/null
-/* $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 <sys/types.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <mm_pthread_debug.h>
-#include <mm_pthread_msg.h>
-#include <mm_pthread_sleep.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <sys/time.h>
-#include <pthread.h>
-#include <unistd.h>
-
-
-
-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
+++ /dev/null
-/* $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 <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#include <mm_pthread_msg.h>
-#include <mm_pthread_pool.h>
-#include <mm_pthread_poll.h>
-
-
-
-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
-}
+++ /dev/null
-/* $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 <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#include <mm_pthread_msg.h>
-#include <mm_pthread_pool.h>
-#include <mm_pthread_poll.h>
-
-
-
-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;
-}
+++ /dev/null
-/*
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-
-#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);
-}
+++ /dev/null
-/*
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <pthread.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-
-#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);
-}
+++ /dev/null
-# $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)
+++ /dev/null
-/* $Id: main.c,v 1.2 2007/03/01 11:18:01 mmondor Exp $ */
-
-/*
- * Copyright (c) 2007, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-/*
- * Headers
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <rlc.h>
-
-
-
-#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);
-}
+++ /dev/null
-/* $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 <sys/stat.h>
-#include <sys/syslimits.h>
-#include <sys/types.h>
-
-#include <assert.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <mmlist.h>
-#include <mmpool.h>
-#include <mmhash.h>
-
-#include <rlc.h>
-
-
-
-/*
- * 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);
-}
+++ /dev/null
-/* $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 *);
+++ /dev/null
-# $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
+++ /dev/null
-/* $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 <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-#include <SDL_rotozoom.h>
-#include <SDL_gfxPrimitives.h>
-
-
-
-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 \"<file>\" <steps>\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, "<steps> 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);
-}
+++ /dev/null
-# $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
+++ /dev/null
-$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
+++ /dev/null
-For these tests, the winxp ships library were borrowed temporarily.
+++ /dev/null
-/* $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
+++ /dev/null
-/* $Id: debug.c,v 1.2 2006/05/19 09:16:14 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-
-
-#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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <stdio.h>
-#include <stdint.h>
-
-#include <decode.h>
-
-
-
-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;
- }
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-
-
-#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 <infile> <outfile> <seed>\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;
- }
-}
+++ /dev/null
-/* $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 <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* THIRD PARTY LIBRARY HEADERS */
-#include <SDL.h>
-#include <SDL_image.h>
-#include <SDL_thread.h>
-#include <SDL_rotozoom.h>
-#include <SDL_gfxPrimitives.h>
-#include <SDL_framerate.h>
-#include <SDL_mixer.h>
-#include <SDL_net.h>
-
-/* APPLICATION HEADERS */
-#include <main.h>
-#include <debug.h>
-#include <screen.h>
-#include <packets.h>
-#include <thread_msg.h>
-#include <thread_net_recv.h>
-#include <thread_net_send.h>
-#include <rawobjs.h>
-#include <decode.h>
-
-
-
-/* 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);
- }
-}
+++ /dev/null
-/* $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 <SDL.h>
-
-#include <thread_msg.h>
-
-
-
-extern thread_port_t main_port;
-
-
-
-#endif
+++ /dev/null
-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
+++ /dev/null
-/* $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 <stdlib.h>
-
-#include <mmstring.h>
-#include <mmarch.h>
-
-#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;
-}
+++ /dev/null
-/* $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 <stdint.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)(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
+++ /dev/null
-/* $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 <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <dlist.h>
-#include <pool.h>
-#include <debug.h>
-
-
-
-/* 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);
- }
-
- /*
- * <page> 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;
-}
+++ /dev/null
-/* $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 <stdint.h>
-
-#include <dlist.h>
-
-
-
-/* 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
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <stdio.h>
-#include <stdlib.h>
-
-#include <SDL.h>
-
-#include <conf.h>
-#include <screen.h>
-
-
-
-#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();
-}
+++ /dev/null
-/* $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 <SDL.h>
-
-
-
-extern SDL_Surface *screen_surface;
-extern int screen_width, screen_height;
-extern SDL_Joystick *gamepad;
-
-
-
-void screen_init(void);
-void screen_destroy(void);
-
-
-
-#endif
+++ /dev/null
-/* $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 <assert.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include <SDL.h>
-
-#include <draw.h>
-#include <conf.h>
-#include <screen.h>
-
-
-
-/* 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 <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 <radius> at
- * angle <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);
- }
-}
+++ /dev/null
-/* $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 <stdint.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-
-#include <fonts.h>
-#include <screen.h>
-#include <draw.h>
-#include <conf.h>
-
-
-
-/* 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);
- }
-}
+++ /dev/null
-/* $id$ */
-
-/*
- * Copyright (c) 2004-2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#ifndef FONTS_H
-#define FONTS_H
-
-
-
-#include <SDL.h>
-
-#include <draw.h>
-
-
-
-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
+++ /dev/null
-/* $Id: msg.c,v 1.1 2006/04/27 13:26:51 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <SDL.h>
-#include <SDL_thread.h>
-
-#include <thread_msg.h>
-
-
-
-#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;
-}
+++ /dev/null
-/* $Id: netrek-like.c,v 1.1 2006/05/03 08:58:01 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-#include <SDL_rotozoom.h>
-#include <SDL_gfxPrimitives.h>
-
-#include <screen.h>
-#include <fonts.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $Id: rot.c,v 1.3 2006/05/03 08:09:37 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-#include <SDL_rotozoom.h>
-#include <SDL_gfxPrimitives.h>
-
-#include <screen.h>
-#include <fonts.h>
-
-
-
-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);
-}
+++ /dev/null
-/* $Id: snd.c,v 1.1 2006/05/01 03:52:45 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <SDL.h>
-#include <SDL_mixer.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <stdlib.h>
-
-#include <debug.h>
-#include <thread_msg.h>
-#include <pool.h>
-
-
-
-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);
- }
-}
+++ /dev/null
-/* $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 <stdint.h>
-
-#include <SDL.h>
-#include <SDL_thread.h>
-
-#include <dlist.h>
-#include <pool.h>
-
-
-
-#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
+++ /dev/null
-/* $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 <stdio.h>
-#include <stdlib.h>
-
-#include <main.h>
-#include <thread_net_recv.h>
-#include <conf.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <SDL.h>
-#include <SDL_net.h>
-
-#include <thread_msg.h>
-
-
-
-/*
- * 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.
- * <status> will be 0 on success or -1 on failure, in which case the error
- * message string will be found into <error>.
- */
-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 <data> size, with a NULL <data> 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
+++ /dev/null
-/* $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 <stdio.h>
-#include <stdlib.h>
-
-#include <thread_net_send.h>
-#include <thread_net_recv.h>
-
-
-
-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;
-}
+++ /dev/null
-/* $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 <SDL.h>
-#include <SDL_net.h>
-
-#include <thread_msg.h>
-
-
-
-int thread_net_send(void *);
-
-
-
-extern thread_port_t send_port;
-
-
-
-#endif
+++ /dev/null
-For now these have been borrowed from the netrekxp client.
+++ /dev/null
-$Id: README,v 1.1 2006/06/15 14:23:24 mmondor Exp $
-
-Simple zlib compression/decompression tests.
+++ /dev/null
-/* $Id: deflate.c,v 1.1 2006/06/15 14:23:24 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <zlib.h>
-
-
-
-#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);
-}
+++ /dev/null
-/* $Id: inflate.c,v 1.1 2006/06/15 14:23:24 mmondor Exp $ */
-
-/*
- * Copyright (c) 2006, Matthew Mondor
- * ALL RIGHTS RESERVED.
- */
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <zlib.h>
-
-
-
-#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);
-}