diff --git a/docs/develop/Makefile b/docs/develop/Makefile new file mode 100644 index 0000000000..06fa047b79 --- /dev/null +++ b/docs/develop/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = generated + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/develop/TODO b/docs/develop/TODO new file mode 100644 index 0000000000..9c38171d7e --- /dev/null +++ b/docs/develop/TODO @@ -0,0 +1,17 @@ +Documents that still need to be converted to restructuredtext (or thrown away): + +- kernel/vm*: it looks like these should be comments in the sourcecode? +- kits/*: TODO, some interesting info in there but also a lot of probably obsolete things +- media/*: some useful things, some sourcecode, and a PDF file about the echo audio driver + +Other things to do: + +- Organize the table of contents a bit. For now I just wanted to get all the existing files in, + in a mostly flat organization. But it makes things hard to follow. +- Reorganize the directories. For example move midi to kits/midi. Should we follow the layout of + the source tree? Or the hierarchy of the table of contents? +- There are doxyfiles for various components. Unlike the one used for API docs, they scan the cpp + source files and will extract some internals documentation from there. Decide what to do with that. +- Migrate some things from the website. Start with documentation about configure and jam, for example. +- There are TODO lists in various places in the docs, turn them into bugreports in the bugtracker + (including this one!) diff --git a/docs/develop/apps/haikudepot/server.md b/docs/develop/apps/haikudepot/server.md deleted file mode 100644 index 4a9b35c4c3..0000000000 --- a/docs/develop/apps/haikudepot/server.md +++ /dev/null @@ -1,60 +0,0 @@ -# HaikuDepot and Server Interactions - -## Introduction - -This document aims to outline the general approach taken within the HaikuDepot application with regard to coordinating processes that relate to fetching and consuming data from remote systems. - -There are two main sources of remote data that are downloaded and consumed from network sources into the HaikuDepot desktop application; - -* Repository HPKR data from a Haiku mirror such as "HaikuPorts" -* Meta-data related to packages from [HaikuDepotServer](http://depot.haiku-os.org) (HDS) such as icons, localizations, ratings and so on. - -## Process, ProcessNode and Coordinator - -A _Process_ (root class ```AbstractProcess```) is a class that takes responsibility for some aspect of pulling material down from a network source and processing it. - -A _ProcessNode_ is a holder for a Process, but also takes responsibility for the following; - -* Maintaining the relationship between the Processes. For example, if Process A needs to complete before Process B then the ProcessNode would record this fact. It does this by storing _predecessor_ and _successor_ ProcessNodes. -* Starting the held Process in a newly spawned thread. -* Stopping the held Process. - -A _Coordinator_ holds a list of ProcessNodes. It will start, stop and cancel nodes as necessary such that, in an ideal case, the various ProcessNodes are completed in the correct order. - -The _ProcessCoordinatorFactory_ is able to create Coordinators. - -## Bulk Load Processes - -The following diagram shows the logical dependencies of the various Processes that are involved in refreshing the HPKR data from remote repositories and then loading data from the HDS system. - -![Process Dependencies](images/processes.svg) - -For example, the ```ServerRepositoryDataUpdateProcess``` must wait until the ```LocalRepositoryUpdateProcess``` has completed before it is able to be started. It is the reponsibility of the Coordinator to ensure that this sequencing is enforced. There are many instances of ```ServerPkgDataUpdateProcess``` shown because there will be one launched for each of the Repositories for which data will be downloaded; "HaikuDepot" etc... - -## Process / ProcessNode / Coordinator - -The following diagram shows the relationship and interplay between the various objects that are involved in running a larger task. Only fictional Processes are shown to keep the diagram tidy. See above for the actual Processes. - -![Process Relationship and Interplay](images/process-interplay.svg) - -Dotted lines show associations between elements and red lines show interaction or data-flow. Green arrows here demonstratively show some dependency; Process C cannot start until A and B are completed. - -The MainWindow owns the Coordinator for the life-span of undertaking some larger task. - -Each Process is coupled with a ProcessNode and then the Coordinator has a list of the ProcessNodes-s. The Processes are generally writing to the local disk system (often with compressed files) to cache data (see ```~/config/cache/HaikuDepot```) and also relay data into the ```Model``` object that maintains state for the HaikuDepot desktop application. - -The Processes communicate when they have finished to the Coordinator and it is at these events that the Coordinator is able to introspect the state of the Processes in order to know what to do next. - -The Coordinator also communicates with MainWindow. It communicates with the MainWindow in order to signal changes or progress in the overall larger task. The MainWindow also uses these events to discover when the Coordinator has completely finished. - -## Failure - -A Process may fail or be stopped. If a Process fails or is stopped then successor Processes, or those that would have run after the failed process, are stopped so that they will not run. - -The Coordinator will still try to complete any other Processes that could still run or are running already. - -Upon the Coordinator completing, the Coordinator will signal to the MainWindow client the change in state and then the MainWindow will be able to identify that the Coordinator has completed, but that something has gone wrong along the way. - -## Concurrency - -It is important to note that Processes may run concurrently. The Processes' are modelled by the Coordinator as a list rather than a tree. The dependencies are likely to form a tree or web of Processes that dictates the order of execution, but it is also quite possible to have multiple non-intersecting trees or webs such that Processes will execute independently. diff --git a/docs/develop/apps/haikudepot/server.rst b/docs/develop/apps/haikudepot/server.rst new file mode 100644 index 0000000000..28a0ff574e --- /dev/null +++ b/docs/develop/apps/haikudepot/server.rst @@ -0,0 +1,120 @@ +HaikuDepot and Server Interactions +================================== + +Introduction +------------ + +This document aims to outline the general approach taken within the +HaikuDepot application with regard to coordinating processes that relate +to fetching and consuming data from remote systems. + +There are two main sources of remote data that are downloaded and +consumed from network sources into the HaikuDepot desktop application; + +- Repository HPKR data from a Haiku mirror such as “HaikuPorts” +- Meta-data related to packages from + `HaikuDepotServer `__ (HDS) such as icons, + localizations, ratings and so on. + +Process, ProcessNode and Coordinator +------------------------------------ + +A *Process* (root class ``AbstractProcess``) is a class that takes +responsibility for some aspect of pulling material down from a network +source and processing it. + +A *ProcessNode* is a holder for a Process, but also takes responsibility +for the following; + +- Maintaining the relationship between the Processes. For example, if + Process A needs to complete before Process B then the ProcessNode + would record this fact. It does this by storing *predecessor* and + *successor* ProcessNodes. +- Starting the held Process in a newly spawned thread. +- Stopping the held Process. + +A *Coordinator* holds a list of ProcessNodes. It will start, stop and +cancel nodes as necessary such that, in an ideal case, the various +ProcessNodes are completed in the correct order. + +The *ProcessCoordinatorFactory* is able to create Coordinators. + +Bulk Load Processes +------------------- + +The following diagram shows the logical dependencies of the various +Processes that are involved in refreshing the HPKR data from remote +repositories and then loading data from the HDS system. + +.. figure:: images/processes.svg + :alt: Process Dependencies + + Process Dependencies + +For example, the ``ServerRepositoryDataUpdateProcess`` must wait until +the ``LocalRepositoryUpdateProcess`` has completed before it is able to +be started. It is the reponsibility of the Coordinator to ensure that +this sequencing is enforced. There are many instances of +``ServerPkgDataUpdateProcess`` shown because there will be one launched +for each of the Repositories for which data will be downloaded; +“HaikuDepot” etc… + +Process / ProcessNode / Coordinator +----------------------------------- + +The following diagram shows the relationship and interplay between the +various objects that are involved in running a larger task. Only +fictional Processes are shown to keep the diagram tidy. See above for +the actual Processes. + +.. figure:: images/process-interplay.svg + :alt: Process Relationship and Interplay + + Process Relationship and Interplay + +Dotted lines show associations between elements and red lines show +interaction or data-flow. Green arrows here demonstratively show some +dependency; Process C cannot start until A and B are completed. + +The MainWindow owns the Coordinator for the life-span of undertaking +some larger task. + +Each Process is coupled with a ProcessNode and then the Coordinator has +a list of the ProcessNodes-s. The Processes are generally writing to the +local disk system (often with compressed files) to cache data (see +``~/config/cache/HaikuDepot``) and also relay data into the ``Model`` +object that maintains state for the HaikuDepot desktop application. + +The Processes communicate when they have finished to the Coordinator and +it is at these events that the Coordinator is able to introspect the +state of the Processes in order to know what to do next. + +The Coordinator also communicates with MainWindow. It communicates with +the MainWindow in order to signal changes or progress in the overall +larger task. The MainWindow also uses these events to discover when the +Coordinator has completely finished. + +Failure +------- + +A Process may fail or be stopped. If a Process fails or is stopped then +successor Processes, or those that would have run after the failed +process, are stopped so that they will not run. + +The Coordinator will still try to complete any other Processes that +could still run or are running already. + +Upon the Coordinator completing, the Coordinator will signal to the +MainWindow client the change in state and then the MainWindow will be +able to identify that the Coordinator has completed, but that something +has gone wrong along the way. + +Concurrency +----------- + +It is important to note that Processes may run concurrently. The +Processes’ are modelled by the Coordinator as a list rather than a tree. +The dependencies are likely to form a tree or web of Processes that +dictates the order of execution, but it is also quite possible to have +multiple non-intersecting trees or webs such that Processes will execute +independently. diff --git a/docs/develop/build/repositories/README.md b/docs/develop/build/repositories/README.md deleted file mode 100644 index a176009635..0000000000 --- a/docs/develop/build/repositories/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# HaikuPorts build-packages repository - -The `build/jam/repositories/HaikuPorts` directory contains -RemotePackageRepository files which detail packages and -repositories leveraged during Haiku's build process. - -> Warning: The URL packages are obtained from -> are determined by the sha256sum of the repository -> file. - -## Updating - -Each RemotePackageRepository jam file in this directory -is processed by src/tools/hardlink_packages.py on the -HaikuPorts package server. - -1) Latest RemotePackageRepository jam file in git is downloaded on package server. -2) Packages are added to HaikuPorts by automatic or manual means. -3) hardlink_packages is provided all the relevant directories and RemotePackageRepository file -4) hardlink_packages performs additional modification of the RemotePackageRepository and creates - build repositories (https://eu.hpkg.haiku-os.org/haikuports/master/build-packages/) -5) The modified RemotePackageRepository file is copied back to the developers system and checked in to git. - -## Container Process - -Here is the fastest way to update this as of today. -Improvements are needed. Replace (ARCH) with architecture, (USER) with your non-root user. - -## Prepare the build-packages repository - -as root on limerick.ams3.haiku-os.org... - -1) wget https://git.haiku-os.org/haiku/plain/build/jam/repositories/HaikuPorts/(ARCH) -O /var/lib/docker/volumes/ci_data_master_(ARCH)/_data/(ARCH) -2) Enter the buildmaster container: - docker exec -it $(docker ps | grep ci_buildmaster_master_(ARCH) | awk '{ print $1 }') /bin/bash -l -3) apt update; apt install -y vim python3 python3-pkg-resources -4) edit the repository define, add the needed packages, _devel packages, and add base package to source section. -5) ln -s /var/buildmaster/package_tools/package_repo /usr/bin/package_repo -6) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/var/buildmaster/package_tools -7) ./package_tools/hardlink_packages.py (ARCH) ./(ARCH) /var/packages/repository/master/(ARCH)/current/packages/ /var/packages/build-packages/master/ -8) exit; cp /var/lib/docker/volumes/ci_data_master_(ARCH)/_data/(ARCH) /home/(USER)/(ARCH); chown (USER) /home/(USER)/(ARCH); - -## Pull the repostory file and commit it - -From your local system... - -1) scp -P2222 (USER)@limerick.ams3.haiku-os.org:./(ARCH) ./(ARCH) -2) commit the updated repostory define *without modifying it* in any way diff --git a/docs/develop/build/repositories/README.rst b/docs/develop/build/repositories/README.rst new file mode 100644 index 0000000000..197869da3d --- /dev/null +++ b/docs/develop/build/repositories/README.rst @@ -0,0 +1,64 @@ +HaikuPorts build-packages repository +==================================== + +The ``build/jam/repositories/HaikuPorts`` directory contains +RemotePackageRepository files which detail packages and repositories +leveraged during Haiku’s build process. + + Warning: The URL packages are obtained from are determined by the + sha256sum of the repository file. + +Updating +-------- + +Each RemotePackageRepository jam file in this directory is processed by +src/tools/hardlink_packages.py on the HaikuPorts package server. + +1) Latest RemotePackageRepository jam file in git is downloaded on + package server. +2) Packages are added to HaikuPorts by automatic or manual means. +3) hardlink_packages is provided all the relevant directories and + RemotePackageRepository file +4) hardlink_packages performs additional modification of the + RemotePackageRepository and creates build repositories + (https://eu.hpkg.haiku-os.org/haikuports/master/build-packages/) +5) The modified RemotePackageRepository file is copied back to the + developers system and checked in to git. + +Container Process +----------------- + +Here is the fastest way to update this as of today. Improvements are +needed. Replace (ARCH) with architecture, (USER) with your non-root +user. + +Prepare the build-packages repository +------------------------------------- + +as root on limerick.ams3.haiku-os.org… + +1) wget + https://git.haiku-os.org/haiku/plain/build/jam/repositories/HaikuPorts/(ARCH) + -O /var/lib/docker/volumes/ci_data_master_(ARCH)/_data/(ARCH) +2) Enter the buildmaster container: docker exec -it $(docker ps \| grep + ci_buildmaster_master_(ARCH) \| awk ‘{ print $1 }’) /bin/bash -l +3) apt update; apt install -y vim python3 python3-pkg-resources +4) edit the repository define, add the needed packages, \_devel + packages, and add base package to source section. +5) ln -s /var/buildmaster/package_tools/package_repo + /usr/bin/package_repo +6) export + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/var/buildmaster/package_tools +7) ./package_tools/hardlink_packages.py (ARCH) ./(ARCH) + /var/packages/repository/master/(ARCH)/current/packages/ + /var/packages/build-packages/master/ +8) exit; cp /var/lib/docker/volumes/ci_data_master_(ARCH)/_data/(ARCH) + /home/(USER)/(ARCH); chown (USER) /home/(USER)/(ARCH); + +Pull the repostory file and commit it +------------------------------------- + +From your local system… + +1) scp -P2222 (USER)@limerick.ams3.haiku-os.org:./(ARCH) ./(ARCH) +2) commit the updated repostory define *without modifying it* in any way diff --git a/docs/develop/busses/agp_gart/ReadMe.md b/docs/develop/busses/agp_gart/ReadMe.md deleted file mode 100644 index f89255d789..0000000000 --- a/docs/develop/busses/agp_gart/ReadMe.md +++ /dev/null @@ -1,22 +0,0 @@ -AGP (and PCI-express) Graphics Address Re-Mapping Table -======================================================= - -The GART is an IO-MMU allowing the videocard and CPU to share some memory. -Either the CPU can access the video RAM directly ("aperture"), or the video -card can access the system RAM using DMA access. - -The GART converts between physical addresses and virtual addresses on the -video card side. Of course, the CPU must then map these physical addresses -in its own address space to use them (using the MMU). - -The GART works as you'd expect from an MMU. It has a page table (called GTT) -in RAM and walks it to figure out mappings. Since there cannot be page misses -(that would require exception handling on the GPU side), access to missing -pages are instead sent to a dedicated "scratch" page which is not used for -anything else. - -Our driver implements the GART and GTT for Intel graphics card only, so far. -Since our videodrivers are only doing modesetting, they do not need much -support and other drivers implemented GTT management directly on their own -(it is usually enough to make the framebuffer accessible to the CPU). However, -this could be generalized into a more flexible iommu bus protocol. diff --git a/docs/develop/busses/agp_gart/ReadMe.rst b/docs/develop/busses/agp_gart/ReadMe.rst new file mode 100644 index 0000000000..5803fce68d --- /dev/null +++ b/docs/develop/busses/agp_gart/ReadMe.rst @@ -0,0 +1,23 @@ +AGP (and PCI-express) Graphics Address Re-Mapping Table +======================================================= + +The GART is an IO-MMU allowing the videocard and CPU to share some +memory. Either the CPU can access the video RAM directly (“aperture”), +or the video card can access the system RAM using DMA access. + +The GART converts between physical addresses and virtual addresses on +the video card side. Of course, the CPU must then map these physical +addresses in its own address space to use them (using the MMU). + +The GART works as you’d expect from an MMU. It has a page table (called +GTT) in RAM and walks it to figure out mappings. Since there cannot be +page misses (that would require exception handling on the GPU side), +access to missing pages are instead sent to a dedicated “scratch” page +which is not used for anything else. + +Our driver implements the GART and GTT for Intel graphics card only, so +far. Since our videodrivers are only doing modesetting, they do not need +much support and other drivers implemented GTT management directly on +their own (it is usually enough to make the framebuffer accessible to +the CPU). However, this could be generalized into a more flexible iommu +bus protocol. diff --git a/docs/develop/busses/bluetooth/overview.md b/docs/develop/busses/bluetooth/overview.md deleted file mode 100644 index 92d5ac6f28..0000000000 --- a/docs/develop/busses/bluetooth/overview.md +++ /dev/null @@ -1,17 +0,0 @@ -(Copied mostly from ) - -**L2cap under `network/protocols/l2cap`**: Provides socket interface to have l2cap channels. L2CAP offers connection oriented and connectionless sockets. But bluetooth stack as this point has no interchangeability with TCP/IP, A Higher level Bluetooth profile must be implemented - -**HCI under `src/add-ons/kernel/bluetooth`**: Here we have 2 modules, one for handling global bluetooth data structures such as connection handles and L2cap channels, and frames - -**H2generic under `src/add-ons/kernel/drivers/bluetooth`**: The USB driver, implementing the H2 transport. - -**Bluetooth kit under `src/kit/bluetooth`**: C++ implementation based on JSR82 api. - -**Bluetooth Server under `src/servers/bluetooth`**: Basically handling opened devices (local connected fisically in our system) and forwaring kit calls to them. - -**Bluetooth Preferences under `src/preferences/bluetooth`**: Configuration using the kit - -**Test applications under `src/tests/kits/bluetooth`**. - -There is a small prototype component which is not here documented below src/add-ons/bluetooth/ResetLocalDevice. Its intention was to be an add-on of bluetooth preferences, So that new HCI commands could be customized by users or external developers. I did not like at the end the idea, I did not find the flexibility I wanted. diff --git a/docs/develop/busses/bluetooth/overview.rst b/docs/develop/busses/bluetooth/overview.rst new file mode 100644 index 0000000000..5a9235c492 --- /dev/null +++ b/docs/develop/busses/bluetooth/overview.rst @@ -0,0 +1,36 @@ +Bluetooth overview +================== + +(Copied mostly from +http://urnenfeld.blogspot.de/2012/07/in-past-i-got-to-know-that-motivation.html) + +**L2cap under ``network/protocols/l2cap``**: Provides socket interface +to have l2cap channels. L2CAP offers connection oriented and +connectionless sockets. But bluetooth stack as this point has no +interchangeability with TCP/IP, A Higher level Bluetooth profile must be +implemented + +**HCI under ``src/add-ons/kernel/bluetooth``**: Here we have 2 modules, +one for handling global bluetooth data structures such as connection +handles and L2cap channels, and frames + +**H2generic under ``src/add-ons/kernel/drivers/bluetooth``**: The USB +driver, implementing the H2 transport. + +**Bluetooth kit under ``src/kit/bluetooth``**: C++ implementation based +on JSR82 api. + +**Bluetooth Server under ``src/servers/bluetooth``**: Basically handling +opened devices (local connected fisically in our system) and forwaring +kit calls to them. + +**Bluetooth Preferences under ``src/preferences/bluetooth``**: +Configuration using the kit + +**Test applications under ``src/tests/kits/bluetooth``**. + +There is a small prototype component which is not here documented below +src/add-ons/bluetooth/ResetLocalDevice. Its intention was to be an +add-on of bluetooth preferences, So that new HCI commands could be +customized by users or external developers. I did not like at the end +the idea, I did not find the flexibility I wanted. diff --git a/docs/develop/busses/sdhci/sdhci_mmc_driver.md b/docs/develop/busses/sdhci/sdhci_mmc_driver.md deleted file mode 100644 index 9709026d05..0000000000 --- a/docs/develop/busses/sdhci/sdhci_mmc_driver.md +++ /dev/null @@ -1,227 +0,0 @@ -# SDHCI MMC Driver - -This driver project is a part of GSoC'18 and is aimed at providing support for -PCI devices with class 8 and subclass 5 over x86 architecture. This document -will make you familiar with the [code produced during GSoC](https://review.haiku-os.org/#/c/haiku/+/318/), -loading and testing the driver(including hardware emulation), insight into the -code and future tasks. - -For detailed explanations about the project, you can refer the -[weekly reports](https://www.haiku-os.org/blog/krish_iyer) and comment issues -if any. For this project we have referred [SD Host Controller Spec Version 1.00](https://www.sdcard.org/downloads/pls/pdf/index.php?p=PartA2_SD_Host_Controller_Simplified_Specification_Ver1.00.jpg&f=PartA2_SD_Host_Controller_Simplified_Specification_Ver1.00.pdf&e=EN_A2100) -and [Physical Layer Spec Version 1.10](https://www.sdcard.org/downloads/pls/pdf/index.php?p=Part1_Physical_Layer_Simplified_Specification_Ver1.10.jpg&f=Part1_Physical_Layer_Simplified_Specification_Ver1.10.pdf&e=EN_P1110). - -## Loading and testing the driver -### Emulating the hardware - -We will emulate a SDHC device using qemu as all system may not have the device. -These days systems provide transfer to SD/ MMC card over USB. The document will -not instruct you on how to build haiku but you can refer the link to -[compile and build the haiku images](https://www.haiku-os.org/guides/building/) -or the [week #1 and #2](https://www.haiku-os.org/blog/krish_iyer/2018-05-06_gsoc_2018_sdhci_mmc_driver_week_1_and_2/) -project report will also work. - -After building the image, we will emulate the hardware and host haiku on top of that. - -#### Emulation -For emulating a sdhci-pci device - - qemu-img create sd-card.img 32M - qemu-system-x86_64 -drive index=0,file=haiku-nightly-anyboot.iso,format=raw \ - -device sdhci-pci -device sd-card,drive=mydrive \ - -drive if=sd,index=1,file=sd-card.img,format=raw,id=mydrive - -m 512M -enable-kvm -usbdevice tablet -machine q35 - -This does the following: - - Create an SD card image of 32MB - - Run qemu with a bootable image in an IDE disk, and an SDHCI bus with an SD card in it - - Have enough memory to boot Haiku, use KVM mode for speed, and a tablet for ease of use - - Use the Q35 chipset so the mouse and SDHCI controllers don't share an interrupt (not strictly - required, but it avoids calls to the SDHCI interrupt handler on every mouse move). - -Tracing of SD operations can also be added to see how qemu is interpreting our commands: - - -trace sdhci* -trace sdbus* -trace sdcard* - -### Testing and loading the driver -The code is merged and part of the default Haiku build. - -## Insight into the code and future tasks - -### Bus, bus manager, and drivers - -The MMC stack is a device manager based "new style" driver. This requires splitting the driver -in different parts but allow easy reuse of each part (for example to support eMMC or SDIO with a -large part of the code in common with plain SD/MMC). - -#### MMC Bus drivers (src/add-ons/kernel/busses/mmc) - -The bus driver provides the low level aspects: interrupts management, DMA transfer, accessing the -hardware registers. It acts as a platform abstraction layer so that the bus manager and disk driver -can be written independently of the underlying hardare. - -Currently there is a single implementation for SDHCI (MMC bus over PCI). Later on, other drivers -will be added for other ways to access the MMC bus (for example on ARM devices where it does not -live on a PCI bus, and may have a different register layout). - -For this reason, the bus drivers should only do the most low-level things, trying to keep as -much code as possible in the upper layers. - -One slightly confusing thing about SDHCI is that it allows a single PCI device to implement -multiple separate MMC busses (each of which could have multiple devices attached). For this reason -there is an SDHCI "device" that attaches to the PCI device node for the controller, and then -publishes multiple device nodes for each available bus. The nodes then work independently of each -other. - -#### The Bus Manager (src/add-ons/kernel/bus_managers/mmc) - -The bus manager is responsible for enumerating devices on the bus, assigning them addresses, -and keeping track of which card is active at any given time. - -Essentially it has everything that requires collaboration between multiple MMC devices, as well -as things that are not specific to a device type (common to SDIO, SD and MMC cards, for example) - -#### Disk Driver (src/add-ons/kernel/drivers/disk/mmc) - -This is a mass storage driver for MMC, SD and SDHC cards. Currently only SD and SDHC are tested, -MMC and eMMC will have to be added (they are similar but there are some differences). - -#### Wiring the driver in the device manager (src/system/kernel/device_manager/device_manager.cpp) - -(note: possibly not accurate documentation, I did not check how things in the device manager are -actually implemented, but this is my understanding of it). - -The device manager attempts to implement lazy, on-demand scanning of the devices. The idea is to -speed up booting by not spending a lot of time scanning everything first, and only scanning -small parts of the device tree as they are needed. - -The trigger is accesses to the devfs. For example, when an application opens /dev/disk, the device -manager will start looking for disks so it can populate it. This means the device manager needs to -know which branches of the device tree to explore. Currently this knowledge is hardcoded into the -device tree sourcecode, and there's a TODO item about moving that knowledge to drivers instead. But -it's tricky, since the whole point is to avoid loading all the drivers. - -Anyway, currently, the device manager is hardcoded to look for mass storage devices under SDHCI -busses, both standard ones and some non-standard ones (for example, Ricoh provides SDHCI implenentations -that are conform to the spec, except they don't have the right device type in the PCI registers). - -### Insight into the code -#### MMC Bus management overview - -The device tree for MMC support looks like this: - -* PCI bus manager - * (other PCI devices) - * SDHCI controller - * SDHCI bus - * MMC bus manager - * MMC device - * mmc\_disk device - * MMC device - * (other SDIO driver) - * MMC bus manager (second MMC bus) - * MMC device - * mmc\_disk device - -At the first level, the PCI bus manager publishes a device node for each device -found. One of them is our SDHCI controller, identified either by the PCI device -class and subclass, or for not completely SDHCI compatible device, by the -device and vendor IDs. - -The SDHCI bus driver attaches to this device and publishes his own node. It -then scans the device and publishes an MMC bus node for each slot (there may -be multiple SD slots attached to a single PCI controller). - -The MMC bus manager then attach to each of these slots, and send the appropriate -commands for enumerating the SD cards (there may be multiple cards in a "slot"), -and publishes a device node for each of them. Finally, the mmc\_disk driver can -bind itself to one of these device nodes, and publish the corresponding disk -node, which is also be made available in /dev/disk/mmc. - -Currently the mmc bus does not publish anything in the devfs, but this could be -added if sending raw SD/MMC commands to SD cards from userland is considered -desirable. - -#### SDHCI driver - -The SDHCI driver is the lowest level of the MMC stack. It provides abstraction -of the SDHCI device. Later on, different way to access an SD bus may be added, -for example for ARM devices which decided to use a different register interface. - -The entry point is as usual **supports\_device()**. This method is called only -for devices which may be SDHCI controllers, thanks to filtering done in the -device manager to probe only the relevant devices. The probing is done on-demand, -currently when the system is enumerating /dev/disk in the devfs. Later on, when -we have SDIO support, probing will also be triggered in other cases. - -The function identifies the device by checking the class and subclass, as well -as a limited set of hardcoded PCI device and vendor IDs for devices that do not -use the assigned subclass. - -Once a compatible device is found, **register\_child\_devices()** is used to -publish device nodes for each slot to be controlled by the mmc bus manager. -The registers for each device are mapped into virtual memory, using the -information from the PCI bar registers. **struct registers** is defined so that -it matches the register layout, and provide a little abstraction to raw register -access. - -An SdhciBus object is created to manage each of these busses at the SDHCI level. -It will be responsible for executing SD commands on that bus, and dealing with -the resulting interrupts. - -#### The Bus Manager - -The MMC bus manager manages the MMC bus (duh). Its tasks are: - -* enumerating SD cards on the bus -* assigning RCAs to the cards for identifying them when sending commands -* setting the bus clock speed according to what the cards can handle -* remember which SD card is currently active (CMD7) -* manage cards state -* publish device nodes for each card - -#### Disk Driver - -The disk driver is attached to devices implementing SDSC or SDHC/SDXC commands. -There will be other drivers for non-storage (SDIO) cards. - -To help with this, the MMC bus manager provides the device with the information -it gathered while initializing the device. According to the commands recognized -by the card during the initialization sequence, it's possible to know if it's -SDSC, SDHC/SDXC, or something else (SDIO, legacy MMC, etc). - -The disk driver publishes devfs entries in /dev/disk/mmc and implements the -usual interface for disk devices. From this point on, the device can be used -just like any other mass storage device. - -#### Getting everything loaded - -The device manager is not completely implemented yet. As a result, some -decisions about which drivers to load are hardcoded in device\_manager.cpp. - -It has been adjusted to handover SDHCI devices to the MMC bus. Whenever a -"disk" device is requested, the MMC busses are searched, which results in -loading the SDHCI driver and probing for SD cards. When we get support for -other types of SDIO devices, we will need to adjust the device manager to -probe the SDHCI bus when these type of devices are requested, too. - - -### Tasks to be completed - -The SDHCI driver is able to send and receive commands. However it does not -handle card insertion and removal interrupts yet, so the card must be already -inserted when the driver is loaded. - -The mmc_disk driver is complete and working, but was not tested for MMC and eMMC -devices. Some changes may be needed. - -There is also work to be done for better performance: making sure we switch to the -high-speed clock when an SD card supports it, and use the 4-bit data transfer mode -instead of the default 1-bit if possible. - -Drivers for SDIO devices should also be added. The mmc_bus and SDHCI drivers have -been tested only with one card on the bus at a time (for lack of hardware allowing -more complex setups). - -If you find it difficult to understand the driver development and it's -functioning and role, please refer *docs/develop/kernel/device_manager_introduction.html* diff --git a/docs/develop/busses/sdhci/sdhci_mmc_driver.rst b/docs/develop/busses/sdhci/sdhci_mmc_driver.rst new file mode 100644 index 0000000000..7f0e19ee29 --- /dev/null +++ b/docs/develop/busses/sdhci/sdhci_mmc_driver.rst @@ -0,0 +1,291 @@ +SDHCI MMC Driver +================ + +This driver project is a part of GSoC’18 and is aimed at providing +support for PCI devices with class 8 and subclass 5 over x86 +architecture. This document will make you familiar with the `code +produced during GSoC `__, +loading and testing the driver(including hardware emulation), insight +into the code and future tasks. + +For detailed explanations about the project, you can refer the `weekly +reports `__ and comment issues +if any. For this project we have referred `SD Host Controller Spec +Version +1.00 `__ +and `Physical Layer Spec Version +1.10 `__. + +Loading and testing the driver +------------------------------ + +Emulating the hardware +~~~~~~~~~~~~~~~~~~~~~~ + +We will emulate a SDHC device using qemu as all system may not have the +device. These days systems provide transfer to SD/ MMC card over USB. +The document will not instruct you on how to build haiku but you can +refer the link to `compile and build the haiku +images `__ or the `week #1 +and +#2 `__ +project report will also work. + +After building the image, we will emulate the hardware and host haiku on +top of that. + +Emulation +^^^^^^^^^ + +For emulating a sdhci-pci device + +:: + + qemu-img create sd-card.img 32M + qemu-system-x86_64 -drive index=0,file=haiku-nightly-anyboot.iso,format=raw \ + -device sdhci-pci -device sd-card,drive=mydrive \ + -drive if=sd,index=1,file=sd-card.img,format=raw,id=mydrive + -m 512M -enable-kvm -usbdevice tablet -machine q35 + +This does the following: - Create an SD card image of 32MB - Run qemu +with a bootable image in an IDE disk, and an SDHCI bus with an SD card +in it - Have enough memory to boot Haiku, use KVM mode for speed, and a +tablet for ease of use - Use the Q35 chipset so the mouse and SDHCI +controllers don’t share an interrupt (not strictly required, but it +avoids calls to the SDHCI interrupt handler on every mouse move). + +Tracing of SD operations can also be added to see how qemu is +interpreting our commands: + +:: + + -trace sdhci* -trace sdbus* -trace sdcard* + +Testing and loading the driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The code is merged and part of the default Haiku build. + +Insight into the code and future tasks +-------------------------------------- + +Bus, bus manager, and drivers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The MMC stack is a device manager based “new style” driver. This +requires splitting the driver in different parts but allow easy reuse of +each part (for example to support eMMC or SDIO with a large part of the +code in common with plain SD/MMC). + +MMC Bus drivers (src/add-ons/kernel/busses/mmc) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The bus driver provides the low level aspects: interrupts management, +DMA transfer, accessing the hardware registers. It acts as a platform +abstraction layer so that the bus manager and disk driver can be written +independently of the underlying hardare. + +Currently there is a single implementation for SDHCI (MMC bus over PCI). +Later on, other drivers will be added for other ways to access the MMC +bus (for example on ARM devices where it does not live on a PCI bus, and +may have a different register layout). + +For this reason, the bus drivers should only do the most low-level +things, trying to keep as much code as possible in the upper layers. + +One slightly confusing thing about SDHCI is that it allows a single PCI +device to implement multiple separate MMC busses (each of which could +have multiple devices attached). For this reason there is an SDHCI +“device” that attaches to the PCI device node for the controller, and +then publishes multiple device nodes for each available bus. The nodes +then work independently of each other. + +The Bus Manager (src/add-ons/kernel/bus_managers/mmc) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The bus manager is responsible for enumerating devices on the bus, +assigning them addresses, and keeping track of which card is active at +any given time. + +Essentially it has everything that requires collaboration between +multiple MMC devices, as well as things that are not specific to a +device type (common to SDIO, SD and MMC cards, for example) + +Disk Driver (src/add-ons/kernel/drivers/disk/mmc) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a mass storage driver for MMC, SD and SDHC cards. Currently only +SD and SDHC are tested, MMC and eMMC will have to be added (they are +similar but there are some differences). + +Wiring the driver in the device manager (src/system/kernel/device_manager/device_manager.cpp) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +(note: possibly not accurate documentation, I did not check how things +in the device manager are actually implemented, but this is my +understanding of it). + +The device manager attempts to implement lazy, on-demand scanning of the +devices. The idea is to speed up booting by not spending a lot of time +scanning everything first, and only scanning small parts of the device +tree as they are needed. + +The trigger is accesses to the devfs. For example, when an application +opens /dev/disk, the device manager will start looking for disks so it +can populate it. This means the device manager needs to know which +branches of the device tree to explore. Currently this knowledge is +hardcoded into the device tree sourcecode, and there’s a TODO item about +moving that knowledge to drivers instead. But it’s tricky, since the +whole point is to avoid loading all the drivers. + +Anyway, currently, the device manager is hardcoded to look for mass +storage devices under SDHCI busses, both standard ones and some +non-standard ones (for example, Ricoh provides SDHCI implenentations +that are conform to the spec, except they don’t have the right device +type in the PCI registers). + +Insight into the code +~~~~~~~~~~~~~~~~~~~~~ + +MMC Bus management overview +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The device tree for MMC support looks like this: + +- PCI bus manager + + - (other PCI devices) + - SDHCI controller + + - SDHCI bus + + - MMC bus manager + + - MMC device + + - mmc_disk device + + - MMC device + + - (other SDIO driver) + + - MMC bus manager (second MMC bus) + + - MMC device + + - mmc_disk device + +At the first level, the PCI bus manager publishes a device node for each +device found. One of them is our SDHCI controller, identified either by +the PCI device class and subclass, or for not completely SDHCI +compatible device, by the device and vendor IDs. + +The SDHCI bus driver attaches to this device and publishes his own node. +It then scans the device and publishes an MMC bus node for each slot +(there may be multiple SD slots attached to a single PCI controller). + +The MMC bus manager then attach to each of these slots, and send the +appropriate commands for enumerating the SD cards (there may be multiple +cards in a “slot”), and publishes a device node for each of them. +Finally, the mmc_disk driver can bind itself to one of these device +nodes, and publish the corresponding disk node, which is also be made +available in /dev/disk/mmc. + +Currently the mmc bus does not publish anything in the devfs, but this +could be added if sending raw SD/MMC commands to SD cards from userland +is considered desirable. + +SDHCI driver +^^^^^^^^^^^^ + +The SDHCI driver is the lowest level of the MMC stack. It provides +abstraction of the SDHCI device. Later on, different way to access an SD +bus may be added, for example for ARM devices which decided to use a +different register interface. + +The entry point is as usual **supports_device()**. This method is called +only for devices which may be SDHCI controllers, thanks to filtering +done in the device manager to probe only the relevant devices. The +probing is done on-demand, currently when the system is enumerating +/dev/disk in the devfs. Later on, when we have SDIO support, probing +will also be triggered in other cases. + +The function identifies the device by checking the class and subclass, +as well as a limited set of hardcoded PCI device and vendor IDs for +devices that do not use the assigned subclass. + +Once a compatible device is found, **register_child_devices()** is used +to publish device nodes for each slot to be controlled by the mmc bus +manager. The registers for each device are mapped into virtual memory, +using the information from the PCI bar registers. **struct registers** +is defined so that it matches the register layout, and provide a little +abstraction to raw register access. + +An SdhciBus object is created to manage each of these busses at the +SDHCI level. It will be responsible for executing SD commands on that +bus, and dealing with the resulting interrupts. + +The Bus Manager +^^^^^^^^^^^^^^^ + +The MMC bus manager manages the MMC bus (duh). Its tasks are: + +- enumerating SD cards on the bus +- assigning RCAs to the cards for identifying them when sending + commands +- setting the bus clock speed according to what the cards can handle +- remember which SD card is currently active (CMD7) +- manage cards state +- publish device nodes for each card + +Disk Driver +^^^^^^^^^^^ + +The disk driver is attached to devices implementing SDSC or SDHC/SDXC +commands. There will be other drivers for non-storage (SDIO) cards. + +To help with this, the MMC bus manager provides the device with the +information it gathered while initializing the device. According to the +commands recognized by the card during the initialization sequence, it’s +possible to know if it’s SDSC, SDHC/SDXC, or something else (SDIO, +legacy MMC, etc). + +The disk driver publishes devfs entries in /dev/disk/mmc and implements +the usual interface for disk devices. From this point on, the device can +be used just like any other mass storage device. + +Getting everything loaded +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The device manager is not completely implemented yet. As a result, some +decisions about which drivers to load are hardcoded in +device_manager.cpp. + +It has been adjusted to handover SDHCI devices to the MMC bus. Whenever +a “disk” device is requested, the MMC busses are searched, which results +in loading the SDHCI driver and probing for SD cards. When we get +support for other types of SDIO devices, we will need to adjust the +device manager to probe the SDHCI bus when these type of devices are +requested, too. + +Tasks to be completed +~~~~~~~~~~~~~~~~~~~~~ + +The SDHCI driver is able to send and receive commands. However it does +not handle card insertion and removal interrupts yet, so the card must +be already inserted when the driver is loaded. + +The mmc_disk driver is complete and working, but was not tested for MMC +and eMMC devices. Some changes may be needed. + +There is also work to be done for better performance: making sure we +switch to the high-speed clock when an SD card supports it, and use the +4-bit data transfer mode instead of the default 1-bit if possible. + +Drivers for SDIO devices should also be added. The mmc_bus and SDHCI +drivers have been tested only with one card on the bus at a time (for +lack of hardware allowing more complex setups). + +If you find it difficult to understand the driver development and it’s +functioning and role, please refer +*docs/develop/kernel/device_manager_introduction.html* diff --git a/docs/develop/busses/usb/USB_stack_design b/docs/develop/busses/usb/USB_stack_design.rst similarity index 99% rename from docs/develop/busses/usb/USB_stack_design rename to docs/develop/busses/usb/USB_stack_design.rst index 09e98c165e..4ff683f5b3 100644 --- a/docs/develop/busses/usb/USB_stack_design +++ b/docs/develop/busses/usb/USB_stack_design.rst @@ -1,4 +1,4 @@ -INSIDE THE USB STACK +The USB stack ============== For all of you who have been over my code and thought: "What is this guy doing?", I can firmly respond that I sometimes haven't a clue either. But when I'm actually reviewing my own code, I occassionally get the feeling that I do have a direction I'm persueing. In order to define this direction more, and share you in the fun, I have written this document. It's a rather superficial account (without actually quoting any code), but it should be enough to get you started. @@ -15,4 +15,4 @@ New transfers are initialized by Pipes. The Transfer objects will be created by As for closing, this design lacks some objects that correspond to USB objects. For example, there are no special Endpoint objects. At the moment, passing adresses is sufficient, but perhaps it should change in order to complete the design. Also, there is currently no idea how locking should work. Finally, the Stack class currently includes some memory management for usb, however, checking from the specs, only UHCI requires manual scheduling, OHCI and EHCI manage the scheduling and packaging itself. That should move. But at the moment, this design works. -Finally, this document gives an idea of how it should work. For details: check the USB specs, host controller specs and the code. If anything stays unclear, please comment on my weblog, or e-mail me. \ No newline at end of file +Finally, this document gives an idea of how it should work. For details: check the USB specs, host controller specs and the code. If anything stays unclear, please comment on my weblog, or e-mail me. diff --git a/docs/develop/conf.py b/docs/develop/conf.py new file mode 100644 index 0000000000..216bbaf182 --- /dev/null +++ b/docs/develop/conf.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Haiku internals' +copyright = '2021, The Haiku development team' +author = 'The Haiku development team' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Haikuinternalsdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Haikuinternals.tex', 'Haiku internals Documentation', + 'The Haiku development team', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'haikuinternals', 'Haiku internals Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Haikuinternals', 'Haiku internals Documentation', + author, 'Haikuinternals', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] diff --git a/docs/develop/drivers/disk/ioctls.txt b/docs/develop/drivers/disk/ioctls.rst similarity index 88% rename from docs/develop/drivers/disk/ioctls.txt rename to docs/develop/drivers/disk/ioctls.rst index 1f6a3e3adc..4f255f7fc8 100644 --- a/docs/develop/drivers/disk/ioctls.txt +++ b/docs/develop/drivers/disk/ioctls.rst @@ -1,37 +1,48 @@ +Disk driver ioctls +================== + Here is a list of ioctls usually implemented by disk devices. B_GET_DEVICE_SIZE +----------------- The parameter is a size_t and is filled with the disk size in bytes. This is limited to 4GB and not very useful. B_GET_GEOMETRY is used instead. B_GET_GEOMETRY +-------------- The parameter is a device_geometry structure to be filled with the device geometry. B_GET_ICON_NAME +--------------- Deprecated. Get the name of an icon to use. The icons are hardcoded in Tracker. B_GET_VECTOR_ICON +----------------- The parameter is a device_icon structure to be populated with the icon data in HVIF format. This icon is then used to show the disk in Tracker, for example. B_EJECT_DEVICE +-------------- Eject the device (for removable devices). B_LOAD_MEDIA +------------ Load the device (reverse of eject) if possible. B_FLUSH_DRIVE_CACHE +------------------- Make sure all data is stored on persistent storage and not in caches (including any caching inside the device) B_TRIM_DEVICE +------------- The parameter is an fs_trim_data structure. It is guaranteed to be in kernel memory because the partition manager pre-processes requests coming from userland and makes sure no sectors diff --git a/docs/develop/drivers/intel_extreme/generations.txt b/docs/develop/drivers/intel_extreme/generations.rst similarity index 92% rename from docs/develop/drivers/intel_extreme/generations.txt rename to docs/develop/drivers/intel_extreme/generations.rst index 31db9f2457..265a3d7be5 100644 --- a/docs/develop/drivers/intel_extreme/generations.txt +++ b/docs/develop/drivers/intel_extreme/generations.rst @@ -1,5 +1,5 @@ Intel video hardware generations -================================ +################################ This file summarizes the different generations of Intel hardware, because the naming is a bit inconsistent and it's hard to follow which is which sometimes. @@ -13,12 +13,12 @@ These are the i740 and i810 devices handled by intel_810. No further info will be provided here. Generation 2 / 2002 -============ +=================== i830, 845, 85x, 865 Generation 3 / 2004 -============ +=================== This is the first generation to be documented at intellinuxgraphics.org. Generation 2 devices are quite similar for the modesetting part, but not @@ -31,7 +31,7 @@ GMA 3100 (G31, G33, Q33 et Q35) GMA 3150 (Pineview for Atom CPUs) Generation 4 / 2006 -============ +=================== GMA X3000 (i965G) GMA X3100 (i965GM) @@ -41,7 +41,7 @@ GMA 4500M / 4500HD (GL40, GS45, GM45, GM47) GMA X4500 / X4500HD (G41, G43 (X4500), G45 (X4500HD)) Generation 5 / 2010 -============ +=================== Westmere / Clarkdale, Arrandale / Iron Lake / Ibex Peak @@ -50,14 +50,14 @@ Switches from the traditional northbridge / southbridge to the new are now directly in the CPU package. Generation 6 / 2011 -============ +=================== Sandybridge / Cougar Point The northbridge and CPU are now even on the same die. Generation 7 / 2012 -============ +=================== Ivy Bridge / Panther Point and Haswell / Lynx Point @@ -73,12 +73,12 @@ This is also the first generation to support 3 independant displays, which also impacts the register layout in many places. Generation 8 / 2013 -============ +=================== Broadwell / Wildcat Point and Braswell Generation 9 / 2015 -============ +=================== Skylake / Sunrise Point, Apollo Lake, Kaby Lake / Union Point diff --git a/docs/develop/file_systems/befs/resources.html b/docs/develop/file_systems/befs/resources.html deleted file mode 100644 index fd728e2c34..0000000000 --- a/docs/develop/file_systems/befs/resources.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - Resources for the Be File System - - - - -

Resources for the Be File System

- -

Probably the best resource for a description of the inner workings of BFS is the -book "Practical File System Design with the Be File System" written by Dominic -Giampaolo and published by Morgan Kaufmann Publishers. Although that book is out of -print, it's available at the Haiku web site. - -

If you prefer to see how it works in code, please have a look at Haiku's BFS -implementation. - -

If you are interested in the Haiku file system API, please refer to its documentation -as part of the Haiku book. - - - diff --git a/docs/develop/file_systems/befs/resources.rst b/docs/develop/file_systems/befs/resources.rst new file mode 100644 index 0000000000..e507fd1907 --- /dev/null +++ b/docs/develop/file_systems/befs/resources.rst @@ -0,0 +1,16 @@ +The Be File System +================================ + +Probably the best resource for a description of the inner workings of +BFS is the book "Practical File System Design with the Be File System" +written by Dominic Giampaolo and published by Morgan Kaufmann +Publishers. Although that book is out of print, it's available at the +`Haiku web +site `__. + +If you prefer to see how it works in code, please have a look at +`Haiku's BFS +implementation `__. + +If you are interested in the Haiku file system API, please refer to its +documentation as part of the Haiku book. diff --git a/docs/develop/file_systems/overview.txt b/docs/develop/file_systems/overview.rst similarity index 97% rename from docs/develop/file_systems/overview.txt rename to docs/develop/file_systems/overview.rst index fff1190e02..63134e8e74 100644 --- a/docs/develop/file_systems/overview.txt +++ b/docs/develop/file_systems/overview.rst @@ -1,4 +1,4 @@ -Writing filesystem drivers for Haiku +Filesystem drivers ==================================== Filesystem drivers are in src/add-ons/kernel/file_system @@ -8,6 +8,7 @@ required. For example, NFS is a network filesystem, so it doesn't need one. Implementation notes -------------------- + Each filesystem driver must define a few structures which act as the interface between the VFS and the filesystem implementation. These structures contain function pointers, some of which are optional, @@ -85,3 +86,8 @@ as kernel code is usually quite easy (and provides a performance boost) Once the basic operations are working fine, it is a good idea to perform more agressive testing. Examples of scripts doing this are available in src/tests/add-ons/kernel/file_systems/ for the fat and ext2 filesystems. + +.. toctree:: + + /file_systems/ufs2 + /file_systems/befs/resources diff --git a/docs/develop/file_systems/ufs2.txt b/docs/develop/file_systems/ufs2.rst similarity index 97% rename from docs/develop/file_systems/ufs2.txt rename to docs/develop/file_systems/ufs2.rst index e09e22ec3d..ae18e7b817 100644 --- a/docs/develop/file_systems/ufs2.txt +++ b/docs/develop/file_systems/ufs2.rst @@ -1,4 +1,4 @@ -Implementation of UFS2 on Haiku +The UFS2 filesystem =============================== While making a device for testing I have used a usb drive and formatted it to diff --git a/docs/develop/index.rst b/docs/develop/index.rst new file mode 100644 index 0000000000..d24eb6f474 --- /dev/null +++ b/docs/develop/index.rst @@ -0,0 +1,69 @@ +Welcome to Haiku internals's documentation! +=========================================== + + +Target audience +--------------- + +This documentation is aimed at people who want to contribute to Haiku by modifying the operating +system itself. It covers various topics, both technical (how things work) and organizational +(patch submission process, for example). + +This document might also be useful to application developers trying to understand the behavior of +the operating system in some specific cases, however, the `API documentation `_ should answer most of +the questions in this area already. + +This documentation assumes basic knowledge of C++ and the Be API, if you need more information +about that, please see the `Learning to program with Haiku `_ book. + +Status of this document +----------------------- + +The work on this book has just started, many sections are incomplete or missing. Here is a list of +other resources that could be useful: + +* The `Haiku website `_ has several years of blog posts and articles + documenting many aspects of the system, +* The `Coding guidelines `_ describes how code should be formatted, +* The `User guide `_ documents Haiku from the users' point of view and can be useful to understand how things are supposed to work, +* The `Haiku Interface Guidelines `_ document graphical user interface conventions, +* The `Haiku Icon Guidelines `_ gives some rules for making icons fitting with the style of the existing ones. + +Table of contents +----------------- + +* :ref:`search` + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + /build/repositories/README + /apps/haikudepot/server + /midi/index + /net/NetworkStackOverview + /net/HowTo-Synchronize_with_NetBSD + /packages/README + /servers/app_server/toc + /servers/registrar/Protocols + /kernel/device_manager_introduction + /kernel/obsolete_pnp_manager + /kernel/vm/swap_file_support + /kernel/arch/long_double + /kernel/arch/arm/overview + /kernel/arch/m68k/overview + /kernel/arch/ppc/overview + /kernel/arch/sparc/overview + /kernel/fs/node_monitoring + /file_systems/overview + /partitioning_systems/sun + /drivers/disk/ioctls + /drivers/intel_extreme/generations + /busses/agp_gart/ReadMe + /busses/bluetooth/overview + /busses/sdhci/sdhci_mmc_driver + /busses/usb/USB_stack_design + /kernel/boot/boot_process_specs.rst + /kernel/boot/Debugging_Bootloaders_GEF + /kernel/pci_serial_debug + diff --git a/docs/develop/kernel/arch/arm/allwinner_a10.md b/docs/develop/kernel/arch/arm/allwinner_a10.md deleted file mode 100644 index 7c6f8e8c86..0000000000 --- a/docs/develop/kernel/arch/arm/allwinner_a10.md +++ /dev/null @@ -1,84 +0,0 @@ -# Allwinner A10 -* http://linux-sunxi.org - -# Hardware Information - -The A10 is a system-on chip. There are many devices based on it, for example -the CubieBoard and the Rikomagic mk802 (versions I and II). - -* ARMv7 Architecture (Cortex-A8) -* Mali 400MP GPU -* CedarX VPU -* SD Card Storage -* 1GB RAM (DDR) -* 4GB NAND Flash -* Video Outputs - * HDMI Video Output -* Ethernet -* USB - -# Setting up the Haiku SD card - -Not so fun layout here. The A10 boot ROM reads raw blocks from the SD card -(MBR style), so the bootloader can't just be dropped in a FAT32 partition. - -* 8KB partition table -* 24KB SPL loader -* 512KB u-boot -* 128KB u-boot environment variables -* 352KB unused -* partition 1 -- FAT32 or ext2 (anything u-boot can read is fine) -* partition 2 -- BeFS, Haiku filesystem, type 'eb' - -Note this layout can be a bit different depending on the u-boot version used, -some versions will store the environment in uEnv.txt in the FAT32 partition -instead. Since everything is loaded from the SD Card, we are free to customize -the u-boot or even remove it and get haiku_loader booting directly. - -## Boot Partition - -### Required Files - -* haiku_loader: Haiku Loader -* haiku-floppyboot.tgz: Compressed image with Haiku kernel - -# Booting - -1. SOC load SPL -2. SPL loads u-boot -2. u-boot loads and run the kernel - -SPL is a small binary (24K) loaded from a fixed location on the SD card. It -does minimal hardware initializations, then loads u-boot, also from the SD -card. From there on things go as usual. - -In the long term, we can make haiku_loader be an SPL executable on this -platform, if it fits the 24K size limit, or have a custom stage1 that loads it. -For now, u-boot can be an useful debugging tool. - -## Script.bin - -In order to work on different devices (RAM timings, PIO configs, ...), the -Linux kernels for Allwinner chips use a "script.bin" file. This is loaded to -RAM at a fixed address by u-boot, then the Kernel parses it and uses it to -configure the hardware (similar to FDT). - -We should probably NOT use this, and convert the script.bin file to an FDT -instead. The format is known and there are tools to convert the binary file -to an editable text version and back (bin2fex and fex2bin). - -This FEX stuff isn't merged in mainline Linux, and lives on as Allwinner -patches. The mainline Linux kernel has some A10 support, rewritten to use -FDT. We may use the FDT files from there for the most common boards. - -# Emulation support - -qemu 1.0 has a Cubieoard target which emulates this chip. - -# Useful links - -Arch Linux instructions on creating a bootable SD card (partition layout, etc) -http://archlinuxarm.org/platforms/armv7/allwinner/cubieboard#qt-platform_tabs-ui-tabs2 - -Linux SunXi: mainline Linux support for the Allwinner chips. Lots of docs on the hardware. -http://linux-sunxi.org/ diff --git a/docs/develop/kernel/arch/arm/allwinner_a10.rst b/docs/develop/kernel/arch/arm/allwinner_a10.rst new file mode 100644 index 0000000000..520fe034fe --- /dev/null +++ b/docs/develop/kernel/arch/arm/allwinner_a10.rst @@ -0,0 +1,99 @@ +Allwinner A10 hardware notes +############################ + +- http://linux-sunxi.org + +Hardware Information +==================== + +The A10 is a system-on chip. There are many devices based on it, for +example the CubieBoard and the Rikomagic mk802 (versions I and II). + +- ARMv7 Architecture (Cortex-A8) +- Mali 400MP GPU +- CedarX VPU +- SD Card Storage +- 1GB RAM (DDR) +- 4GB NAND Flash +- Video Outputs + + - HDMI Video Output + +- Ethernet +- USB + +Setting up the Haiku SD card +============================ + +Not so fun layout here. The A10 boot ROM reads raw blocks from the SD +card (MBR style), so the bootloader can’t just be dropped in a FAT32 +partition. + +- 8KB partition table +- 24KB SPL loader +- 512KB u-boot +- 128KB u-boot environment variables +- 352KB unused +- partition 1 – FAT32 or ext2 (anything u-boot can read is fine) +- partition 2 – BeFS, Haiku filesystem, type ‘eb’ + +Note this layout can be a bit different depending on the u-boot version +used, some versions will store the environment in uEnv.txt in the FAT32 +partition instead. Since everything is loaded from the SD Card, we are +free to customize the u-boot or even remove it and get haiku_loader +booting directly. + +Boot Partition +-------------- + +Required Files +~~~~~~~~~~~~~~ + +- haiku_loader: Haiku Loader +- haiku-floppyboot.tgz: Compressed image with Haiku kernel + +Booting +======= + +1. SOC load SPL +2. SPL loads u-boot +3. u-boot loads and run the kernel + +SPL is a small binary (24K) loaded from a fixed location on the SD card. +It does minimal hardware initializations, then loads u-boot, also from +the SD card. From there on things go as usual. + +In the long term, we can make haiku_loader be an SPL executable on this +platform, if it fits the 24K size limit, or have a custom stage1 that +loads it. For now, u-boot can be an useful debugging tool. + +Script.bin +---------- + +In order to work on different devices (RAM timings, PIO configs, …), the +Linux kernels for Allwinner chips use a “script.bin” file. This is +loaded to RAM at a fixed address by u-boot, then the Kernel parses it +and uses it to configure the hardware (similar to FDT). + +We should probably NOT use this, and convert the script.bin file to an +FDT instead. The format is known and there are tools to convert the +binary file to an editable text version and back (bin2fex and fex2bin). + +This FEX stuff isn’t merged in mainline Linux, and lives on as Allwinner +patches. The mainline Linux kernel has some A10 support, rewritten to +use FDT. We may use the FDT files from there for the most common boards. + +Emulation support +================= + +qemu 1.0 has a Cubieoard target which emulates this chip. + +Useful links +============ + +Arch Linux instructions on creating a bootable SD card (partition +layout, etc) +http://archlinuxarm.org/platforms/armv7/allwinner/cubieboard#qt-platform_tabs-ui-tabs2 + +Linux SunXi: mainline Linux support for the Allwinner chips. Lots of +docs on the hardware. http://linux-sunxi.org/ diff --git a/docs/develop/kernel/arch/arm/beagle.md b/docs/develop/kernel/arch/arm/beagle.md deleted file mode 100644 index 2d662e73d9..0000000000 --- a/docs/develop/kernel/arch/arm/beagle.md +++ /dev/null @@ -1,60 +0,0 @@ -# BeagleBone Black -* http://beagleboard.org -* TODO: This is a WIP - -# Hardware information (Rev A5A) - -* ARMv7 Architecture -* Sitara AM3359AZCZ100 Cortex-A8 CPU @ 1 Ghz -* PowerVR SGX530 3D GPU -* eMMC Onboard Storage 2GB (MMC1) -* SD Card Storage (MMC0) -* 512 MB DDR3L RAM -* Video Outputs - * HDMI Video Output (with audio) -* SMSC LAN8710A Ethernet - -# Setting up the Haiku SD card - -The BeagleBone Black supports booting from an microSD card while the boot switch is pressed at power on. A MBR file system layout is normally used as seen below. Partition 1 is all that is required to boot an OS. - -* partition 1 -- FAT32, bootable flag, type 'c' -* partition 2 -- BeFS, Haiku filesystem, type 'eb' - -## Boot Partition - -### Required files - -* MLO -* u-boot.img: u-Boot image -* uEnv.txt: u-Boot Environment settings - -### Optional files - -* ID.txt: Unknown - -# Compiling - -* Create your work directory `mkdir generated.beagle; cd generated.beagle` -* Build an ARM toolchain using `../configure --build-cross-tools arm ../../buildtools --target-board beagle` -* TODO - -# Booting - -1. If the boot switch is not depressed: - MMC1, MMC0, UART0, USB0 -2. If the boot switch is depressed: - SPI0, MMC0, USB0, UART0 - -# Emulation - -The Linaro Fork of QEmu has beagle board (and other OMAP3) support. -https://launchpad.net/qemu-linaro - -It seems you get this as the default QEmu install on some, but not all, Ubuntu -versions. For other distros (or Haiku), you'll have to compile it yourself. - -# Additional information - -* [CircutCo WikiPage](http://circuitco.com/support/index.php?title=BeagleBoneBlack) -* [BeagleBone Black A5A SRM](https://github.com/CircuitCo/BeagleBone-Black/blob/master/BBB_SRM.pdf?raw=true) diff --git a/docs/develop/kernel/arch/arm/beagle.rst b/docs/develop/kernel/arch/arm/beagle.rst new file mode 100644 index 0000000000..d990b92c0d --- /dev/null +++ b/docs/develop/kernel/arch/arm/beagle.rst @@ -0,0 +1,78 @@ +BeagleBone Black +================ + +- http://beagleboard.org +- TODO: This is a WIP + +Hardware information (Rev A5A) +============================== + +- ARMv7 Architecture +- Sitara AM3359AZCZ100 Cortex-A8 CPU @ 1 Ghz +- PowerVR SGX530 3D GPU +- eMMC Onboard Storage 2GB (MMC1) +- SD Card Storage (MMC0) +- 512 MB DDR3L RAM +- Video Outputs + + - HDMI Video Output (with audio) + +- SMSC LAN8710A Ethernet + +Setting up the Haiku SD card +============================ + +The BeagleBone Black supports booting from an microSD card while the +boot switch is pressed at power on. A MBR file system layout is normally +used as seen below. Partition 1 is all that is required to boot an OS. + +- partition 1 – FAT32, bootable flag, type ‘c’ +- partition 2 – BeFS, Haiku filesystem, type ‘eb’ + +Boot Partition +-------------- + +Required files +~~~~~~~~~~~~~~ + +- MLO +- u-boot.img: u-Boot image +- uEnv.txt: u-Boot Environment settings + +Optional files +~~~~~~~~~~~~~~ + +- ID.txt: Unknown + +Compiling +========= + +- Create your work directory + ``mkdir generated.beagle; cd generated.beagle`` +- Build an ARM toolchain using + ``../configure --build-cross-tools arm ../../buildtools --target-board beagle`` +- TODO + +Booting +======= + +1. If the boot switch is not depressed: MMC1, MMC0, UART0, USB0 +2. If the boot switch is depressed: SPI0, MMC0, USB0, UART0 + +Emulation +========= + +The Linaro Fork of QEmu has beagle board (and other OMAP3) support. +https://launchpad.net/qemu-linaro + +It seems you get this as the default QEmu install on some, but not all, +Ubuntu versions. For other distros (or Haiku), you’ll have to compile it +yourself. + +Additional information +====================== + +- `CircutCo + WikiPage `__ +- `BeagleBone Black A5A + SRM `__ diff --git a/docs/develop/kernel/arch/arm/efikamx.rst b/docs/develop/kernel/arch/arm/efikamx.rst new file mode 100644 index 0000000000..d8b1af451a --- /dev/null +++ b/docs/develop/kernel/arch/arm/efikamx.rst @@ -0,0 +1,8 @@ +Efika MX +======== + +FDT +--- + +* http://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/imx51x.dtsi?revision=248557&view=markup +* http://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/efikamx.dts?revision=248557&view=markup diff --git a/docs/develop/kernel/arch/arm/efikamx.txt b/docs/develop/kernel/arch/arm/efikamx.txt deleted file mode 100644 index 11edfc0072..0000000000 --- a/docs/develop/kernel/arch/arm/efikamx.txt +++ /dev/null @@ -1,5 +0,0 @@ -Notes on Efika MX port -*- org -*- - -* FDT -http://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/imx51x.dtsi?revision=248557&view=markup -http://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/efikamx.dts?revision=248557&view=markup diff --git a/docs/develop/kernel/arch/arm/ipaq.rst b/docs/develop/kernel/arch/arm/ipaq.rst new file mode 100644 index 0000000000..35a057b358 --- /dev/null +++ b/docs/develop/kernel/arch/arm/ipaq.rst @@ -0,0 +1,20 @@ +iPaq +==== + +* http://www.NetBSD.org/ports/hpcarm/ +* http://www.ibm.com/developerworks/linux/library/l-ipaq/index.html +* http://mstempin.free.fr/linux-ipaq/html_nochunks/Linux-iPAQ-HOWTO-1.1.html#BACKING-UP-BOOTLOADER +* http://www.eecs.umich.edu/~panalyzer/ +* http://www.eecs.umich.edu/~panalyzer/sim-ipaq/sim_ipaq_readme.html +* http://blogs.unbolt.net/index.php/brinley/2007/08/04/exploring_hp_ipaq_6515e_bootloader +* http://gert-menke.de/jtag-howto/ +* http://ecos.sourceware.org/docs-3.0/redboot-guide/ipaq.html +* http://www.balloonboard.org/balloon/balloon3/distro/test-v0.2/sources/balloonsvn/bootldr295/doc/install-via-osloader.html + +RS232 +----- + +* http://www.kronosrobotics.com/Zeus/IPAQcon.pdf +* http://bevhoward.com/serial.htm +* http://www.mail-archive.com/newbie@linux-mandrake.com/msg132363.html +* http://web.archive.org/web/20050408063754/http://www.handhelds.org/pipermail/ipaq/2000-August/000061.html diff --git a/docs/develop/kernel/arch/arm/ipaq.txt b/docs/develop/kernel/arch/arm/ipaq.txt deleted file mode 100644 index 75dc1aabd0..0000000000 --- a/docs/develop/kernel/arch/arm/ipaq.txt +++ /dev/null @@ -1,15 +0,0 @@ -http://www.NetBSD.org/ports/hpcarm/ -http://www.ibm.com/developerworks/linux/library/l-ipaq/index.html -http://mstempin.free.fr/linux-ipaq/html_nochunks/Linux-iPAQ-HOWTO-1.1.html#BACKING-UP-BOOTLOADER -http://www.eecs.umich.edu/~panalyzer/ -http://www.eecs.umich.edu/~panalyzer/sim-ipaq/sim_ipaq_readme.html -http://blogs.unbolt.net/index.php/brinley/2007/08/04/exploring_hp_ipaq_6515e_bootloader -http://gert-menke.de/jtag-howto/ -http://ecos.sourceware.org/docs-3.0/redboot-guide/ipaq.html -http://www.balloonboard.org/balloon/balloon3/distro/test-v0.2/sources/balloonsvn/bootldr295/doc/install-via-osloader.html - -RS232: -http://www.kronosrobotics.com/Zeus/IPAQcon.pdf -http://bevhoward.com/serial.htm -http://www.mail-archive.com/newbie@linux-mandrake.com/msg132363.html -http://web.archive.org/web/20050408063754/http://www.handhelds.org/pipermail/ipaq/2000-August/000061.html diff --git a/docs/develop/kernel/arch/arm/limitations.txt b/docs/develop/kernel/arch/arm/limitations.txt deleted file mode 100644 index 7d080c831d..0000000000 --- a/docs/develop/kernel/arch/arm/limitations.txt +++ /dev/null @@ -1,2 +0,0 @@ -* Does not support < ARMv5 -* Requires support for high vectors diff --git a/docs/develop/kernel/arch/arm/overview.rst b/docs/develop/kernel/arch/arm/overview.rst new file mode 100644 index 0000000000..3e83cd8a07 --- /dev/null +++ b/docs/develop/kernel/arch/arm/overview.rst @@ -0,0 +1,170 @@ +The ARM port +============ + +Note: there are in fact two ports to the ARM architecture, one for 32-bit, and one for 64-bit +systems. They don't have a lot of shared code as the two architectures are very different from +one another. + +ARM devices are very popular, and especially since the release of the Raspberry Pi, people have +been requesting that Haiku is ported to it. Unfortunately, limitations in the architecture itself +and the wide diversity of hardware have made this task more complicated, and progress has been +slow. For example, ARM has no standard like the PC is for x86, so concepts as basic as a system +timer, a bootloader, or a serial port, are different from one machine to another. The situation +has improved with the later generations, as more things were integrated in the CPU core, and u-boot +is now well established as the main bootloader for ARM devices. + +Limitations +----------- + +There will be no support for hardware using architectures older than ARMv5. There will probably be +no support for architectures before ARMv7, which require more work on the compiler and OS, for +example due to lack of atomic instructions. + +Support for high vectors (interrupt vectors stored at the end of the memory space) is required. + +Information about specific hardware targets +------------------------------------------- + +Over the years, various possible ARM targets have been considered for the Haiku ARM port. +We have accumulated some notes and documentation on some of them. + +.. toctree:: + + /kernel/arch/arm/allwinner_a10 + /kernel/arch/arm/beagle + /kernel/arch/arm/efikamx + /kernel/arch/arm/ipaq + /kernel/arch/arm/rpi1 + /kernel/arch/arm/rpi2 + +TODO list +--------- + +Fix pre-ARMv7 support +********************* + +The ARM instruction set has evolved a lot over time, and we have to make a choice: use the oldest +versions of the instruction set gives us maximal compatibility, but at the cost of a large +performance hit on newer systems, as well as extra code being needed in the OS to compensate for +the missing instructions. + +Currently the cross-tools are compiled to default to ARMv7, Cortex-A8, and +hardware floating point. This works around the missing atomic support, see +below. This should be done by setting the -mcpu,-march and -mfloat-abi +switches at build time, however, they aren't passed on to haikuporter +during the bootstrap build, leading to the ports failing to find the +gcc atomic ops again. + +It seems this create other problems, mainly because the UEFI environment for ARM is not supposed to +handle floating point registers. So, the softfloat ABI should be used there instead. To be able +to build both "soft float" and "hard float" code, we need multilib support, see below. + +Determine how to handle atomic functions on ARM +*********************************************** + +GCC inlines are not supported, since the instructionset is ill-equiped for +this on older (pre-ARMv7) architectures. We possibly have to do something +similar to the linux kernel helper functions for this.... + +On ARMv7 and later, this is not an issue. Not sure about ARMv6, we may get +it going there. ARMv5 definitely needs us to write some code, but is it +worth the trouble? + +Fix multilib support +******************** + +ARM-targetting versions of gcc are usually built with multilib support, to +allow targetting architectures with or without FPU, and using either ARM +or Thumb instructions. This bascally means a different libgcc and libstdc++ +are built for each combination. + +The cross-tools can be built with multilib support. However, we do some +tricks to get a separate libgcc and libstdc++ for the kernel (without C++11 +threads support, as that would not build in the kernel). Building this lib +is not done in a multilib-aware way, so you get one only for the default +arch/cpu/abi the compiler is targetting. This is good enough, as long as that +arch is the one we want to use for the kernel... + +Later on, the bootstrap build of the native gcc compiler will fail, because +it tries to build its multilib library set by linking against the different +versions of libroot (with and without fpu, etc). We only build one libroot, +so this also fails. + +The current version of the x86_64 compiler appears is using multilib (to build for both 32 and 64 +bit targets) and is working fine, so it's possible that most of the issues in this area have +already been fixed. + +Figure out how to get page flags (modified/accessed) and implement it +********************************************************************* + +use unmapped/read-only mappings to trigger soft faults for tracking used/modified flags for ARMv5 and ARMv6 + +Fix serial port mapping +*********************** + +Currently kernel uses the haiku_loader identity +mapping for it, but this lives in user virtual address space... +(Need to not use identity mapping in haiku_loader but just +map_physical_memory() there too so it can be handed over without issues). + +Seperate ARM architecture/System-On-Chip IP code +************************************************ + +The early work on the ARM port resulted in lots of board specific code being added to early stages +of the kernel. Ideally, this would not be needed, the kernel would manage to initialize itself +mostly in a platform independant way, and get the needed information from the FDT passed by the +bootloader. The difficulty is that on older ARM versions, even the interrupt controller and timers +can be different on each machine. + +KDL disasm module +***************** + +Currently it is not possible to disassemble code in the kernel debugger. + +The `NetBSD disassembler `_ could be ported and used for this. + +Add KDL hangman to the boot image +********************************* + +for more enjoyment during porting.... + +Userland +******** + +Even if KDL hangman is fun, users will want to run real applications someday. + +Bootloader TODOs +**************** + +- Better handling of memory ranges. Currently no checks are done, and + memory is assumed to be a single contiguous range, and the "input" + ranges for mmu_init are setup, but never considered. +- Allocate the pagetable range using mmu_allocate() instead of identity + mapping it. That way, there's a bit more flexibility in where to place + it both physically and virtually. This will need a minor change on the + kernel side too (in the early pagetable allocator). + +Other resources +--------------- + +About flatenned device trees +**************************** + +* http://www.denx.de/wiki/U-Boot/UBootFdtInfo +* http://wiki.freebsd.org/FlattenedDeviceTree#Supporting_library_.28libfdt.29 +* http://elinux.org/images/4/4e/Glikely-powerpc-porting-guide.pdf +* http://ols.fedoraproject.org/OLS/Reprints-2008/likely2-reprint.pdf +* http://www.bsdcan.org/2010/schedule/events/171.en.html +* http://www.devicetree.org/ (unofficial bindings) +* http://www.devicetree.org/Device_Tree_Usage +* http://elinux.org/Device_Trees + +About openfirmware +****************** + +http://www.openfirmware.info/Bindings + +About floating point numbers handling on ARM +******************************************** + +https://wiki.debian.org/ArmHardFloatPort/VfpComparison diff --git a/docs/develop/kernel/arch/arm/rpi1.md b/docs/develop/kernel/arch/arm/rpi1.md deleted file mode 100644 index 171f5ab195..0000000000 --- a/docs/develop/kernel/arch/arm/rpi1.md +++ /dev/null @@ -1,74 +0,0 @@ -# Raspberry Pi -* http://raspberrypi.org - -# Hardware Information - -* ARMv6 Architecture -* Broadcom BCM2835 (SoC) - * Includes ARM1176JZF-S CPU @ 700 MHz - * Includes VideoCore IV GPU -* SD Card Storage -* 256 or 512 MB RAM (depending on revision) -* Video Outputs - * HDMI Video Output - * Composite Video Output -* Ethernet - -# Setting up the Haiku SD card - -The Raspberry Pi SD card generally uses the MBR file system layout below. Partition 1 is all that is required to boot an OS. - -* partition 1 -- FAT32, bootable flag, type 'c' -* partition 2 -- BeFS, Haiku filesystem, type 'eb' - -## Boot Partition - -### Required Files - -* bootcode.bin : 2nd stage bootloader -* start.elf: The GPU binary firmware image -* config.txt: A configuration file read by the Pi to start u-boot.bin -* u-boot.bin: u-boot loader for the Pi 2 -* bcm2835-rpi-b.dtb: FDT binary for the Raspberry Pi 2 -* haiku_loader_linux.ub: Haiku Loader -* haiku-floppyboot.tgz.ub: Compressed initial ram image with Haiku kernel - -### Optional Files - -* vlls directory: Additional GPU code, e.g. extra codecs. -* uEnv.txt: u-boot configuration script to automate boot. - -# Compiling - -* Create your ARM work directory `mkdir generated.arm; cd generated.arm` -* Build an ARM toolchain using `../configure --build-cross-tools arm ../../buildtools --target-board=rpi1` -* Build our loader using `jam -q haiku_loader_linux.ub` -* Build our initial ram disk using `jam -q haiku-floppyboot.tgz.ub` - -# Booting - -1. SOC finds bootcode.bin -2. bootcode.bin runs start.elf -3. start.elf reads config.txt and start u-boot -4. u-boot.bin starts the Haiku loader -5. Haiku loader boots Haiku kernel - -## config.txt Options - - kernel=u-boot.bin - -## u-boot startup - -These will be condensed and automated long-term via uEnv.txt :-) - -* `fatload mmc 0 ${fdt_addr_r} bcm2835-rpi-b.dtb` -* `fdt addr ${fdt_addr_r}` -* `fatload mmc 0 ${ramdisk_addr_r} haiku-floppyboot.tgz.ub` -* `fatload mmc 0 ${kernel_addr_r} haiku_loader_linux.ub` -* `bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}` - -# Additional Information - -* [Latest Raspberry Pi firmware](http://github.com/raspberrypi/firmware/tree/master/boot) -* [config.txt options](http://www.elinux.org/RPiconfig) - diff --git a/docs/develop/kernel/arch/arm/rpi1.rst b/docs/develop/kernel/arch/arm/rpi1.rst new file mode 100644 index 0000000000..7626ccc393 --- /dev/null +++ b/docs/develop/kernel/arch/arm/rpi1.rst @@ -0,0 +1,96 @@ +Raspberry Pi +############ + +- http://raspberrypi.org + +Hardware Information +==================== + +- ARMv6 Architecture +- Broadcom BCM2835 (SoC) + + - Includes ARM1176JZF-S CPU @ 700 MHz + - Includes VideoCore IV GPU + +- SD Card Storage +- 256 or 512 MB RAM (depending on revision) +- Video Outputs + + - HDMI Video Output + - Composite Video Output + +- Ethernet + +Setting up the Haiku SD card +============================ + +The Raspberry Pi SD card generally uses the MBR file system layout +below. Partition 1 is all that is required to boot an OS. + +- partition 1 – FAT32, bootable flag, type ‘c’ +- partition 2 – BeFS, Haiku filesystem, type ‘eb’ + +Boot Partition +-------------- + +Required Files +~~~~~~~~~~~~~~ + +- bootcode.bin : 2nd stage bootloader +- start.elf: The GPU binary firmware image +- config.txt: A configuration file read by the Pi to start u-boot.bin +- u-boot.bin: u-boot loader for the Pi 2 +- bcm2835-rpi-b.dtb: FDT binary for the Raspberry Pi 2 +- haiku_loader_linux.ub: Haiku Loader +- haiku-floppyboot.tgz.ub: Compressed initial ram image with Haiku + kernel + +Optional Files +~~~~~~~~~~~~~~ + +- vlls directory: Additional GPU code, e.g. extra codecs. +- uEnv.txt: u-boot configuration script to automate boot. + +Compiling +========= + +- Create your ARM work directory + ``mkdir generated.arm; cd generated.arm`` +- Build an ARM toolchain using + ``../configure --build-cross-tools arm ../../buildtools --target-board=rpi1`` +- Build our loader using ``jam -q haiku_loader_linux.ub`` +- Build our initial ram disk using ``jam -q haiku-floppyboot.tgz.ub`` + +Booting +======= + +1. SOC finds bootcode.bin +2. bootcode.bin runs start.elf +3. start.elf reads config.txt and start u-boot +4. u-boot.bin starts the Haiku loader +5. Haiku loader boots Haiku kernel + +config.txt Options +------------------ + +:: + + kernel=u-boot.bin + +u-boot startup +-------------- + +These will be condensed and automated long-term via uEnv.txt :-) + +- ``fatload mmc 0 ${fdt_addr_r} bcm2835-rpi-b.dtb`` +- ``fdt addr ${fdt_addr_r}`` +- ``fatload mmc 0 ${ramdisk_addr_r} haiku-floppyboot.tgz.ub`` +- ``fatload mmc 0 ${kernel_addr_r} haiku_loader_linux.ub`` +- ``bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}`` + +Additional Information +====================== + +- `Latest Raspberry Pi + firmware `__ +- `config.txt options `__ diff --git a/docs/develop/kernel/arch/arm/rpi2.md b/docs/develop/kernel/arch/arm/rpi2.md deleted file mode 100644 index df19f3d24d..0000000000 --- a/docs/develop/kernel/arch/arm/rpi2.md +++ /dev/null @@ -1,74 +0,0 @@ -# Raspberry Pi 2 -* http://raspberrypi.org - -# Hardware Information - -* ARMv7 Architecture -* Broadcom BCM2836 (SoC) - * Includes Quad ARM1176JZF-S CPU @ 900 MHz - * Includes VideoCore IV GPU -* SD Card Storage -* 1 GB RAM -* Video Outputs - * HDMI Video Output - * Composite Video Output -* Ethernet - -# Setting up the Haiku SD card - -The Raspberry Pi SD card generally uses the MBR file system layout below. Partition 1 is all that is required to boot an OS. - -* partition 1 -- FAT32, bootable flag, type 'c' -* partition 2 -- BeFS, Haiku filesystem, type 'eb' - -## Boot Partition - -### Required Files - -* bootcode.bin : 2nd stage bootloader -* start.elf: The GPU binary firmware image -* config.txt: A configuration file read by the Pi to start u-boot.bin -* u-boot.bin: u-boot loader for the Pi 2 -* bcm2836-rpi-2-b.dtb: FDT binary for the Raspberry Pi 2 -* haiku_loader_linux.ub: Haiku Loader -* haiku-floppyboot.tgz.ub: Compressed initial ram image with Haiku kernel - -### Optional Files - -* vlls directory: Additional GPU code, e.g. extra codecs. -* uEnv.txt: u-boot configuration script to automate boot. - -# Compiling - -* Create your ARM work directory `mkdir generated.arm; cd generated.arm` -* Build an ARM toolchain using `../configure --build-cross-tools arm ../../buildtools --target-board=rpi2` -* Build our loader using `jam -q haiku_loader_linux.ub` -* Build our initial ram disk using `jam -q haiku-floppyboot.tgz.ub` - -# Booting - -1. SOC finds bootcode.bin -2. bootcode.bin runs start.elf -3. start.elf reads config.txt and start u-boot -4. u-boot.bin starts the Haiku loader -5. Haiku loader boots Haiku kernel - -## config.txt Options - - kernel=u-boot.bin - -## u-boot startup - -These will be condensed and automated long-term via uEnv.txt :-) - -* `fatload mmc 0 ${fdt_addr_r} bcm2836-rpi-2-b.dtb` -* `fdt addr ${fdt_addr_r}` -* `fatload mmc 0 ${ramdisk_addr_r} haiku-floppyboot.tgz.ub` -* `fatload mmc 0 ${kernel_addr_r} haiku_loader_linux.ub` -* `bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}` - -# Additional Information - -* [Latest Raspberry Pi firmware](http://github.com/raspberrypi/firmware/tree/master/boot) -* [config.txt options](http://www.elinux.org/RPiconfig) - diff --git a/docs/develop/kernel/arch/arm/rpi2.rst b/docs/develop/kernel/arch/arm/rpi2.rst new file mode 100644 index 0000000000..a7a1762e02 --- /dev/null +++ b/docs/develop/kernel/arch/arm/rpi2.rst @@ -0,0 +1,96 @@ +Raspberry Pi 2 +############## + +- http://raspberrypi.org + +Hardware Information +==================== + +- ARMv7 Architecture +- Broadcom BCM2836 (SoC) + + - Includes Quad ARM1176JZF-S CPU @ 900 MHz + - Includes VideoCore IV GPU + +- SD Card Storage +- 1 GB RAM +- Video Outputs + + - HDMI Video Output + - Composite Video Output + +- Ethernet + +Setting up the Haiku SD card +============================ + +The Raspberry Pi SD card generally uses the MBR file system layout +below. Partition 1 is all that is required to boot an OS. + +- partition 1 – FAT32, bootable flag, type ‘c’ +- partition 2 – BeFS, Haiku filesystem, type ‘eb’ + +Boot Partition +-------------- + +Required Files +~~~~~~~~~~~~~~ + +- bootcode.bin : 2nd stage bootloader +- start.elf: The GPU binary firmware image +- config.txt: A configuration file read by the Pi to start u-boot.bin +- u-boot.bin: u-boot loader for the Pi 2 +- bcm2836-rpi-2-b.dtb: FDT binary for the Raspberry Pi 2 +- haiku_loader_linux.ub: Haiku Loader +- haiku-floppyboot.tgz.ub: Compressed initial ram image with Haiku + kernel + +Optional Files +~~~~~~~~~~~~~~ + +- vlls directory: Additional GPU code, e.g. extra codecs. +- uEnv.txt: u-boot configuration script to automate boot. + +Compiling +========= + +- Create your ARM work directory + ``mkdir generated.arm; cd generated.arm`` +- Build an ARM toolchain using + ``../configure --build-cross-tools arm ../../buildtools --target-board=rpi2`` +- Build our loader using ``jam -q haiku_loader_linux.ub`` +- Build our initial ram disk using ``jam -q haiku-floppyboot.tgz.ub`` + +Booting +======= + +1. SOC finds bootcode.bin +2. bootcode.bin runs start.elf +3. start.elf reads config.txt and start u-boot +4. u-boot.bin starts the Haiku loader +5. Haiku loader boots Haiku kernel + +config.txt Options +------------------ + +:: + + kernel=u-boot.bin + +u-boot startup +-------------- + +These will be condensed and automated long-term via uEnv.txt :-) + +- ``fatload mmc 0 ${fdt_addr_r} bcm2836-rpi-2-b.dtb`` +- ``fdt addr ${fdt_addr_r}`` +- ``fatload mmc 0 ${ramdisk_addr_r} haiku-floppyboot.tgz.ub`` +- ``fatload mmc 0 ${kernel_addr_r} haiku_loader_linux.ub`` +- ``bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}`` + +Additional Information +====================== + +- `Latest Raspberry Pi + firmware `__ +- `config.txt options `__ diff --git a/docs/develop/kernel/arch/arm/todo.txt b/docs/develop/kernel/arch/arm/todo.txt deleted file mode 100644 index 31101a33f1..0000000000 --- a/docs/develop/kernel/arch/arm/todo.txt +++ /dev/null @@ -1,64 +0,0 @@ -* Fix pre-ARMv7 support - Currently the cross-tools are compiled to default to ARMv7, Cortex-A8, and - hardware floating point. This works around the missing atomic support, see - below. This should be done by setting the -mcpu,-march and -mfloat-abi - switches at build time, however, they aren't passed on to haikuporter - during the bootstrap build, leading to the ports failing to find the - gcc atomic ops again. - -* Determine how to handle atomic functions on ARM. - GCC inlines are not supported, since the instructionset is ill-equiped for - this on older (pre-ARMv7) architectures. We possibly have to do something - similar to the linux kernel helper functions for this.... - On ARMv7 and later, this is not an issue. Not sure about ARMv6, we may get - it going there. ARMv5 definitely needs us to write some code, but is it - worth the trouble? - -* Fix multilib support - ARM-targetting versions of gcc are usually built with multilib support, to - allow targetting architectures with or without FPU, and using either ARM - or Thumb instructions. This bascally means a different libgcc and libstdc++ - are built for each combination. - The cross-tools can be built with multilib support. However, we do some - tricks to get a separate libgcc and libstdc++ for the kernel (without C++11 - threads support, as that would not build in the kernel). Building this lib - is not done in a multilib-aware way, so you get one only for the default - arch/cpu/abi the compiler is targetting. This is good enough, as long as that - arch is the one we want to use for the kernel... - Later on, the bootstrap build of the native gcc compiler will fail, because - it tries to build its multilib library set by linking against the different - versions of libroot (with and without fpu, etc). We only build one libroot, - so this also fails. - -* Figure out how to get page flags (modified/accessed) and implement it ;) - use unmapped/read-only mappings to trigger soft faults - for tracking used/modified flags for ARMv5 and ARMv6 - -* Fix serial port mapping. Currently kernel uses the haiku_loader identity - mapping for it, but this lives in user virtual address space... - (Need to not use identity mapping in haiku_loader but just - map_physical_memory() there too so it can be handed over without issues). - -* Seperate ARM architecture/System-On-Chip IP code. Needed very early on - (Interrupt Controller, Timer IP block). Should use FDT for this too. - -* Use FDT to remove all the seperate board definitions in the build. Use a - "minimal ARM architecture version" as the compile flag for ARM support. - This to be able to optimize a kernel build for a specific SoC (or family). - -* KDL disasm module. - cf. - http://fxr.watson.org/fxr/source/arch/arm/arm/disassem.c?v=NETBSD - -* Add KDL hangman to the boot floppy image for more enjoyment during porting.... - -* Userland........... - -* Bootloader TODOs: - - Better handling of memory ranges. Currently no checks are done, and - memory is assumed to be a single contiguous range, and the "input" - ranges for mmu_init are setup, but never considered. - - Allocate the pagetable range using mmu_allocate() instead of identity - mapping it. That way, there's a bit more flexibility in where to place - it both physically and virtually. This will need a minor change on the - kernel side too (in the early pagetable allocator). diff --git a/docs/develop/kernel/arch/arm/urls.txt b/docs/develop/kernel/arch/arm/urls.txt deleted file mode 100644 index 77deb4123c..0000000000 --- a/docs/develop/kernel/arch/arm/urls.txt +++ /dev/null @@ -1,13 +0,0 @@ -* FDT -http://www.denx.de/wiki/U-Boot/UBootFdtInfo -http://wiki.freebsd.org/FlattenedDeviceTree#Supporting_library_.28libfdt.29 -http://elinux.org/images/4/4e/Glikely-powerpc-porting-guide.pdf -http://ols.fedoraproject.org/OLS/Reprints-2008/likely2-reprint.pdf -http://www.bsdcan.org/2010/schedule/events/171.en.html -http://www.devicetree.org/ (unofficial bindings) -http://www.devicetree.org/Device_Tree_Usage -http://elinux.org/Device_Trees -* OF -http://www.openfirmware.info/Bindings -* Floating Point; VFP -https://wiki.debian.org/ArmHardFloatPort/VfpComparison diff --git a/docs/develop/kernel/arch/long double.md b/docs/develop/kernel/arch/long double.md deleted file mode 100644 index 46ea470a61..0000000000 --- a/docs/develop/kernel/arch/long double.md +++ /dev/null @@ -1,48 +0,0 @@ -Notes on long double support -============================ - -The "long double" type is different on each architecture. Depending on the -available hardware and ABI conventions, performance compromises, etc, there -may be many implementations of it. Here is a summary for our convenience. - -128-bit IEEE ------------- - -Platforms: Sparc, ARM64, RISC-V - -This is the standard long double type from IEEE754. It has 1 sign bit, -15 exponent bit, and 112 fractional part bits. It is the natural extension -of the 64bit double. - -Sparc specifies this type in their ABI but no implementation actually has -the instructions, they instead trigger a trap which would software emulate -them. However, gcc short circuits this by default and calls C library -support functions directly. - -64-bit IEEE ------------ - -Platforms: ARM - -This is the same representation as plain "double". ARM uses this for simplicity. - -80-bit ------- - -Platform: x86, x86\_64, m68k - -This intermediate format is used by x86 CPUs internally. It may end up being -faster than plain double there. It consists of a 64bit fractional part, 15 -exponent bits, and 1 sign bit. This is convenient because the fractional part -is a relatively easy to handle 64bit number. - -m68k uses a similar format, but padded to 96 bits (the extra 16 bits are unused). - -double double -------------- - -Platforms: PowerPC? - -This is also a 128bit type, but the representation is just two 64bit doubles. -The value is the sum of the two halves. This format allows faster emulation -than a "true" 128bit long double, and the precision is almost as good. diff --git a/docs/develop/kernel/arch/long_double.rst b/docs/develop/kernel/arch/long_double.rst new file mode 100644 index 0000000000..7e9719c38c --- /dev/null +++ b/docs/develop/kernel/arch/long_double.rst @@ -0,0 +1,54 @@ +Notes on long double support +============================ + +The “long double” type is different on each architecture. Depending on +the available hardware and ABI conventions, performance compromises, +etc, there may be many implementations of it. Here is a summary for our +convenience. + +128-bit IEEE +------------ + +Platforms: Sparc, ARM64, RISC-V + +This is the standard long double type from IEEE754. It has 1 sign bit, +15 exponent bit, and 112 fractional part bits. It is the natural +extension of the 64bit double. + +Sparc specifies this type in their ABI but no implementation actually +has the instructions, they instead trigger a trap which would software +emulate them. However, gcc short circuits this by default and calls C +library support functions directly. + +.. _bit-ieee-1: + +64-bit IEEE +----------- + +Platforms: ARM + +This is the same representation as plain “double”. ARM uses this for +simplicity. + +80-bit +------ + +Platform: x86, x86_64, m68k + +This intermediate format is used by x86 CPUs internally. It may end up +being faster than plain double there. It consists of a 64bit fractional +part, 15 exponent bits, and 1 sign bit. This is convenient because the +fractional part is a relatively easy to handle 64bit number. + +m68k uses a similar format, but padded to 96 bits (the extra 16 bits are +unused). + +double double +------------- + +Platforms: PowerPC? + +This is also a 128bit type, but the representation is just two 64bit +doubles. The value is the sum of the two halves. This format allows +faster emulation than a “true” 128bit long double, and the precision is +almost as good. diff --git a/docs/develop/kernel/arch/m68k/TODO b/docs/develop/kernel/arch/m68k/TODO deleted file mode 100644 index e67f5557e4..0000000000 --- a/docs/develop/kernel/arch/m68k/TODO +++ /dev/null @@ -1,3 +0,0 @@ -- optimization: remove M68KPagingStructures[*]::UpdateAllPageDirs() and just allocate all the kernel page root entries at boot and be done with it. It's not very big anyway. -- possibly other optimizations in the VM code due to not supporting SMP? - diff --git a/docs/develop/kernel/arch/m68k/amiga.rst b/docs/develop/kernel/arch/m68k/amiga.rst new file mode 100644 index 0000000000..a6394c74c3 --- /dev/null +++ b/docs/develop/kernel/arch/m68k/amiga.rst @@ -0,0 +1,4 @@ +The Amiga port +============== + +* http://wandel.ca/homepage/execdis/ diff --git a/docs/develop/kernel/arch/m68k/amiga/urls.txt b/docs/develop/kernel/arch/m68k/amiga/urls.txt deleted file mode 100644 index b11018a6b6..0000000000 --- a/docs/develop/kernel/arch/m68k/amiga/urls.txt +++ /dev/null @@ -1 +0,0 @@ -http://wandel.ca/homepage/execdis/ diff --git a/docs/develop/kernel/arch/m68k/atari.rst b/docs/develop/kernel/arch/m68k/atari.rst new file mode 100644 index 0000000000..5f8de43f0f --- /dev/null +++ b/docs/develop/kernel/arch/m68k/atari.rst @@ -0,0 +1,108 @@ +The Atari ST port +================= + +Atari ST executables +-------------------- + +From: DaFi + +The specs for Atari ST executables (was listed as requested on www.wotsit.demon.co.uk/wanted.htm)... + +applies for TOS, PRG, TTP, PRX, GTP, APP, ACC, ACX (different suffixes indicate different behavior of the program, i.e. TOS and TTP may not use the GEM GUI, while all the others may; only TTP and GTP can be called with parameters; ACC may be installed as desktop accessories; PRX and ACX mean the programs were disabled. + +file structure: + ++--------------------+---------------------------------------------------------------------------+ +| [2] WORD PRG_magic | magic value 0x601a | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRG_tsize | size of text segment | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRG_dsize | size of data segment | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRG_bsize | size of bss segment | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRG_ssize | size of symbol table | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRG_res1 | reserved | ++--------------------+---------------------------------------------------------------------------+ +| [4] LONG PRGFLAGS | bit vector that defines additional process characteristics, as follows: | +| | | +| | * **Bit 0 PF_FASTLOAD** - if set, only the BSS area is cleared, otherwise,| +| | the program's whole memory is cleared before loading | +| | * **Bit 1 PF_TTRAMLOAD** - if set, the program will be loaded into TT RAM | +| | * **Bit 2 PF_TTRAMMEM** - if set, the program will be allowed to allocate | +| | memory from TT RAM | +| | | +| | Bit 4 AND 5 as a two bit value with the following meanings: | +| | | +| | * 0 PF_PRIVATE - the processes entire memory space is considered private | +| | * 1 PF_GLOBAL - the processes memory will be r/w-allowed for others | +| | * 2 PF_SUPER - the memory will be r/w for itself and any supervisor proc | +| | * 3 PF_READ - the memory will be readable by others | ++--------------------+---------------------------------------------------------------------------+ +| [2] WORD ABSFLAG | is NON-ZERO, if the program does not need to be relocated | +| | | +| | is ZERO, if the program needs to be relocated | +| | | +| | note: since some TOS versions handle files with ABSFLAG>0 incorrectly, | +| | this value should be set to ZERO also for programs that need to be | +| | relocated, and the FIXUP_offset should be set to 0. | ++--------------------+---------------------------------------------------------------------------+ + +From there on... (should be offset 0x1c) + +[PRG_tsize] TEXT segment +[PRG_dsize] DATA segment +[PRG_ssize] Symbol table + +[4] LONG FIXUP_offset - first LONG that needs to be relocated (offset to beginning of file) + +From there on till the end of the file... + +FIXUP table, with entries as follows: + +[1] BYTE value + +with value as follows: + +- value=0 end of list +- value=1 advance 254 bytes +- value=2 to value=254 (only even values!) advance this many bytes and relocate the LONG found there. + +That's it. You made it through to EOF. + +A final note about fixing up (relocating) an executable: (pseudo-code) + +The long value FIXUP_offset tells you your start adress. Let's call it "adr". So, now, that +you have adr, read the first byte of the table. + +(*) loop + +- if it's 0, stop relocating -> you're done! +- if it's 1, add 254 to adr and read the next byte, jump back to the asterisk (*) +- if it's any other even value, add the value to your adr, then relocate the LONG at adr. + (i.e. add the adress of the LONG to its value) + +Useful resources +---------------- + +* http://toshyp.atari.org/en/index.html + +* http://www.lysator.liu.se/~celeborn/sync/atari/misc.html +* http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/F30.ZIP +* http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/FALCLIB6.ZIP +* http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/FALCREGS.ZIP + +* http://fxr.watson.org/fxr/source/include/asm-m68k/atarihw.h?v=linux-2.4.22 +* http://lxr.linux.no/linux+v2.6.27/arch/m68k/atari/config.c#L664 + +* http://www.atari-forum.com/wiki/index.php/MFP_MK68901 + +* http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/ahdi-xxboot/xxboot.ahdi.S + +AHDI args + +* http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/wdboot/wdboot.S +* http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/sdboot/sdboot.S +* http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/fdboot/fdboot.S + diff --git a/docs/develop/kernel/arch/m68k/atari/atariexe.txt b/docs/develop/kernel/arch/m68k/atari/atariexe.txt deleted file mode 100644 index 4061c2eead..0000000000 --- a/docs/develop/kernel/arch/m68k/atari/atariexe.txt +++ /dev/null @@ -1,57 +0,0 @@ -Subject: Atari ST executables -From: DaFi - -The specs for Atari ST executables (was listed as requested on www.wotsit.demon.co.uk/wanted.htm)... - -applies for TOS, PRG, TTP, PRX, GTP, APP, ACC, ACX (different suffixes indicate different behavior of the program, i.e. TOS and TTP may not use the GEM GUI, while all the others may; only TTP and GTP can be called with parameters; ACC may be installed as desktop accessories; PRX and ACX mean the programs were disabled. - -file structure: -[2] WORD PRG_magic - magic value 0x601a -[4] LONG PRG_tsize - size of text segment -[4] LONG PRG_dsize - size of data segment -[4] LONG PRG_bsize - size of bss segment -[4] LONG PRG_ssize - size of symbol table -[4] LONG PRG_res1 - reserved -[4] LONG PRGFLAGS - bit vector that defines additional process characteristics, as follows: - Bit 0 PF_FASTLOAD - if set, only the BSS area is cleared, otherwise, - the programs whole memory is cleared before loading - Bit 1 PF_TTRAMLOAD - if set, the program will be loaded into TT RAM - Bit 2 PF_TTRAMMEM - if set, the program will be allowed to allocate - memory from TT RAM - Bit 4 AND 5 as a two bit value with the following meanings: - 0 PF_PRIVATE - the processes entire memory space is considered private - 1 PF_GLOBAL - the processes memory will be r/w-allowed for others - 2 PF_SUPER - the memory will be r/w for itself and any supervisor proc - 3 PF_READ - the memory will be readable by others -[2] WORD ABSFLAG - is NON-ZERO, if the program does not need to be relocated - is ZERO, if the program needs to be relocated - note: since some TOS versions handle files with ABSFLAG>0 incorrectly, - this value should be set to ZERO also for programs that need to be - relocated, and the FIXUP_offset should be set to 0. - -From there on... (should be offset 0x1c) -[PRG_tsize] TEXT segment -[PRG_dsize] DATA segment -[PRG_ssize] Symbol table - -[4] LONG FIXUP_offset - first LONG that needs to be relocated (offset to beginning of file) - -From there on till the end of the file... -FIXUP table, with entries as follows: -[1] BYTE value - with value as follows: - value=0 end of list - value=1 advance 254 bytes - value=2 to value=254 (only even values!) advance this many bytes and - relocate the LONG found there -Thats it. You made it through to EOF. - -A final note about fixing up (relocating) an executable: (pseudo-code) -The long value FIXUP_offset tells you your start adress. Lets call it "adr". So, now, that -you have adr, read the first byte of the table. -(*) loop -- if its 0, stop relocating -> youre done! -- if its 1, add 254 to adr and read the next byte, jump back to the asterisk (*) -- if its any other even value, add the value to your adr, then relocate the LONG at adr. - (i.e. add the adress of the LONG to its value) - -dafi diff --git a/docs/develop/kernel/arch/m68k/atari/urls.txt b/docs/develop/kernel/arch/m68k/atari/urls.txt deleted file mode 100644 index 2874b4b90c..0000000000 --- a/docs/develop/kernel/arch/m68k/atari/urls.txt +++ /dev/null @@ -1,19 +0,0 @@ -http://toshyp.atari.org/en/index.html - -http://www.lysator.liu.se/~celeborn/sync/atari/misc.html -http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/F30.ZIP -http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/FALCLIB6.ZIP -http://www.lysator.liu.se/~celeborn/sync/atari/ATARI/FALCREGS.ZIP - - -http://fxr.watson.org/fxr/source/include/asm-m68k/atarihw.h?v=linux-2.4.22 -http://lxr.linux.no/linux+v2.6.27/arch/m68k/atari/config.c#L664 - -http://www.atari-forum.com/wiki/index.php/MFP_MK68901 - -http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/ahdi-xxboot/xxboot.ahdi.S -AHDI args -http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/wdboot/wdboot.S -http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/sdboot/sdboot.S -http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/atari/stand/xxboot/fdboot/fdboot.S - diff --git a/docs/develop/kernel/arch/m68k/overview.rst b/docs/develop/kernel/arch/m68k/overview.rst new file mode 100644 index 0000000000..cf5b590100 --- /dev/null +++ b/docs/develop/kernel/arch/m68k/overview.rst @@ -0,0 +1,21 @@ +The m68k port +############# + +The Motorola 68000 is an old CPU and not a reasonable target for Haiku. However, later models +which are equipped with a memory management unit could work (slowly). + +There is work in progress to target Atari, Amiga, and NeXT hardware platforms. + +Todo list +========= + +- optimization: remove M68KPagingStructures[*]::UpdateAllPageDirs() and just allocate all the kernel page root entries at boot and be done with it. It's not very big anyway. +- possibly other optimizations in the VM code due to not supporting SMP? + +Target platforms information +============================ + +.. toctree:: + + /kernel/arch/m68k/amiga + /kernel/arch/m68k/atari diff --git a/docs/develop/kernel/arch/ppc/bebox.rst b/docs/develop/kernel/arch/ppc/bebox.rst new file mode 100644 index 0000000000..9736c79c99 --- /dev/null +++ b/docs/develop/kernel/arch/ppc/bebox.rst @@ -0,0 +1,19 @@ +Notes on a possible BeBox Haiku port +==================================== + +Bootloader +---------- + +The BeBox ROM expects the bootloader to be in PEF format, as was produced by the CodeWarrior +compiler used by Be. However, support for this format in binutils seems incomplete. + +references +---------- + +* http://www.netbsd.org/ports/bebox/ +* http://netbsd.2816.n7.nabble.com/BeBox-memory-configuration-td278318.html + +QEMU target +----------- + +http://qemu-project.org/Features/BeBox diff --git a/docs/develop/kernel/arch/ppc/bebox.txt b/docs/develop/kernel/arch/ppc/bebox.txt deleted file mode 100644 index 6dc6d80b5d..0000000000 --- a/docs/develop/kernel/arch/ppc/bebox.txt +++ /dev/null @@ -1,7 +0,0 @@ -Notes on a possible BeBox Haiku port -*- org -*- - -* references -http://www.netbsd.org/ports/bebox/ -http://netbsd.2816.n7.nabble.com/BeBox-memory-configuration-td278318.html -** QEMU target -http://qemu-project.org/Features/BeBox diff --git a/docs/develop/kernel/arch/ppc/mac.rst b/docs/develop/kernel/arch/ppc/mac.rst new file mode 100644 index 0000000000..c6b775c2c6 --- /dev/null +++ b/docs/develop/kernel/arch/ppc/mac.rst @@ -0,0 +1,17 @@ +The Apple Macintosh port +====================================== + +The current target is "new world" machines, which have a more complete and reliable implementation +of Open Firmware. + +* http://www.debian.org/releases/stable/powerpc/ch05s01.html.en +* http://www.kernelthread.com/mac/osx/arch_boot.html +* http://playground.sun.com/1275/mejohnson/ +* http://homepages.gold.ac.uk/suzanne/startup.html +* http://www.netbsd.org/ports/macppc/SystemDisk-tutorial/ +* http://www.netneurotic.net/mac/openfirmware.html +* http://www.netbsd.org/ports/macppc/faq.html +* http://mail-index.netbsd.org/port-macppc/1999/03/21/0001.html +* http://mail-index.netbsd.org/port-macppc/1999/06/25/0006.html +* http://ps-2.kev009.com/solinno.co.uk/7043-140/files/docs/ {OF,PReP} +* http://www.openfirmware.org/1275/bindings/chrp/ diff --git a/docs/develop/kernel/arch/ppc/mac/urls.txt b/docs/develop/kernel/arch/ppc/mac/urls.txt deleted file mode 100644 index 7e48f652d4..0000000000 --- a/docs/develop/kernel/arch/ppc/mac/urls.txt +++ /dev/null @@ -1,11 +0,0 @@ -http://www.debian.org/releases/stable/powerpc/ch05s01.html.en -http://www.kernelthread.com/mac/osx/arch_boot.html -http://playground.sun.com/1275/mejohnson/ -http://homepages.gold.ac.uk/suzanne/startup.html -http://www.netbsd.org/ports/macppc/SystemDisk-tutorial/ -http://www.netneurotic.net/mac/openfirmware.html -http://www.netbsd.org/ports/macppc/faq.html -http://mail-index.netbsd.org/port-macppc/1999/03/21/0001.html -http://mail-index.netbsd.org/port-macppc/1999/06/25/0006.html -http://ps-2.kev009.com/solinno.co.uk/7043-140/files/docs/ {OF,PReP} -http://www.openfirmware.org/1275/bindings/chrp/ diff --git a/docs/develop/kernel/arch/ppc/overview.rst b/docs/develop/kernel/arch/ppc/overview.rst new file mode 100644 index 0000000000..1131b4c6c8 --- /dev/null +++ b/docs/develop/kernel/arch/ppc/overview.rst @@ -0,0 +1,24 @@ +The PowerPC port +================ + +PowerPC was the first non-x86architecture for which a port of Haiku was attempted. The initial +target was the (then recently released) Mac Mini, but of course the BeBox was in everyone's mind +as a possible target for this port. + +This port went as far as starting the kernel, but then difficulties in implementing the Mac Mini +PCI bus driver stopped it. + +Later on, some work as done on adding support for the Sam460ex development board, after a donation +of one to one of the Haiku developers. + +Recently, the lack of easily available and affordable PowerPC hardware has reduced interest in this +port. + +Platform specific details +------------------------- + +.. toctree:: + + /kernel/arch/ppc/bebox + /kernel/arch/ppc/mac + /kernel/arch/ppc/sam460ex diff --git a/docs/develop/kernel/arch/ppc/sam460ex.rst b/docs/develop/kernel/arch/ppc/sam460ex.rst new file mode 100644 index 0000000000..5d0d32e4b2 --- /dev/null +++ b/docs/develop/kernel/arch/ppc/sam460ex.rst @@ -0,0 +1,119 @@ +The Sam460ex Haiku port +======================= + +Complications for this port comes from the fact that the CPU used was designed for embedded devices, +and has a much simpler MMU than the one on desktop machines. As a result, completely different +memory management code needs to be written. + +U-Boot commands +--------------- + +no-fdt no-initrd +**************** + +seems the U-Boot input buffer is quite limited, can't paste much more on single line in minicom + + setenv ipaddr 192.168.4.100; tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub; bootm 0x4000000 + +with FDT and tgz as initrd +************************** + + setenv ipaddr 192.168.4.100 + tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub + tftpboot 0x8000000 192.168.4.2:haiku_initrd.ub + tftpboot 0xc000000 192.168.4.2:sam460ex.dtb + fdt addr 0xc000000 + fdt header + bootm 0x4000000 0x8000000 0xc000000 plop + +for environment +*************** + + setenv booth1 'setenv ipaddr 192.168.4.100; tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub' + setenv booth2 'tftpboot 0x8000000 192.168.4.2:haiku_initrd.ub' + setenv booth3 'tftpboot 0xc000000 192.168.4.2:sam460ex.dtb' + setenv booth4 'bootm 0x4000000 0x8000000 0xc000000 plop' + setenv booth 'run booth1; run booth2; run booth3; run booth4' + saveenv + run booth + +TODOs +----- + +* U-Boot API? +* move Partenope hack to proper official U-Boot API? +* reserved regs? + + BoardSetup +=:? + TARGET_BOOT_CCFLAGS += -ffixed-r2 -ffixed-r14 -ffixed-r29 ; + TARGET_BOOT_C++FLAGS += -ffixed-r2 -ffixed-r14 -ffixed-r29 ; + +* kdebug/disasm/ppc http://code.google.com/p/ppcd/ + +Other ports +----------- + +* `AROS port `_ +* `Linux port `_ +* `NetBSD `_ + +PowerPC information +------------------- + +Classic +******* + +* http://class.ee.iastate.edu/cpre211/labs/quickrefPPC.html +* http://www.ibm.com/developerworks/library/l-ppc/ +* http://www.csd.uwo.ca/~mburrel/stuff/ppc-asm.html + +Book-E +****** + +* http://www.linux-kvm.org/page/PowerPC_Book_E_MMU +* http://wiki.freebsd.org/powerpc/BookE +* http://en.wikipedia.org/wiki/Memory_management_unit#PowerPC + +ePAPR +***** + +* https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf +* PPC440: http://elinux.org/Book_E_and_PPC_440 + +amcc 4x0 +******** + +* http://c0ff33.net/drop/PPC440_UM2013.pdf +* http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/PP460EX_DS2063.pdf + +Freescale 440 +************* + +This version has a different mmu!! + +* http://www.freescale.com/files/32bit/doc/white_paper/POWRPCARCPRMRM.pdf + +FDT +--- + +* http://www.denx.de/wiki/U-Boot/UBootFdtInfo +* http://wiki.freebsd.org/FlattenedDeviceTree#Supporting_library_.28libfdt.29 +* (see also arm docs) + +Sam440 dts +********** + +* http://lxr.linux.no/linux+v3.4/arch/powerpc/boot/dts/sam440ep.dts +* Sam460ex dts: identical to amcc,Canyonlands !? +* http://www.denx.de/wiki/view/DULG/Appendix#Section_13.1. + +OpenFirmware framebuffer +************************ + +(not really usable from U-Boot (yet?)) + +* http://www.feedface.com/howto/forth.html +* http://mail-index.netbsd.org/port-macppc/2004/12/13/0046.html +* http://lists.freebsd.org/pipermail/svn-src-user/2012-January/004806.html +* http://www.openfirmware.info/Bindings + diff --git a/docs/develop/kernel/arch/ppc/sam460ex/notes.txt b/docs/develop/kernel/arch/ppc/sam460ex/notes.txt deleted file mode 100644 index 772eeceea0..0000000000 --- a/docs/develop/kernel/arch/ppc/sam460ex/notes.txt +++ /dev/null @@ -1,76 +0,0 @@ -Notes on Sam460ex Haiku port -*- org -*- - -* U-Boot commands -** no-fdt no-initrd -# (seems the U-Boot input buffer is quite limited, can't paste much more on single line in minicom) -setenv ipaddr 192.168.4.100; tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub; bootm 0x4000000 -** with FDT and tgz as initrd -setenv ipaddr 192.168.4.100 -tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub -tftpboot 0x8000000 192.168.4.2:haiku_initrd.ub -tftpboot 0xc000000 192.168.4.2:sam460ex.dtb -fdt addr 0xc000000 -fdt header -bootm 0x4000000 0x8000000 0xc000000 plop -** for environment: -setenv booth1 'setenv ipaddr 192.168.4.100; tftpboot 0x4000000 192.168.4.2:haiku_loader_linux.ub' -setenv booth2 'tftpboot 0x8000000 192.168.4.2:haiku_initrd.ub' -setenv booth3 'tftpboot 0xc000000 192.168.4.2:sam460ex.dtb' -setenv booth4 'bootm 0x4000000 0x8000000 0xc000000 plop' -setenv booth 'run booth1; run booth2; run booth3; run booth4' -saveenv -run booth - - -* TODO U-Boot API? -** TODO move Partenope hack to proper official U-Boot API? -** TODO reserved regs? -BoardSetup +=:? -TARGET_BOOT_CCFLAGS += -ffixed-r2 -ffixed-r14 -ffixed-r29 ; -TARGET_BOOT_C++FLAGS += -ffixed-r2 -ffixed-r14 -ffixed-r29 ; - -* Other ports -** AROS port -https://www.gitorious.org/aros/aros/commits/sam460 -** Linux port -http://kernel.org/doc/ols/2003/ols2003-pages-340-350.pdf -** NetBSD -https://wiki.netbsd.org/users/rkujawa/sam4x0/ - -* PPC -** Classic -http://class.ee.iastate.edu/cpre211/labs/quickrefPPC.html -http://www.ibm.com/developerworks/library/l-ppc/ -http://www.csd.uwo.ca/~mburrel/stuff/ppc-asm.html -** Book-E -http://www.linux-kvm.org/page/PowerPC_Book_E_MMU -http://wiki.freebsd.org/powerpc/BookE -http://en.wikipedia.org/wiki/Memory_management_unit#PowerPC -** ePAPR -https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf -** 440 -http://elinux.org/Book_E_and_PPC_440 -*** amcc 4x0 -http://c0ff33.net/drop/PPC440_UM2013.pdf -http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/PP460EX_DS2063.pdf -*** Freescale 440 (different mmu!!) -http://www.freescale.com/files/32bit/doc/white_paper/POWRPCARCPRMRM.pdf - -* FDT -http://www.denx.de/wiki/U-Boot/UBootFdtInfo -http://wiki.freebsd.org/FlattenedDeviceTree#Supporting_library_.28libfdt.29 -(see also arm docs) -** Sam440 dts -http://lxr.linux.no/linux+v3.4/arch/powerpc/boot/dts/sam440ep.dts -** Sam460ex dts: identical to amcc,Canyonlands !? -http://www.denx.de/wiki/view/DULG/Appendix#Section_13.1. - -* OF framebuffer -(not really usable from U-Boot (yet?)) -http://www.feedface.com/howto/forth.html -http://mail-index.netbsd.org/port-macppc/2004/12/13/0046.html -http://lists.freebsd.org/pipermail/svn-src-user/2012-January/004806.html -http://www.openfirmware.info/Bindings - -* TODO kdebug/disasm/ppc -http://code.google.com/p/ppcd/ diff --git a/docs/develop/kernel/arch/sparc/ABI.txt b/docs/develop/kernel/arch/sparc/ABI.txt deleted file mode 100644 index 9f4ca19911..0000000000 --- a/docs/develop/kernel/arch/sparc/ABI.txt +++ /dev/null @@ -1,32 +0,0 @@ -The SPARC architecture has 32 integer registers, divided as follows: - -- global registers (g0-g7) -- input (i0-i7) -- local (l0-l7) -- output (o0-o7) - -Parameter passing and return is done using the output registers, which are -generally considered scratch registers and can be corrupted by the callee. The -caller must take care of preserving them. - -The input and local registers are callee-saved, but we have hardware assistance -in the form of a register window. There is an instruction to shift the registers -so that: -- o registers become i registers -- local and output registers are replaced with fresh sets, for use by the - current function -- global registers are not affected - -Note that as a side-effect, o7 is moved to i7, this is convenient because these -are usually the stack and frame pointers, respectively. So basically this sets -the frame pointer for free. - -Simple enough functions may end up using just the o registers, in that case -nothing special is necessary, of course. - -When shifting the register window, the extra registers come from the register -stack in the CPU. This is not infinite, however, most implementations of SPARC -will only have 8 windows available. When the internal stack is full, an overflow -trap is raised, and the handler must free up old windows by storing them on the -stack, likewise, when the internal stack is empty, an underflow trap must fill -it back from the stack-saved data. diff --git a/docs/develop/kernel/arch/sparc/misaligned memory access.txt b/docs/develop/kernel/arch/sparc/misaligned memory access.txt deleted file mode 100644 index 9591b453a5..0000000000 --- a/docs/develop/kernel/arch/sparc/misaligned memory access.txt +++ /dev/null @@ -1,37 +0,0 @@ -The SPARC CPU is not designed to gracefully handle misaligned accesses. -You can access a single byte at any address, but 16-bit access only at even -addresses, 32bit access at multiple of 4 addresses, etc. - -For example, on x86, such accesses are not a problem, it is allowed and handled -directly by the instructions doing the access. So there is no performance cost. - -On SPARC, however, such accesses will cause a SIGBUS. This means a trap handler -has to catch the misaligned access and do it in software, byte by byte, then -give back control to the application. This is, of course, very slow, so we -should avoid it when possible. - -Fortunately, gcc knows about this, and will normally do the right thing: -- For usual variables and structures, it will make sure to lay them out so that - they are aligned. It relies on stack alignment, as well as malloc returning - sufficiently aligned memory (as required by the C standard). -- On packed structure, gcc knows the data is misaligned, and will automatically - use the appropriate way to access it (most likely, byte-by-byte). - -This leaves us with two undesirable cases: -- Pointer arithmetics and casting. When computing addresses manually, it's - possible to generate a misaligned address and cast it to a type with a wider - alignment requirement. In this case, gcc may access the pointer using a - multi byte instruction and cause a SIGBUS. Solution: make sure the struct - is aligned, or declare it as packed so unaligned access are used instead. -- Access to hardware: it is a common pattern to declare a struct as packed, - and map it to hardware registers. If the alignment isn't known, gcc will use - byte by byte access. It seems volatile would cause gcc to use the proper way - to access the struct, assuming that a volatile value is necessarily - aligned as it should. - -In the end, we just need to be careful about pointer math resulting in unalined -access. -Wcast-align helps with that, but it also raises a lot of false positives -(where the alignment is preserved even when casting to other types). So we -enable it only as a warning for now. We will need to ceck the sigbus handler to -identify places where we do a lot of misaligned accesses that trigger it, and -rework the code as needed. But in general, except for these cases, we're fine. diff --git a/docs/develop/kernel/arch/sparc/mmu.txt b/docs/develop/kernel/arch/sparc/mmu.txt deleted file mode 100644 index 6c6e8f9b36..0000000000 --- a/docs/develop/kernel/arch/sparc/mmu.txt +++ /dev/null @@ -1,116 +0,0 @@ -Notes on the Ultrasparc MMUs -============================ - -First, a word of warning: the MMU was different in SPARCv8 (32bit) -implementations, and it was changed again on newer CPUs. - -The Ultrasparc-II we are supporting for now is documented in the Ultrasparc -user manual. There were some minor changes in the Ultrasparc-III to accomodate -larger physical addresses. This was then standardized as JPS1, and Fujitsu -also implemented it. - -Later on, the design was changed again, for example Ultrasparc T2 (UA2005 -architecture) uses a different data structure format to enlarge, again, the -physical and virtual address tags. - -For now te implementation is focused on Ultrasparc-II because that's what I -have at hand, later on we will need support for the more recent systems. - -Ultrasparc-II MMU -================= - -There are actually two separate units for the instruction and data address -spaces, known as I-MMU and D-MMU. They each implement a TLB (translation -lookaside buffer) for the recently accessed pages. - -This is pretty much all there is to the MMU hardware. No hardware page table -walk is provided. However, there is some support for implementing a TSB -(Translation Storage Buffer) in the form of providing a way to compute an -address into that buffer where the data for a missing page could be. - -It is up to software to manage the TSB (globally or per-process) and in general -keep track of the mappings. This means we are relatively free to manage things -however we want, as long as eventually we can feed the iTLB and dTLB with the -relevant data from the MMU trap handler. - -To make sure we can handle the fault without recursing, we need to pin a few -items in place: - -In the TLB: -- TLB miss handler code -- TSB and any linked data that the TLB miss handler may need -- asynchronous trap handlers and data - -In the TSB: -- TSB-miss handling code -- Interrupt handlers code and data - -So, from a given virtual address (assuming we are using only 8K pages and a -512 entry TSB to keep things simple): - -VA63-44 are unused and must be a sign extension of bit 43 -VA43-22 are the 'tag' used to match a TSB entry with a virtual address -VA21-13 are the offset in the TSB at which to find a candidate entry -VA12-0 are the offset in the 8K page, and used to form PA12-0 for the access - -Inside the TLBs, VA63-13 is stored, so there can be multiple entries matching -the same tag active at the same time, even when there is only one in the TSB. -The entries are rotated using a simple LRU scheme, unless they are locked of -course. Be careful to not fill a TLB with only locked entries! Also one must -take care of not inserting a new mapping for a given VA without first removing -any possible previous one (no need to worry about this when handling a TLB -miss however, as in that case we obviously know that there was no previous -entry). - -Entries also have a "context". This could for example be mapped to the process -ID, allowing to easily clear all entries related to a specific context. - -TSB entries format -================== - -Each entry is composed of two 64bit values: "Tag" and "Data". The data uses the -same format as the TLB entries, however the tag is different. - -They are as follow: - -Tag ---- - -Bit 63: 'G' indicating a global entry, the context should be ignored. -Bits 60-48: context ID (13 bits) -Bits 41-0: VA63-22 as the 'tag' to identify this entry - -Data ----- - -Bit 63: 'V' indicating a valid entry, if it's 0 the entry is unused. -Bits 62-61: size: 8K, 64K, 512K, 4MB -Bit 60: NFO, indicating No Fault Only -Bit 59: Invert Endianness of accesses to this page -Bits 58-50: reserved for use by software -Bits 49-41: reserved for diagnostics -Bits 40-13: Physical Address<40-13> -Bits 12-7: reserved for use by software -Bit 6: Lock in TLB -Bit 5: Cachable physical -Bit 4: Cachable virtual -Bit 3: Access has side effects (HW is mapped here, or DMA shared RAM) -Bit 2: Privileged -Bit 1: Writable -Bit 0: Global - -TLB internal tag ----------------- - -Bits 63-13: VA<63-13> -Bits 12-0: context ID - -Conveniently, a 512 entries TSB fits exactly in a 8K page, so it can be locked -in the TLB with a single entry there. However, it may be a wise idea to instead -map 64K (or more) of RAM locked as a single entry for all the things that needs -to be accessed by the TLB miss trap handler, so we minimize the use of TLB -entries. - -Likewise, it may be useful to use 64K pages instead of 8K whenever possible. -The hardware provides some support for mixing the two sizes but it makes things -a bit more complex. Let's start out with simpler things. diff --git a/docs/develop/kernel/arch/sparc/openboot.txt b/docs/develop/kernel/arch/sparc/openboot.txt deleted file mode 100644 index 6dbba352bb..0000000000 --- a/docs/develop/kernel/arch/sparc/openboot.txt +++ /dev/null @@ -1,97 +0,0 @@ -Openboot is Sun's implementation of Open Firmware. So we should be able to share -a lot of code with the PowerPC port. There are some differences however. - -Executable format -================= - -PowerPC uses COFF. Sparc uses a.out, which is a lot simpler. According to the -spec, some fields should be zeroed out, but they say implementation may chose -to allow other values, so a standard a.out file works as well. - -It used to be possible to generate one with objcopy, but support was removed, -so we now use elf2aout (imported from FreeBSD). - -The file is first loaded at 4000, then relocated to its load address (we use -202000 and executed there) - -Openfirmware prompt -=================== - -To get the prompt on display, use STOP+A at boot until you get the "ok" prompt. -On some machines, if no keyboard is detected, the ROM will assume it is set up -in headless mode, and will expect a BREAK+A on the serial port. - -STOP+N resets all variables to default values (in case you messed up input or -output, for example). - -Useful commands -=============== - -Disable autoboot to get to the openboot prompt and stop there -------------------------------------------------------------- - -setenv auto-boot? false - -Configuring for keyboard/framebuffer io ---------------------------------------- - -setenv screen-#columns 160 -setenv screen-#rows 49 -setenv output-device screen:r1920x1080x60 -setenv input-device keyboard - -Configuring openboot for serial port ------------------------------------- - -setenv ttya-mode 38400,8,n,1,- -setenv output-device ttya -setenv input-device ttya -reset - -Boot from network ------------------ - -static ip: -This currently works best, because rarp does not let the called binary know the -IP address. We need the IP address if we want to mount the root filesystem using -remote_disk server. - - boot net:192.168.1.2,somefile,192.168.1.89 - -The first IP is the server from which to download (using TFTP), the second is -the client IP to use. Once the bootloader starts, it will detect that it is -booted from network and look for a the remote_disk_server on the same machine. - -rarp: - -This needs a reverse ARP server (easy to setup on any Linux system). You need -to list the MAC address of the SPARC machine in /etc/ethers on the server. The -machine will get its IP, and will use TFTP to the server which replied, to get -the boot file from there. - - boot net:,somefile - -(net is an alias to the network card and also sets the load address: /pci@1f,4000/network@1,1) - -dhcp: - -This needs a DHCP/BOOTP server configured to send the info about where to find -the file to load and boot. - - boot net:dhcp - - - -Debugging ---------- - -202000 dis (disassemble starting at 202000 until next return instruction) - -4000 1000 dump (dump 1000 bytes from address 4000) - -.registers (show global registers) -.locals (show local/windowed registers) - -%pc dis (disassemble code being exectuted) - -ctrace (backtrace) diff --git a/docs/develop/kernel/arch/sparc/overview.rst b/docs/develop/kernel/arch/sparc/overview.rst new file mode 100644 index 0000000000..2b3a86969f --- /dev/null +++ b/docs/develop/kernel/arch/sparc/overview.rst @@ -0,0 +1,335 @@ +The SPARC port +############## + +The SPARC port targets various machines from Sun product lineup. The initial effort is on the +Ultra 60 and Ultra 5, with plans to latter add the Sun T5120 and its newer CPU. This may change +depending on hardware donations and developer interest. + +Support for 32-bit versions of SPARC is currently not planned. + +SPARC ABI +========= + +The SPARC architecture has 32 integer registers, divided as follows: + +- global registers (g0-g7) +- input (i0-i7) +- local (l0-l7) +- output (o0-o7) + +Parameter passing and return is done using the output registers, which are +generally considered scratch registers and can be corrupted by the callee. The +caller must take care of preserving them. + +The input and local registers are callee-saved, but we have hardware assistance +in the form of a register window. There is an instruction to shift the registers +so that: + +- o registers become i registers +- local and output registers are replaced with fresh sets, for use by the + current function +- global registers are not affected + +Note that as a side-effect, o7 is moved to i7, this is convenient because these +are usually the stack and frame pointers, respectively. So basically this sets +the frame pointer for free. + +Simple enough functions may end up using just the o registers, in that case +nothing special is necessary, of course. + +When shifting the register window, the extra registers come from the register +stack in the CPU. This is not infinite, however, most implementations of SPARC +will only have 8 windows available. When the internal stack is full, an overflow +trap is raised, and the handler must free up old windows by storing them on the +stack, likewise, when the internal stack is empty, an underflow trap must fill +it back from the stack-saved data. + +Misaligned memory access +======================== + +The SPARC CPU is not designed to gracefully handle misaligned accesses. +You can access a single byte at any address, but 16-bit access only at even +addresses, 32bit access at multiple of 4 addresses, etc. + +For example, on x86, such accesses are not a problem, it is allowed and handled +directly by the instructions doing the access. So there is no performance cost. + +On SPARC, however, such accesses will cause a SIGBUS. This means a trap handler +has to catch the misaligned access and do it in software, byte by byte, then +give back control to the application. This is, of course, very slow, so we +should avoid it when possible. + +Fortunately, gcc knows about this, and will normally do the right thing: + +- For usual variables and structures, it will make sure to lay them out so that + they are aligned. It relies on stack alignment, as well as malloc returning + sufficiently aligned memory (as required by the C standard). +- On packed structure, gcc knows the data is misaligned, and will automatically + use the appropriate way to access it (most likely, byte-by-byte). + +This leaves us with two undesirable cases: + +- Pointer arithmetics and casting. When computing addresses manually, it's + possible to generate a misaligned address and cast it to a type with a wider + alignment requirement. In this case, gcc may access the pointer using a + multi byte instruction and cause a SIGBUS. Solution: make sure the struct + is aligned, or declare it as packed so unaligned access are used instead. +- Access to hardware: it is a common pattern to declare a struct as packed, + and map it to hardware registers. If the alignment isn't known, gcc will use + byte by byte access. It seems volatile would cause gcc to use the proper way + to access the struct, assuming that a volatile value is necessarily + aligned as it should. + +In the end, we just need to be careful about pointer math resulting in unalined +access. -Wcast-align helps with that, but it also raises a lot of false positives +(where the alignment is preserved even when casting to other types). So we +enable it only as a warning for now. We will need to ceck the sigbus handler to +identify places where we do a lot of misaligned accesses that trigger it, and +rework the code as needed. But in general, except for these cases, we're fine. + +The Ultrasparc MMUs +============================ + +First, a word of warning: the MMU was different in SPARCv8 (32bit) +implementations, and it was changed again on newer CPUs. + +The Ultrasparc-II we are supporting for now is documented in the Ultrasparc +user manual. There were some minor changes in the Ultrasparc-III to accomodate +larger physical addresses. This was then standardized as JPS1, and Fujitsu +also implemented it. + +Later on, the design was changed again, for example Ultrasparc T2 (UA2005 +architecture) uses a different data structure format to enlarge, again, the +physical and virtual address tags. + +For now te implementation is focused on Ultrasparc-II because that's what I +have at hand, later on we will need support for the more recent systems. + +Ultrasparc-II MMU +----------------- + +There are actually two separate units for the instruction and data address +spaces, known as I-MMU and D-MMU. They each implement a TLB (translation +lookaside buffer) for the recently accessed pages. + +This is pretty much all there is to the MMU hardware. No hardware page table +walk is provided. However, there is some support for implementing a TSB +(Translation Storage Buffer) in the form of providing a way to compute an +address into that buffer where the data for a missing page could be. + +It is up to software to manage the TSB (globally or per-process) and in general +keep track of the mappings. This means we are relatively free to manage things +however we want, as long as eventually we can feed the iTLB and dTLB with the +relevant data from the MMU trap handler. + +To make sure we can handle the fault without recursing, we need to pin a few +items in place: + +In the TLB: + +- TLB miss handler code +- TSB and any linked data that the TLB miss handler may need +- asynchronous trap handlers and data + +In the TSB: + +- TSB-miss handling code +- Interrupt handlers code and data + +So, from a given virtual address (assuming we are using only 8K pages and a +512 entry TSB to keep things simple): + +VA63-44 are unused and must be a sign extension of bit 43 +VA43-22 are the 'tag' used to match a TSB entry with a virtual address +VA21-13 are the offset in the TSB at which to find a candidate entry +VA12-0 are the offset in the 8K page, and used to form PA12-0 for the access + +Inside the TLBs, VA63-13 is stored, so there can be multiple entries matching +the same tag active at the same time, even when there is only one in the TSB. +The entries are rotated using a simple LRU scheme, unless they are locked of +course. Be careful to not fill a TLB with only locked entries! Also one must +take care of not inserting a new mapping for a given VA without first removing +any possible previous one (no need to worry about this when handling a TLB +miss however, as in that case we obviously know that there was no previous +entry). + +Entries also have a "context". This could for example be mapped to the process +ID, allowing to easily clear all entries related to a specific context. + +TSB entries format +------------------ + +Each entry is composed of two 64bit values: "Tag" and "Data". The data uses the +same format as the TLB entries, however the tag is different. + +They are as follow: + +Tag +*** + +Bit 63: 'G' indicating a global entry, the context should be ignored. +Bits 60-48: context ID (13 bits) +Bits 41-0: VA63-22 as the 'tag' to identify this entry + +Data +**** + +Bit 63: 'V' indicating a valid entry, if it's 0 the entry is unused. +Bits 62-61: size: 8K, 64K, 512K, 4MB +Bit 60: NFO, indicating No Fault Only +Bit 59: Invert Endianness of accesses to this page +Bits 58-50: reserved for use by software +Bits 49-41: reserved for diagnostics +Bits 40-13: Physical Address<40-13> +Bits 12-7: reserved for use by software +Bit 6: Lock in TLB +Bit 5: Cachable physical +Bit 4: Cachable virtual +Bit 3: Access has side effects (HW is mapped here, or DMA shared RAM) +Bit 2: Privileged +Bit 1: Writable +Bit 0: Global + +TLB internal tag +**************** + +Bits 63-13: VA<63-13> +Bits 12-0: context ID + +Conveniently, a 512 entries TSB fits exactly in a 8K page, so it can be locked +in the TLB with a single entry there. However, it may be a wise idea to instead +map 64K (or more) of RAM locked as a single entry for all the things that needs +to be accessed by the TLB miss trap handler, so we minimize the use of TLB +entries. + +Likewise, it may be useful to use 64K pages instead of 8K whenever possible. +The hardware provides some support for mixing the two sizes but it makes things +a bit more complex. Let's start out with simpler things. + +Software floating-point support +=============================== + +The SPARC instruction set specifies instruction for handling long double +values, however, no hardware implementation actually provides them. They +generate a trap, which is expected to be handled by the softfloat library. + +Since traps are slow, and gcc knows better, it will never generate those +instructions. Instead it directly calls into the C library, to functions +specified in the ABI and used to do long double math using softfloats. + +The support code for this is, in our case, compiled into both the kernel and +libroot. It lives in src/system/libroot/os/arch/sparc/softfloat.c (and other +support files). This code was extracted from FreeBSD, rather than the glibc, +because that made it much easier to get it building in the kernel. + +Openboot bootloader +=================== + +Openboot is Sun's implementation of Open Firmware. So we should be able to share +a lot of code with the PowerPC port. There are some differences however. + +Executable format +----------------- + +PowerPC uses COFF. Sparc uses a.out, which is a lot simpler. According to the +spec, some fields should be zeroed out, but they say implementation may chose +to allow other values, so a standard a.out file works as well. + +It used to be possible to generate one with objcopy, but support was removed, +so we now use elf2aout (imported from FreeBSD). + +The file is first loaded at 4000, then relocated to its load address (we use +202000 and executed there) + +Openfirmware prompt +------------------- + +To get the prompt on display, use STOP+A at boot until you get the "ok" prompt. +On some machines, if no keyboard is detected, the ROM will assume it is set up +in headless mode, and will expect a BREAK+A on the serial port. + +STOP+N resets all variables to default values (in case you messed up input or +output, for example). + +Useful commands +--------------- + +Disable autoboot to get to the openboot prompt and stop there + +.. code-block:: text + + setenv auto-boot? false + +Configuring for keyboard/framebuffer io + +.. code-block:: text + + setenv screen-#columns 160 + setenv screen-#rows 49 + setenv output-device screen:r1920x1080x60 + setenv input-device keyboard + +Configuring openboot for serial port + +.. code-block:: text + + setenv ttya-mode 38400,8,n,1,- + setenv output-device ttya + setenv input-device ttya + reset + +Boot from network +----------------- + +static ip +********* + +This currently works best, because rarp does not let the called binary know the +IP address. We need the IP address if we want to mount the root filesystem using +remote_disk server. + +.. code-block:: text + + boot net:192.168.1.2,somefile,192.168.1.89 + +The first IP is the server from which to download (using TFTP), the second is +the client IP to use. Once the bootloader starts, it will detect that it is +booted from network and look for a the remote_disk_server on the same machine. + +rarp +**** + +This needs a reverse ARP server (easy to setup on any Linux system). You need +to list the MAC address of the SPARC machine in /etc/ethers on the server. The +machine will get its IP, and will use TFTP to the server which replied, to get +the boot file from there. + +.. code-block:: text + + boot net:,somefile + +(net is an alias to the network card and also sets the load address: /pci@1f,4000/network@1,1) + +dhcp +**** + +This needs a DHCP/BOOTP server configured to send the info about where to find +the file to load and boot. + +.. code-block:: text + + boot net:dhcp + + + +Debugging +--------- + +.. code-block:: text + + 202000 dis (disassemble starting at 202000 until next return instruction) + 4000 1000 dump (dump 1000 bytes from address 4000) + .registers (show global registers) + .locals (show local/windowed registers) + %pc dis (disassemble code being exectuted) + ctrace (backtrace) diff --git a/docs/develop/kernel/arch/sparc/softfloat.txt b/docs/develop/kernel/arch/sparc/softfloat.txt deleted file mode 100644 index 4fbd2a0b49..0000000000 --- a/docs/develop/kernel/arch/sparc/softfloat.txt +++ /dev/null @@ -1,12 +0,0 @@ -The SPARC instruction set specifies instruction for handling long double -values, however, no hardware implementation actually provides them. They -generate a trap, which is expected to be handled by the softfloat library. - -Since traps are slow, and gcc knows better, it will never generate those -instructions. Instead it directly calls into the C library, to functions -specified in the ABI and used to do long double math using softfloats. - -The support code for this is, in our case, compiled into both the kernel and -libroot. It lives in src/system/libroot/os/arch/sparc/softfloat.c (and other -support files). This code was extracted from FreeBSD, rather than the glibc, -because that made it much easier to get it building in the kernel. diff --git a/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.md b/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.md deleted file mode 100644 index dac2537045..0000000000 --- a/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.md +++ /dev/null @@ -1,93 +0,0 @@ -# Bootloader debugging with GEF - -When Haiku's early boot process is experiencing unknown crashes or faults, it can be extremely -difficult to troubleshoot (especially when serial, video, or other i/o devices are non-functional) - -It **is** possible to step through the boot of any architecture of Haiku in a debugger if the system -boots and the issue can be reproduced in qemu. - -> This works for any architecture and is _extremely_ helpful to trouble early platforms. Linux or Mac OS -> are requirements. You need a full POSIX environment. - -## Building Haiku - -On most non-x86 platforms, you will need a "kernel" (haiku_loader) and an "initrd" (haiku_floppyboot). - -For arm/arm64: ```jam -q @minimum-mmc``` - -## Launching Haiku in QEMU - -In the example below, we will prepare Haiku arm in QEMU for debugging. - -``` -qemu-system-arm -M raspi2 -kernel haiku_loader.u-boot -initrd haiku-floppyboot.tgz.u-boot -serial stdio -m 2G -dtb rpi2.dtb -s -S -``` - -**Key Flags:** - - * **-s** - * Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234. - * **-S** - * Do not start CPU at startup (you must type 'c' in the monitor). - -These simple flags will make qemu listen for a debugger connection on localhost:1234 and have the VM not start until you tell it to. - -> In the example above, we are Emulating a Raspberry Pi 2, and using our Raspberry Pi 2 dtb. If you don't have a dtb for the machine -> you're emulating, you can dump qemu's internal dtb by adding ```-M dumpdtb=myboard.dtb``` to the end of your qemu command. - -## Attaching GEF - -[GEF](https://github.com/hugsy/gef) is an enhanced debugger which works extremely well for debugging code running in virtual machines. -It piggy-backs on gdb and offers a lot of valueable insight at a glance without requiring to know every gdb command. - -Once GEF is installed, we can step through the process to attach gdb to qemu. - -### Open gdb with our symbols. - -First we run gdb pointed at our boot loader. We use the native ELF binary as that seems to give gdb/gef the most accurate knowledge -of our symbols. (the haiku_loader.u-boot is wrapped by u-boot's mkimage, your milage may vary based on platform) - -```gdb objects/haiku/arm/release/system/boot/u-boot/boot_loader_u-boot``` - -### Set the architecture - -This may not be required, but re-enforces to gef/gdb that we're working on arm. - -```set architecture arm``` - -### Connect to QEMU - -Now we tell gdb/gef about out running (but paused) QEMU instance. - -```gef-remote -q localhost:1234``` - -A successful connection should occur. - -### Step into debugging - -Before you begin execution, it's handy to set a *breakpoint*. A *breakpoint* tells gdb/gef where it should pause execution to begin -the debugging process. All of our bootloaders start in a ```start_gen``` function, so this is a good place to start. - -```breakpoint start_gen``` - -Now that a breakpoint is defined, lets run the virtual machine. - -In gef, type ```continue```. - -If everything is working as expected, you should now be "paused" at the ```start_gen``` function (hopefully showing the C/C++ code). - -Now, you have a few commands to leverage: - - * **step** - * Take a single step forward and execute the code listed. - * Does **not** step "into" functions, just over them getting the return from the code. - * Alias: s - * **stepi** - * step forward "into" the next code. - * If you're on a function it will enter the function and show the code executed. - * **break** - * add additional "breakpoints" where you can step through the code execution. - * **continue** - * Resume execution. - * If you have no additional breakpoints the code will "go do what it's supposed to" - * Alias: c diff --git a/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.rst b/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.rst new file mode 100644 index 0000000000..39d5e7ac61 --- /dev/null +++ b/docs/develop/kernel/boot/Debugging_Bootloaders_GEF.rst @@ -0,0 +1,137 @@ +Bootloader debugging with GEF +============================= + +When Haiku’s early boot process is experiencing unknown crashes or +faults, it can be extremely difficult to troubleshoot (especially when +serial, video, or other i/o devices are non-functional) + +It **is** possible to step through the boot of any architecture of Haiku +in a debugger if the system boots and the issue can be reproduced in +qemu. + + This works for any architecture and is *extremely* helpful to trouble + early platforms. Linux or Mac OS are requirements. You need a full + POSIX environment. + +Building Haiku +-------------- + +On most non-x86 platforms, you will need a “kernel” (haiku_loader) and +an “initrd” (haiku_floppyboot). + +For arm/arm64: ``jam -q @minimum-mmc`` + +Launching Haiku in QEMU +----------------------- + +In the example below, we will prepare Haiku arm in QEMU for debugging. + +:: + + qemu-system-arm -M raspi2 -kernel haiku_loader.u-boot -initrd haiku-floppyboot.tgz.u-boot -serial stdio -m 2G -dtb rpi2.dtb -s -S + +**Key Flags:** + +- **-s** + + - Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port + 1234. + +- **-S** + + - Do not start CPU at startup (you must type ‘c’ in the monitor). + +These simple flags will make qemu listen for a debugger connection on +localhost:1234 and have the VM not start until you tell it to. + + In the example above, we are Emulating a Raspberry Pi 2, and using + our Raspberry Pi 2 dtb. If you don’t have a dtb for the machine + you’re emulating, you can dump qemu’s internal dtb by adding + ``-M dumpdtb=myboard.dtb`` to the end of your qemu command. + +Attaching GEF +------------- + +`GEF `__ is an enhanced debugger which +works extremely well for debugging code running in virtual machines. It +piggy-backs on gdb and offers a lot of valueable insight at a glance +without requiring to know every gdb command. + +Once GEF is installed, we can step through the process to attach gdb to +qemu. + +Open gdb with our symbols. +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First we run gdb pointed at our boot loader. We use the native ELF +binary as that seems to give gdb/gef the most accurate knowledge of our +symbols. (the haiku_loader.u-boot is wrapped by u-boot’s mkimage, your +milage may vary based on platform) + +``gdb objects/haiku/arm/release/system/boot/u-boot/boot_loader_u-boot`` + +Set the architecture +~~~~~~~~~~~~~~~~~~~~ + +This may not be required, but re-enforces to gef/gdb that we’re working +on arm. + +``set architecture arm`` + +Connect to QEMU +~~~~~~~~~~~~~~~ + +Now we tell gdb/gef about out running (but paused) QEMU instance. + +``gef-remote -q localhost:1234`` + +A successful connection should occur. + +Step into debugging +~~~~~~~~~~~~~~~~~~~ + +Before you begin execution, it’s handy to set a *breakpoint*. A +*breakpoint* tells gdb/gef where it should pause execution to begin the +debugging process. All of our bootloaders start in a ``start_gen`` +function, so this is a good place to start. + +``breakpoint start_gen`` + +Now that a breakpoint is defined, lets run the virtual machine. + +In gef, type ``continue``. + +If everything is working as expected, you should now be “paused” at the +``start_gen`` function (hopefully showing the C/C++ code). + +Now, you have a few commands to leverage: + +- **step** + + - Take a single step forward and execute the code listed. + - Does **not** step “into” functions, just over them getting the + return from the code. + - Alias: s + +- **stepi** + + - step forward “into” the next code. + - If you’re on a function it will enter the function and show the + code executed. + +- **break** + + - add additional “breakpoints” where you can step through the code + execution. + +- **continue** + + - Resume execution. + - If you have no additional breakpoints the code will “go do what + it’s supposed to” + - Alias: c + +- **next** + + - Resume execution until it reaches the next line of code. + - Useful for example to run until a loop is completed, and stop at the first line after that loop. diff --git a/docs/develop/kernel/boot/boot_process_specs.html b/docs/develop/kernel/boot/boot_process_specs.html deleted file mode 100644 index b5a0d9bf0e..0000000000 --- a/docs/develop/kernel/boot/boot_process_specs.html +++ /dev/null @@ -1,165 +0,0 @@ - -

Haiku boot process specification

-
- Creation Date: November 23, 2002
- Version: 2.0 (Jan 22, 2021)
- Status: documenting the current state of things
- Author(s): Axel Dörfler, Adrien Destugues -
- -

Overview

- -

Unlike other systems, Haiku comes with its own user-friendly bootloader. The main task of - the bootloader is to load and start the kernel. We don't have a concept of an initramfs as - Linux does, instead our bootloader is able to find the kernel and modules in a BFS partition, - and even extract them from packages as needed. It also provides an early boot menu that can - be used to change settings, boot older versions of Haiku that were snapshotted by the package - system, and write boot logs to USB mass storage.

- -

Booting from BIOS

- -

- Haiku BIOS boot loader process is split into 3 different stages. Since the second - stage is bound tightly to both other stages (which are independent from each other), - it is referred to as stage 1.5, whereas the other stages are referred to as stage 1 - and 2. This architecture is used because the BIOS booting process only loads a very - small piece of code from disk for booting, insufficient for the needs outlined above.

- -

The following will explain all stages in detail.

- -

Stage 1

-

- The first stage is responsible for loading the real boot loader from a BFS disk. It - will be loaded by the Master Boot Record (MBR) and executed in the x86 real mode. - It is only used if the system will be booted directly from a BFS partition, it won't - be used at all if it is booted from a floppy disk or CD-ROM (in this case, stage - 1.5 is in charge immediately). -

-

- It resides in the first 1024 bytes of a BFS disk which usually refers to the - first two sectors of the partition in question. Since the BFS superblock is located - at byte offset 512, and about 170 bytes large, this section is already reserved, - and thus cannot be used by the loader itself.
- The MBR only loads the first sector of a partition into memory, so it has to load - the superblock (and the rest of its implementation) by itself. -

-

- The loader must be able to load the real boot loader from a certain path, and - execute it. In BeOS this boot loader would be in "/boot/beos/system/zbeos", - in Haiku this is haiku_loader.bios_ia32 found in the haiku_loader package.
- Theoretically, it is enough to load the first few blocks from the loader, and - let the next stage then load the whole thing (which it has to do anyway if it - has been written on a floppy). This would be one possible optimization - if the 850 bytes of space are filled too early, but would require that "zbeos" - is written in one sequential block (which should be always the case anyway). -

- -

haiku_loader.bios_ia32

-

- Contains both the stage 1.5 boot loader, and the compressed stage 2 loader. - It's not an ELF executable file; i.e. it can be directly written to a floppy - disk which would cause the BIOS to load the first 512 bytes of that file and - execute it. -

-

- Therefore, it will start with the stage 1.5 boot loader which will be loaded - either by the BIOS when it directly resides on the disk (for example when - loaded from a floppy disk), or the stage 1 boot loader, although this one - could have a different entry point than the BIOS. -

- -

Stage 1.5

-

- Will have to load the rest of haiku_loader into memory (if not already done by the - stage 1 loader in case it has been loaded from a BFS disk), set up the global - descriptor table, switch to x86 protected mode, uncompress stage 2, and execute it. -

-

- This part is very similar to the stage 1 boot loader from NewOS. -

- -

Stage 2

-

- This is the most complex part of the boot loader. In short, it has to load - any modules and devices the kernel needs to access the boot device, set up - the system, load the kernel, and execute it. -

-

- The kernel, and the modules and drivers needed are loaded from the boot - disk - therefore the loader has to be able to access BFS disks. It also - has to be able to load and parse the settings of these drivers (and the - kernel) from the boot disk, some of them are already important for the - boot loader itself (like "don't call the BIOS"). Since this stage is already - executed in protected mode, it has to use the virtual-86 mode to call the - BIOS and access any disk. -

-

- Before loading those files from the boot disk, it should look for additional - files located on a specific disk location after the "zbeos" file (on floppy disk - or CD-ROM). This way, it could access disks that cannot be accessed by the - BIOS itself. -

-

- Setting up the system for the kernel also means initalizing PCI devices needed - during the boot process before the kernel is up. It must be able to do so since - the BIOS might not have set up those devices correctly or at all. -

-

- It also must calculate a check sum for the boot device which the kernel can then - use to identify the boot volume and partition with - there is no other reliable - way to map BIOS disk IDs to the /dev/disk/... tree the system itself is using. -

-

- After having loaded and relocated the kernel, it executes it by passing a special - structure which tells the kernel things like the boot device check sum, which - modules are already loaded and where they are. -

-

- The stage 2 boot loader also includes user interaction. If the user presses a - special key during the boot process (like the space key, or some others as well), - a menu will be presented where the user can select the boot device (if several, - the loader has to scan for options), safe mode options, VESA mode, etc. -

-

- This menu may also come up if an error occured during the execution of the stage - 2 loader. -

- -

Open Firmware

- -

On Open Firmware based systems, there is no need for a stage 1.5 because the firmware - does not give us as many constraints. Instead, the stage 2 is loaded directly by the firmware. - This requires converting the haiku_loader executable to the appropriate executable format - (a.out on sparc, pef on powerpc). The conversion is done using custom tools because binutils - does not support these formats anymore.

- -

There is no notion of real and protected mode on non-x86 architectures, and the bootloader - is able to easily call Open Firmware methods to perform most tasks (disk access, network booting, - setting up the framebuffer) in a largely hardware-independent way.

- -

U-Boot

- -

U-Boot is able to load the stage2 loader directly from an ELF file. However, it does not - provide any other features. It is not possible for the bootloader to call into U-Boot APIs - for disk access, displaying messages on screen etc (while possible in theory, these features - are often disabled in U-Boot). This means haiku_loader would need to parse the FDT (describing - the available hardware) and bundle its own drivers for using the hardware. This approach is - not easy to set up, and it is recommended to instead use the UEFI support in U-Boot where - possible.

- -

EFI

- -

On EFI systems, there is no need for a stage1 loader as there is for BIOS. Instead, our stage2 - loader (haiku_loader) can be executed directly from the EFI firmware.

- -

The EFI firmware only knows how to run executables in the PE format - (as used by Windows) because Microsoft was involved in specifying it. - On x86_64, we can use binutils to output a PE file directly. But on other platforms, this is not - supported by binutils. So, what we do is generate a "fake" PE header and wrap our elf file inside - it. The bootloader then parses the embedded ELF header and relocates itself, so the other parts - of the code can be run.

- -

After this initial loading phase, the process is very similar to the Open Firmware one. EFI - provides us with all the tools we need to do disk access and both text mode and framebuffer - output.

- diff --git a/docs/develop/kernel/boot/boot_process_specs.rst b/docs/develop/kernel/boot/boot_process_specs.rst new file mode 100644 index 0000000000..00e671b35e --- /dev/null +++ b/docs/develop/kernel/boot/boot_process_specs.rst @@ -0,0 +1,174 @@ +Haiku boot process specification +================================ + +Creation Date: November 23, 2002 +Version: 2.0 (Jan 22, 2021) +Status: documenting the current state of things +Author(s): Axel Dörfler, Adrien Destugues + + +Overview +-------- + +Unlike other systems, Haiku comes with its own user-friendly bootloader. +The main task of the bootloader is to load and start the kernel. We +don't have a concept of an initramfs as Linux does, instead our +bootloader is able to find the kernel and modules in a BFS partition, +and even extract them from packages as needed. It also provides an early +boot menu that can be used to change settings, boot older versions of +Haiku that were snapshotted by the package system, and write boot logs +to USB mass storage. + +Booting from BIOS +----------------- + +Haiku BIOS boot loader process is split into 3 different stages. Since +the second stage is bound tightly to both other stages (which are +independent from each other), it is referred to as stage 1.5, whereas +the other stages are referred to as stage 1 and 2. This architecture is +used because the BIOS booting process only loads a very small piece of +code from disk for booting, insufficient for the needs outlined above. + +The following will explain all stages in detail. + +Stage 1 +~~~~~~~ + +The first stage is responsible for loading the real boot loader from a +BFS disk. It will be loaded by the Master Boot Record (MBR) and executed +in the x86 real mode. It is only used if the system will be booted +directly from a BFS partition, it won't be used at all if it is booted +from a floppy disk or CD-ROM (in this case, stage 1.5 is in charge +immediately). + +| It resides in the first 1024 bytes of a BFS disk which usually refers + to the first two sectors of the partition in question. Since the BFS + superblock is located at byte offset 512, and about 170 bytes large, + this section is already reserved, and thus cannot be used by the + loader itself. +| The MBR only loads the first sector of a partition into memory, so it + has to load the superblock (and the rest of its implementation) by + itself. + +| The loader must be able to load the real boot loader from a certain + path, and execute it. In BeOS this boot loader would be in + "/boot/beos/system/zbeos", in Haiku this is haiku_loader.bios_ia32 + found in the haiku_loader package. +| Theoretically, it is enough to load the first few blocks from the + loader, and let the next stage then load the whole thing (which it has + to do anyway if it has been written on a floppy). This would be one + possible optimization if the 850 bytes of space are filled too early, + but would require that "zbeos" is written in one sequential block + (which should be always the case anyway). + +haiku_loader.bios_ia32 +~~~~~~~~~~~~~~~~~~~~~~ + +Contains both the stage 1.5 boot loader, and the compressed stage 2 +loader. It's not an ELF executable file; i.e. it can be directly written +to a floppy disk which would cause the BIOS to load the first 512 bytes +of that file and execute it. + +Therefore, it will start with the stage 1.5 boot loader which will be +loaded either by the BIOS when it directly resides on the disk (for +example when loaded from a floppy disk), or the stage 1 boot loader, +although this one could have a different entry point than the BIOS. + +Stage 1.5 +~~~~~~~~~ + +Will have to load the rest of haiku_loader into memory (if not already +done by the stage 1 loader in case it has been loaded from a BFS disk), +set up the global descriptor table, switch to x86 protected mode, +uncompress stage 2, and execute it. + +This part is very similar to the stage 1 boot loader from NewOS. + +Stage 2 +~~~~~~~ + +This is the most complex part of the boot loader. In short, it has to +load any modules and devices the kernel needs to access the boot device, +set up the system, load the kernel, and execute it. + +The kernel, and the modules and drivers needed are loaded from the boot +disk - therefore the loader has to be able to access BFS disks. It also +has to be able to load and parse the settings of these drivers (and the +kernel) from the boot disk, some of them are already important for the +boot loader itself (like "don't call the BIOS"). Since this stage is +already executed in protected mode, it has to use the virtual-86 mode to +call the BIOS and access any disk. + +Before loading those files from the boot disk, it should look for +additional files located on a specific disk location after the "zbeos" +file (on floppy disk or CD-ROM). This way, it could access disks that +cannot be accessed by the BIOS itself. + +Setting up the system for the kernel also means initalizing PCI devices +needed during the boot process before the kernel is up. It must be able +to do so since the BIOS might not have set up those devices correctly or +at all. + +It also must calculate a check sum for the boot device which the kernel +can then use to identify the boot volume and partition with - there is +no other reliable way to map BIOS disk IDs to the /dev/disk/... tree the +system itself is using. + +After having loaded and relocated the kernel, it executes it by passing +a special structure which tells the kernel things like the boot device +check sum, which modules are already loaded and where they are. + +The stage 2 boot loader also includes user interaction. If the user +presses a special key during the boot process (like the space key, or +some others as well), a menu will be presented where the user can select +the boot device (if several, the loader has to scan for options), safe +mode options, VESA mode, etc. + +This menu may also come up if an error occured during the execution of +the stage 2 loader. + +Open Firmware +------------- + +On Open Firmware based systems, there is no need for a stage 1.5 because +the firmware does not give us as many constraints. Instead, the stage 2 +is loaded directly by the firmware. This requires converting the +haiku_loader executable to the appropriate executable format (a.out on +sparc, pef on powerpc). The conversion is done using custom tools +because binutils does not support these formats anymore. + +There is no notion of real and protected mode on non-x86 architectures, +and the bootloader is able to easily call Open Firmware methods to +perform most tasks (disk access, network booting, setting up the +framebuffer) in a largely hardware-independent way. + +U-Boot +------ + +U-Boot is able to load the stage2 loader directly from an ELF file. +However, it does not provide any other features. It is not possible for +the bootloader to call into U-Boot APIs for disk access, displaying +messages on screen etc (while possible in theory, these features are +often disabled in U-Boot). This means haiku_loader would need to parse +the FDT (describing the available hardware) and bundle its own drivers +for using the hardware. This approach is not easy to set up, and it is +recommended to instead use the UEFI support in U-Boot where possible. + +EFI +--- + +On EFI systems, there is no need for a stage1 loader as there is for +BIOS. Instead, our stage2 loader (haiku_loader) can be executed directly +from the EFI firmware. + +The EFI firmware only knows how to run executables in the PE format (as +used by Windows) because Microsoft was involved in specifying it. On +x86_64, we can use binutils to output a PE file directly. But on other +platforms, this is not supported by binutils. So, what we do is generate +a "fake" PE header and wrap our elf file inside it. The bootloader then +parses the embedded ELF header and relocates itself, so the other parts +of the code can be run. + +After this initial loading phase, the process is very similar to the +Open Firmware one. EFI provides us with all the tools we need to do disk +access and both text mode and framebuffer output. diff --git a/docs/develop/kernel/device_manager_introduction.html b/docs/develop/kernel/device_manager_introduction.html deleted file mode 100644 index 57a215d9eb..0000000000 --- a/docs/develop/kernel/device_manager_introduction.html +++ /dev/null @@ -1,315 +0,0 @@ - - - -

Introduction to Haiku's Device Driver Architecture

- -

This document tries to give you a short introduction into the new device -manager, and how to write drivers for it. Haiku still supports the legacy -device driver architecture introduced with BeOS.

- -

The new device driver architecture of Haiku is still a moving target, -although most of its details are already specificed.

- - -

1. The Basics

- -

The device manager functionality builds upon device_node objects. -Every driver in the system publishes one or more of such nodes, building a -tree of device nodes. This tree is in theory a dynamic representation of the -current hardware devices in the system, but in practice will also contain -implementation specific details; since every node comes with an API specific -to that node, you'll find device nodes that only come with a number of support -functions for a certain class of drivers.

- -

Structurally, a device_node is a set of a module, attributes, -and resources, as well as a parent and children. At a minimum, a node must -have a module, all other components are optional.

- -TODO: picture of the device node tree - -

When the system starts, there is only a root node registered. Only primary -hardware busses register with the root node, such as PCI, and ISA on x86. -Since the PCI bus is an intelligent bus, it knows what hardware is installed, -and registers a child node for each device on the bus.

- -

Every driver can also publish a device in /dev for communication with -userland applications. All drivers and devices are kernel modules.

- - -

2. Exploring the Device Tree

- -

So how does it all work? When building the initial device tree, the system only -explores a minimum of device drivers only, resulting in a tree that basically -only shows the hardware found in the computer.

- -

Now, if the system requires disk access, it will scan the device file system -for a driver that provides such functionality, in this case, it will look for -drivers under "/dev/disk/". The device manager has a set of built-in rules for -how to translate a device path into a device node, and vice versa: every node -representing a device of an intelligent bus (such as PCI) will also contain -device type information following the PCI definitions. In this case, the "disk" -sub-path will translate into the PCI_mass_storage type, and hence, the -device manager will then completely explore all device nodes of that type.

- -

It will also use that path information to only ask drivers that actually -are in a matching module directory. In the above example of a disk driver, this -would be either in "busses/scsi", "busses/ide", "drivers/disk", ...

- -

For untyped or generic busses, it will use the context information gained -from the devfs query directly, and will search for drivers in that sub directory -only. The only exception to this rule are the devfs directories "disk", "ports", -and "bus", which will also allow to search matching drivers in "busses". While -this is relatively limited, it is a good way to cut down the number of drivers -to be loaded.

- - -

3. Writing a Driver

- -

The device manager assumes the following API from a driver module:

-
    -
  • supports_device()
    - Determines wether or not the driver supports a given parent device node, - that is the hardware device it represents (if any), and the API the node - exports.
  • -
  • register_device()
    - The driver should register its device node here. The parent driver is - always initialized at this point. When registering the node, the driver - can also attach certain I/O resources (like I/O ports, or memory ranges) - to the node -- the device manager will make sure that only one node can - claim these resources.
  • -
  • init_driver()
    - Any initialization necessary to get the driver going. For most drivers, - this will be reduced to the creation of a private data structure that is - going to be used for all of the following functions.
  • -
  • uninit_driver()
    - Uninitializes resources acquired by init_driver().
  • -
  • register_child_devices()
    - If the driver wants to register any child device nodes or to publish - any devices, it should do so here. This function is called only during - the initial registration process of the device node.
  • -
  • rescan_child_devices()
    - Is called whenever a manual rescan is triggered.
  • -
  • device_removed()
    - Is called when the device node is about to be unregistered when its - device is gone, for example when a USB device is unplugged.
  • -
  • suspend()
    - Enters different sleep modes.
  • -
  • resume()
    - Resumes a device from a previous sleep mode.
  • -
- -

To ensure that a module exports this API, it must end its module name -with "driver_v1" to denote the version of the API it supports. Note that -suspend() and resume() are currently never called, as Haiku has -no power management implemented yet.

- -

If your driver can give the device it is attached to a nice name that can be -presented to the user, it should add the B_DEVICE_PRETTY_NAME attribute -to the device node. - -

The B_DEVICE_UNIQUE_ID should be used in case the device has a unique -ID that can be used to identify it, and also differentiate it from other devices -of the same model and vendor. This information will be added to the file system -attributes of all devices published by your driver, so that user applications -can identify, say, a USB printer no matter what USB slot it is attached to, and -assign it additional data, like paper configuration, or recognize it as the -default printer.

- -

If your driver implements an API that is used by a support or bus module, you -will usually use the B_DEVICE_FIXED_CHILD attribute to specify exactly -which child device node you will be talking to. If you support several child -nodes, you may want to have a closer look at the section explaining -how to write a bus driver.

- -

In addition to the child nodes a driver registers itself, a driver can either -have dynamic children or fixed children, never both. Also, fixed children are -registered before register_child_devices() is called, while dynamic -children are registered afterwards.

- - -

4. Publishing a Device

- -To publish a device entry in the device file system under /dev, all your -driver has to do is to call the -
-	publish_device(device_node *node, const char *path,
-		const char *deviceModuleName);
-
-function the device manager module exports. The path is the path -component that follows "/dev", for example "net/ipro1000/0". The -deviceModuleName is the module exporting the device functionality. -It should end with "device_v1" to show the device manager which protocol it -supports. If the device node your device belongs to is removed, your device -is removed automatically with it. On the other hand, you are allowed to -unpublish the device at any point using the unpublish_device() function -the device manager delivers for this.

- -

A device module must export the following API:

-
    -
  • init_device()
    - This is called when the open() is called on this device for the first - time. You may want to create a private data structure that is passed on - to all subsequent calls of the open() function that your device - exports.
  • -
  • uninit_device()
    - Is called when the last file descriptor to the device had been closed.
  • -
  • device_removed()
    - When the device node your device belongs to is going to be removed, - you're notified about this in this function.
  • -
  • open()
    - Called whenever your device is opened.
  • -
  • close()
    -
  • -
  • free()
    - Free the private data structure you allocated in open().
  • -
  • read()
    -
  • -
  • write()
    -
  • -
  • io()
    - This is a replacement for the read(), and write() calls, - and allows, among other things, for asynchronous I/O. This functionality - has not yet been implemented, though (see below).
  • -
  • control()
    -
  • -
  • select()
    -
  • -
  • deselect()
    -
  • -
- - -

5. Writing a Bus Driver

- -

A bus driver is a driver that represents a bus where one or more arbitrary -devices can be attached to.

- -

There are two basic types of busses: intelligent busses like PCI or USB that -know a lot about the devices attached to it, like a generic device type, as -well as device and vendor ID information, and simple untyped/generic busses that -either have not all the information (like device type) or don't even know what -and if any devices are attached. The device manager has been written in such a -way that device exploration makes use of additional information the bus can -provide in order to find a responsible device driver faster, and with less -overhead.

- -

5.1. Writing an Intelligent Bus Driver

- -

If your bus knows what type of device is attached to, and also has vendor and -device ID information about that device, it is considered to be an intelligent -bus. The bus driver is supposed to have one parent node representing the bus, -and to create a child node for each device attached to the bus.

- -

The additional information you have about the devices are attached to the -device node in the following attributes:

-
    -
  • B_DEVICE_VENDOR_ID
    - The vendor ID - this ID has only to be valid in the namespace of your - bus.
  • -
  • B_DEVICE_ID
    - The device ID.
  • -
  • B_DEVICE_TYPE
    - The device type as defined by the PCI class base information.
  • -
  • B_DEVICE_SUB_TYPE
    - The device sub type as defined by the PCI sub class information.
  • -
  • B_DEVICE_INTERFACE
    - The device interface type as defined by the PCI class API information.
  • -
- -

You can use the B_DEVICE_FLAGS attribute to define how the device -manager finds the children of the devices you exported. For this kind of bus -drivers, you will usually only want to specify B_FIND_CHILD_ON_DEMAND -here, which causes the driver only to be searched when the system asks for it. -

- -

5.2. Writing a Simple Bus Driver

- -

A bus can be simple in a number of ways:

-
    -
  1. It may not know how many or if any devices are attached to it
  2. -
  3. It cannot retrieve any type information about the devices it has, but - knows all devices that are attached to it
  4. -
- -

An example of the latter would be the Zorro bus of the Amiga - it only has -information about the vendor and device ID, but no type information. It should -be implemented like an intelligent bus, though, with the type information simply -omitted.

- -

Therefore, this section is about the former case, that is, a simple bus like -the ISA bus. Since it doesn't know anything about its children, it does not -publish any child nodes, instead, it will just specify the -B_FIND_MULTIPLE_CHILDREN and B_FIND_CHILD_ON_DEMAND flags for its device node. -Since there is no additional information about this bus, the device manager -will assume a simple bus, and will try to find drivers on demand only.

- -

The generic bus

- -Some devices are not tied to a specific bus. This is the case for all drivers -that do not relate to a physical device: /dev/null, /dev/zero, /dev/random, -etc. - -A "generic" bus has been added, and these drivers can attach to it. - -

6. Open Issues

- -While most of the new device manager is fledged out, there are some areas that -could use improvements or are problematic under certain requirements. Also, some -parts just haven't been written yet. - -

6.1. generic/simple busses

- -

6.2. Unpublishing

- -

6.4. Versioning

- -

The way the device manager works, it makes versioning of modules (which are -supposed to be one of the strong points of the module system) much harder or -even impossible. While the device manager could introduce a new API and could -translate between a "driver_v1", and a "driver_v2" API on the fly, it's not -yet possible for a PCI sub module to do the same thing.

- -

Proposed Solution: Add attribute B_DEVICE_ALTERNATE_VERSION -that specifies alternate versions of the module API this device node supports. -We would then need a request_version() or set_version() function -(to be called from supports_device()) that allows to specify the version -of the parent node this device node wants to talk to.

- -

6.5. Unregistering Nodes

- -

6.6. Support for generic drivers is missing

- -

This should probably be done by simply adding a simple bus driver named -"generic" that generic drivers need to ask for.

- -

6.7. Mappings, And Other Optimizations

- -

Due to the way the device tree is built, the device manager could remember -which driver served a given device node. That way, it wouldn't need to search -for a driver anymore, but could just pick it up. Practically, the device manager -should cache the type (and/or vendor/device) information of a node, and assign -one or more drivers (via module name) to this information. It should also -remember negative outcome, that is if there is no driver supporting the -hardware.

- -

This way, only the first boot would require an actual search for drivers, as -subsequent boots would reuse the type-driver assignments. If a new driver is -installed, the cached assignments would need to be updated immediately. If a -driver has been installed outside of the running system, the device manager -might want to create a hash per module directory to see if anything changed to -flush the cache. Alternatively or additionally, the boot loader could have a -menu causing the cache to be ignored.

- -

It would be nice to find a way for generic and simple busses to reduce the -amount of searching necessary for them. One way would be to remember which -driver supports which bus - but this information is currently only accessible -derived from what the driver does, and is therefore not reliable or complete. -A separately exported information would be necessary for this.

- -

Also, when looking for a generic or simple bus driver, actual directories -could be omitted; currently, driver search is always recursive, as that's how -the module mechanism is working. Eventually, we might want to extend the -open_module_list_etc() call a bit more to accomplish that.

- - - diff --git a/docs/develop/kernel/device_manager_introduction.rst b/docs/develop/kernel/device_manager_introduction.rst new file mode 100644 index 0000000000..93128aff2c --- /dev/null +++ b/docs/develop/kernel/device_manager_introduction.rst @@ -0,0 +1,325 @@ +Device Driver Architecture +================================================== + +This document tries to give you a short introduction into the new device +manager, and how to write drivers for it. Haiku still supports the +legacy device driver architecture introduced with BeOS. + +The new device driver architecture of Haiku is still a moving target, +although most of its details are already specificed. + +1. The Basics +------------- + +The device manager functionality builds upon *device_node* objects. +Every driver in the system publishes one or more of such nodes, building +a tree of device nodes. This tree is in theory a dynamic representation +of the current hardware devices in the system, but in practice will also +contain implementation specific details; since every node comes with an +API specific to that node, you'll find device nodes that only come with +a number of support functions for a certain class of drivers. + +Structurally, a *device_node* is a set of a module, attributes, and +resources, as well as a parent and children. At a minimum, a node must +have a module, all other components are optional. + +TODO: picture of the device node tree + +When the system starts, there is only a root node registered. Only +primary hardware busses register with the root node, such as PCI, and +ISA on x86. Since the PCI bus is an intelligent bus, it knows what +hardware is installed, and registers a child node for each device on the +bus. + +Every driver can also publish a device in */dev* for communication with +userland applications. All drivers and devices are kernel modules. + +2. Exploring the Device Tree +---------------------------- + +So how does it all work? When building the initial device tree, the +system only explores a minimum of device drivers only, resulting in a +tree that basically only shows the hardware found in the computer. + +Now, if the system requires disk access, it will scan the device file +system for a driver that provides such functionality, in this case, it +will look for drivers under "/dev/disk/". The device manager has a set +of built-in rules for how to translate a device path into a device node, +and vice versa: every node representing a device of an intelligent bus +(such as PCI) will also contain device type information following the +PCI definitions. In this case, the "disk" sub-path will translate into +the *PCI_mass_storage* type, and hence, the device manager will then +completely explore all device nodes of that type. + +It will also use that path information to only ask drivers that actually +are in a matching module directory. In the above example of a disk +driver, this would be either in "busses/scsi", "busses/ide", +"drivers/disk", ... + +For untyped or generic busses, it will use the context information +gained from the devfs query directly, and will search for drivers in +that sub directory only. The only exception to this rule are the devfs +directories "disk", "ports", and "bus", which will also allow to search +matching drivers in "busses". While this is relatively limited, it is a +good way to cut down the number of drivers to be loaded. + +3. Writing a Driver +------------------- + +The device manager assumes the following API from a driver module: + +- **supports_device()** + Determines wether or not the driver supports a given parent device + node, that is the hardware device it represents (if any), and the API + the node exports. +- **register_device()** + The driver should register its device node here. The parent driver is + always initialized at this point. When registering the node, the + driver can also attach certain I/O resources (like I/O ports, or + memory ranges) to the node -- the device manager will make sure that + only one node can claim these resources. +- **init_driver()** + Any initialization necessary to get the driver going. For most + drivers, this will be reduced to the creation of a private data + structure that is going to be used for all of the following + functions. +- **uninit_driver()** + Uninitializes resources acquired by **init_driver()**. +- **register_child_devices()** + If the driver wants to register any child device nodes or to publish + any devices, it should do so here. This function is called only + during the initial registration process of the device node. +- **rescan_child_devices()** + Is called whenever a manual rescan is triggered. +- **device_removed()** Is called when the device node is about to be + unregistered when its device is gone, for example when a USB device + is unplugged. +- **suspend()** + Enters different sleep modes. +- **resume()** + Resumes a device from a previous sleep mode. + +To ensure that a module exports this API, it **must** end its module +name with "driver_v1" to denote the version of the API it supports. Note +that **suspend()** and **resume()** are currently never called, as Haiku +has no power management implemented yet. + +If your driver can give the device it is attached to a nice name that +can be presented to the user, it should add the **B_DEVICE_PRETTY_NAME** +attribute to the device node. + +The **B_DEVICE_UNIQUE_ID** should be used in case the device has a +unique ID that can be used to identify it, and also differentiate it +from other devices of the same model and vendor. This information will +be added to the file system attributes of all devices published by your +driver, so that user applications can identify, say, a USB printer no +matter what USB slot it is attached to, and assign it additional data, +like paper configuration, or recognize it as the default printer. + +If your driver implements an API that is used by a support or bus +module, you will usually use the **B_DEVICE_FIXED_CHILD** attribute to +specify exactly which child device node you will be talking to. If you +support several child nodes, you may want to have a closer look at the +section explaining `how to write a bus driver <#bus_driver>`__. + +In addition to the child nodes a driver registers itself, a driver can +either have dynamic children or fixed children, never both. Also, fixed +children are registered before **register_child_devices()** is called, +while dynamic children are registered afterwards. + +4. Publishing a Device +---------------------- + +To publish a device entry in the device file system under */dev*, all +your driver has to do is to call the + +:: + + publish_device(device_node *node, const char *path, + const char *deviceModuleName); + +function the device manager module exports. The *path* is the path +component that follows "/dev", for example "net/ipro1000/0". The +*deviceModuleName* is the module exporting the device functionality. It +should end with "device_v1" to show the device manager which protocol it +supports. If the device node your device belongs to is removed, your +device is removed automatically with it. On the other hand, you are +allowed to unpublish the device at any point using the +**unpublish_device()** function the device manager delivers for this. + +A device module must export the following API: + +- **init_device()** + This is called when the open() is called on this device for the first + time. You may want to create a private data structure that is passed + on to all subsequent calls of the **open()** function that your + device exports. +- **uninit_device()** + Is called when the last file descriptor to the device had been + closed. +- **device_removed()** + When the device node your device belongs to is going to be removed, + you're notified about this in this function. +- **open()** + Called whenever your device is opened. +- **close()** +- **free()** + Free the private data structure you allocated in **open()**. +- **read()** +- **write()** +- **io()** + This is a replacement for the **read()**, and **write()** calls, and + allows, among other things, for asynchronous I/O. This functionality + has not yet been implemented, though (see below). +- **control()** +- **select()** +- **deselect()** + +5. Writing a Bus Driver +----------------------- + +A bus driver is a driver that represents a bus where one or more +arbitrary devices can be attached to. + +There are two basic types of busses: intelligent busses like PCI or USB +that know a lot about the devices attached to it, like a generic device +type, as well as device and vendor ID information, and simple +untyped/generic busses that either have not all the information (like +device type) or don't even know what and if any devices are attached. +The device manager has been written in such a way that device +exploration makes use of additional information the bus can provide in +order to find a responsible device driver faster, and with less +overhead. + +5.1. Writing an Intelligent Bus Driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If your bus knows what type of device is attached to, and also has +vendor and device ID information about that device, it is considered to +be an intelligent bus. The bus driver is supposed to have one parent +node representing the bus, and to create a child node for each device +attached to the bus. + +The additional information you have about the devices are attached to +the device node in the following attributes: + +- **B_DEVICE_VENDOR_ID** + The vendor ID - this ID has only to be valid in the namespace of your + bus. +- **B_DEVICE_ID** + The device ID. +- **B_DEVICE_TYPE** + The device type as defined by the PCI class base information. +- **B_DEVICE_SUB_TYPE** + The device sub type as defined by the PCI sub class information. +- **B_DEVICE_INTERFACE** + The device interface type as defined by the PCI class API + information. + +You can use the **B_DEVICE_FLAGS** attribute to define how the device +manager finds the children of the devices you exported. For this kind of +bus drivers, you will usually only want to specify +**B_FIND_CHILD_ON_DEMAND** here, which causes the driver only to be +searched when the system asks for it. + +5.2. Writing a Simple Bus Driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A bus can be simple in a number of ways: + +#. It may not know how many or if any devices are attached to it +#. It cannot retrieve any type information about the devices it has, but + knows all devices that are attached to it + +An example of the latter would be the Zorro bus of the Amiga - it only +has information about the vendor and device ID, but no type information. +It should be implemented like an intelligent bus, though, with the type +information simply omitted. + +Therefore, this section is about the former case, that is, a simple bus +like the ISA bus. Since it doesn't know anything about its children, it +does not publish any child nodes, instead, it will just specify the +B_FIND_MULTIPLE_CHILDREN and B_FIND_CHILD_ON_DEMAND flags for its device +node. Since there is no additional information about this bus, the +device manager will assume a simple bus, and will try to find drivers on +demand only. + +The generic bus +--------------- + +Some devices are not tied to a specific bus. This is the case for all +drivers that do not relate to a physical device: /dev/null, /dev/zero, +/dev/random, etc. A "generic" bus has been added, and these drivers can +attach to it. + +6. Open Issues +-------------- + +While most of the new device manager is fledged out, there are some +areas that could use improvements or are problematic under certain +requirements. Also, some parts just haven't been written yet. + +6.1. generic/simple busses +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +6.2. Unpublishing +^^^^^^^^^^^^^^^^^ + +6.4. Versioning +^^^^^^^^^^^^^^^ + +The way the device manager works, it makes versioning of modules (which +are supposed to be one of the strong points of the module system) much +harder or even impossible. While the device manager could introduce a +new API and could translate between a "driver_v1", and a "driver_v2" API +on the fly, it's not yet possible for a PCI sub module to do the same +thing. + +**Proposed Solution:** Add attribute **B_DEVICE_ALTERNATE_VERSION** that +specifies alternate versions of the module API this device node +supports. We would then need a **request_version()** or +**set_version()** function (to be called from **supports_device()**) +that allows to specify the version of the parent node this device node +wants to talk to. + +6.5. Unregistering Nodes +^^^^^^^^^^^^^^^^^^^^^^^^ + +6.6. Support for generic drivers is missing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This should probably be done by simply adding a simple bus driver named +"generic" that generic drivers need to ask for. + +6.7. Mappings, And Other Optimizations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Due to the way the device tree is built, the device manager could +remember which driver served a given device node. That way, it wouldn't +need to search for a driver anymore, but could just pick it up. +Practically, the device manager should cache the type (and/or +vendor/device) information of a node, and assign one or more drivers +(via module name) to this information. It should also remember negative +outcome, that is if there is no driver supporting the hardware. + +This way, only the first boot would require an actual search for +drivers, as subsequent boots would reuse the type-driver assignments. If +a new driver is installed, the cached assignments would need to be +updated immediately. If a driver has been installed outside of the +running system, the device manager might want to create a hash per +module directory to see if anything changed to flush the cache. +Alternatively or additionally, the boot loader could have a menu causing +the cache to be ignored. + +It would be nice to find a way for generic and simple busses to reduce +the amount of searching necessary for them. One way would be to remember +which driver supports which bus - but this information is currently only +accessible derived from what the driver does, and is therefore not +reliable or complete. A separately exported information would be +necessary for this. + +Also, when looking for a generic or simple bus driver, actual +directories could be omitted; currently, driver search is always +recursive, as that's how the module mechanism is working. Eventually, we +might want to extend the open_module_list_etc() call a bit more to +accomplish that. diff --git a/docs/develop/kernel/fs/node_monitoring.html b/docs/develop/kernel/fs/node_monitoring.html deleted file mode 100644 index 04afe84486..0000000000 --- a/docs/develop/kernel/fs/node_monitoring.html +++ /dev/null @@ -1,262 +0,0 @@ - - -

Node Monitoring

-
- Creation Date: January 16, 2003
- Author(s): Axel Dörfler -
- - This document describes the feature of the BeOS kernel to monitor nodes. First, - there is an explanation of what kind of functionality we have to reproduce (along - with the higher level API), then we will present the implementation in OpenBeOS. - -

Requirements - Exported Functionality in BeOS

- - From user-level, BeOS exports the following API as found in the storage/NodeMonitor.h - header file: - -
-	status_t watch_node(const node_ref *node, 
-		uint32 flags, 
-		BMessenger target);
-
-	status_t watch_node(const node_ref *node, 
-		uint32 flags, 
-		const BHandler *handler,
-		const BLooper *looper = NULL);
-
-	status_t stop_watching(BMessenger target);
-
-	status_t stop_watching(const BHandler *handler, 
-		const BLooper *looper = NULL);
-	
- - The kernel also exports two other functions to be used from file system add-ons - that causes the kernel to send out notification messages: - -
-	int notify_listener(int op, nspace_id nsid,
-		vnode_id vnida,	vnode_id vnidb,
-		vnode_id vnidc, const char *name);
-	int send_notification(port_id port, long token,
-		ulong what, long op, nspace_id nsida,
-		nspace_id nsidb, vnode_id vnida,
-		vnode_id vnidb, vnode_id vnidc,
-		const char *name);
-	
- -

- The latter is only used for live query updates, but is obviously called by - the former. The port/token pair identify a unique BLooper/BHandler pair, and - it used internally to address those high-level objects from the kernel. -

-

- When a file system calls the notify_listener() function, it will have - a look if there are monitors for that node which meet the specified constraints - - and it will call send_notification() for every single message to be send. -

-

- Each of the parameters vnida - vnidc has a dedicated meaning: -

    -
  • vnida: the parent directory of the "main" node
  • -
  • vnidb: the target parent directory for a move
  • -
  • vnidc: the node that has triggered the notification to be send
  • -
-

-

- The flags parameter in watch_node() understands the following constants: -

-
    -
  • B_STOP_WATCHING
    - watch_node() will stop to watch the specified node.
  • -
  • B_WATCH_NAME
    - name changes are notified through a B_ENTRY_MOVED opcode.
  • -
  • B_WATCH_STAT
    - changes to the node's stat structure are notified with a B_STAT_CHANGED code.
  • -
  • B_WATCH_ATTR
    - attribute changes will cause a B_ATTR_CHANGED to be send.
  • -
  • B_WATCH_DIRECTORY
    - notifies on changes made to the specified directory, i.e. B_ENTRY_REMOVED, B_ENTRY_CREATED
  • -
  • B_WATCH_ALL
    - is a short-hand for the flags above.
  • -
  • B_WATCH_MOUNT
    - causes B_DEVICE_MOUNTED and B_DEVICE_UNMOUNTED to be send.
  • -
-

- Node monitors are maintained per team - every team can have up to 4096 monitors, although - there exists a private kernel call to raise this limit (for example, Tracker is using it - intensively). -

-

- The kernel is able to send the BMessages directly to the specified BLooper and BHandler; - it achieves this using the application kit's token mechanism. The message is constructed - manually in the kernel, it doesn't use any application kit services. -

-
- -

Meeting the Requirements in an Optimal Way - Implementation in OpenBeOS

- -

- If you assume that every file operation could trigger a notification message to be send, - it's clear that the node monitoring system must be optimized for sending messages. For - every call to notify_listener(), the kernel must check if there are any - monitors for the node that was updated. -

-

- Those monitors are put into a hash table which has the device number and the vnode ID - as keys. Each of the monitors maintains a list of listeners which specify which port/token - pair should be notified for what change. Since the vnodes are created/deleted as needed - from the kernel, the node monitor is maintained independently from them; a simple pointer - from a vnode to its monitor is not possible. -

-

- The main structures that are involved in providing the node monitoring functionality - look like this: -

- -
-	struct monitor_listener {
-		monitor_listener	*next;
-		monitor_listener	*prev;
-		list_link		monitor_link;
-		port_id			port;
-		int32			token;
-		uint32			flags;
-		node_monitor		*monitor;
-	};
-
-	struct node_monitor {
-		node_monitor		*next;
-		mount_id		device;
-		vnode_id		node;
-		struct list		listeners;
-	};
-	
- -

- The relevant part of the I/O context structure is this: -

- -
-	struct io_context {
-		...
-		struct list		node_monitors;
-		uint32			num_monitors;
-		uint32			max_monitors;
-	};
-	
- -

- If you call watch_node() on a file with a flags parameter unequal to - B_STOP_WATCHING, the following will happen in the node monitor: -

-
    -
  1. The add_node_monitor() function does a hash lookup for the - device/vnode pair. If there is no node_monitor yet for this pair, - a new one will be created.
  2. -
  3. The list of listeners is scanned for the provided port/token pair (the - BLooper/BHandler pointer will already be translated in user-space), and - the new flag is or'd to the old field, or a new monitor_listener - is created if necessary - in the latter case, the team's node monitor - counter is incremented.
  4. -
-

- If it's called with B_STOP_WATCHING defined, the reverse operation take effect, and - the monitor field is used to see if this monitor don't have any listeners - anymore, in which case it will be removed. -

-

- Note the presence of the max_monitors - there is no hard limit the kernel - exposes to userland applications; the listeners are maintained in a doubly-linked list. -

-

- If a team is shut down, all listeners from its I/O context will be removed - since every - listener stores a pointer to its monitor, determining the monitors that can be removed - because of this operation is very cheap. -

-

- The notify_listener() also only does a hash lookup for the device/node - pair it got from the file system, and sends out as many notifications as specified by - the listeners of the monitor that belong to that node. -

-

- If a node is deleted from the disk, the corresponding node_monitor and its - listeners will be removed as well, to prevent watching a new file that accidently happen - to have the same device/node pair (as is possible with BFS, for example). -

- -
-

Differences Between Both Implementations

- -

- Although the aim was to create a completely compatible monitoring implementation, - there are some notable differences between the two. -

-

- BeOS reserves a certain number of slots for calls to watch_node() - each - call to that function will use one slot, even if you call it twice for the same node. - OpenBeOS, however, will always use one slot per node - you could call watch_node() - several times, but you would waste only one slot. -

-

- While this is an implementational detail, it also causes a change in behaviour for - applications; in BeOS, applications will get one message for every watch_node() - call, in OpenBeOS, you'll get only one message per node. If an application relies - on this strange behaviour of the BeOS kernel, it will no longer work correctly. -

-

- The other difference is that OpenBeOS exports its node monitoring functionality to - kernel modules as well, and provides an extra plain C API for them to use. -

- -
-

And Beyond?

- -

- The current implementation directly iterates over all listeners and sends out notifications - as required synchronously in the context of the thread that triggered the notification to - be sent. -

-

- If a node monitor needs to send out several messages, this could theoretically greatly - decrease file system performance. To optimize for this case, the required data of the - notification could be put into a queue and be sent by a dedicated worker thread. Since - this requires an additional copy operation and a reserved address space for this queue, - this optimization could be more expensive than the current implementation, depending - on the usage pattern of the node monitoring mechanism. -

-

- With BFS, it would be possible to introduce the possibility to automatically watch all - files in a specified directory. While this would be very convenient at application level, - it comes with several disadvantages: -

-
    -
  1. This feature might not be easily accomplishable for many file systems; a file system - must be able to retrieve a node by ID only - it might not be feasible to find - out about the parent directory for many file systems.
  2. -
  3. Although it could potentially safe node monitors, it might cause the kernel to - send out a lot more messages to the application than it needs. With the restriction - the kernel imposes to the number of watched nodes for a team, the application's - designer might try to be much stricter with the number of monitors his application - will consume.
  4. -
-

- While 1.) might be a real show stopper, 2.) is almost invalidated because of Tracker's - usage of node monitors; it consumes a monitor for every entry it displays, which might - be several thousands. Implementing this feature would not only greatly speed up maintaining - this massive need of monitors, and cut down memory usage, but also ease the implementation - at application level. -

-

- Even 1.) could be solved if the kernel could query a file system if it can support - this particular feature; it could then automatically monitor all files in that directory - without adding complexity to the application using this feature. Of course, - the effort to provide this functionality is much larger then - but for applications - like Tracker, the complexity would be removed from the application without extra cost. -

-

- However, none of the discussed feature extensions have been implemented for the currently - developed version R1 of OpenBeOS. -

- - diff --git a/docs/develop/kernel/fs/node_monitoring.rst b/docs/develop/kernel/fs/node_monitoring.rst new file mode 100644 index 0000000000..8e373998a7 --- /dev/null +++ b/docs/develop/kernel/fs/node_monitoring.rst @@ -0,0 +1,257 @@ +Node Monitoring +=============== + +Creation Date: January 16, 2003 +Author(s): Axel Dörfler + + +This document describes the feature of the BeOS kernel to monitor nodes. +First, there is an explanation of what kind of functionality we have to +reproduce (along with the higher level API), then we will present the +implementation in OpenBeOS. + +Requirements - Exported Functionality in BeOS +--------------------------------------------- + +From user-level, BeOS exports the following API as found in the +storage/NodeMonitor.h header file: + +:: + + status_t watch_node(const node_ref *node, + uint32 flags, + BMessenger target); + + status_t watch_node(const node_ref *node, + uint32 flags, + const BHandler *handler, + const BLooper *looper = NULL); + + status_t stop_watching(BMessenger target); + + status_t stop_watching(const BHandler *handler, + const BLooper *looper = NULL); + + +The kernel also exports two other functions to be used from file system +add-ons that causes the kernel to send out notification messages: + +:: + + int notify_listener(int op, nspace_id nsid, + vnode_id vnida, vnode_id vnidb, + vnode_id vnidc, const char *name); + int send_notification(port_id port, long token, + ulong what, long op, nspace_id nsida, + nspace_id nsidb, vnode_id vnida, + vnode_id vnidb, vnode_id vnidc, + const char *name); + + +The latter is only used for live query updates, but is obviously called +by the former. The port/token pair identify a unique BLooper/BHandler +pair, and it used internally to address those high-level objects from +the kernel. + +When a file system calls the ``notify_listener()`` function, it will +have a look if there are monitors for that node which meet the specified +constraints - and it will call ``send_notification()`` for every single +message to be send. + +Each of the parameters ``vnida - vnidc`` has a dedicated meaning: + +- **vnida:** the parent directory of the "main" node +- **vnidb:** the target parent directory for a move +- **vnidc:** the node that has triggered the notification to be send + +The flags parameter in ``watch_node()`` understands the following +constants: + +- **B_STOP_WATCHING** + watch_node() will stop to watch the specified node. +- **B_WATCH_NAME** + name changes are notified through a B_ENTRY_MOVED opcode. +- **B_WATCH_STAT** + changes to the node's stat structure are notified with a + B_STAT_CHANGED code. +- **B_WATCH_ATTR** + attribute changes will cause a B_ATTR_CHANGED to be send. +- **B_WATCH_DIRECTORY** + notifies on changes made to the specified directory, i.e. + B_ENTRY_REMOVED, B_ENTRY_CREATED +- **B_WATCH_ALL** + is a short-hand for the flags above. +- **B_WATCH_MOUNT** + causes B_DEVICE_MOUNTED and B_DEVICE_UNMOUNTED to be send. + +Node monitors are maintained per team - every team can have up to 4096 +monitors, although there exists a private kernel call to raise this +limit (for example, Tracker is using it intensively). + +The kernel is able to send the BMessages directly to the specified +BLooper and BHandler; it achieves this using the application kit's token +mechanism. The message is constructed manually in the kernel, it doesn't +use any application kit services. + +| + +Meeting the Requirements in an Optimal Way - Implementation in OpenBeOS +----------------------------------------------------------------------- + +If you assume that every file operation could trigger a notification +message to be send, it's clear that the node monitoring system must be +optimized for sending messages. For every call to ``notify_listener()``, +the kernel must check if there are any monitors for the node that was +updated. + +Those monitors are put into a hash table which has the device number and +the vnode ID as keys. Each of the monitors maintains a list of listeners +which specify which port/token pair should be notified for what change. +Since the vnodes are created/deleted as needed from the kernel, the node +monitor is maintained independently from them; a simple pointer from a +vnode to its monitor is not possible. + +The main structures that are involved in providing the node monitoring +functionality look like this: + +:: + + struct monitor_listener { + monitor_listener *next; + monitor_listener *prev; + list_link monitor_link; + port_id port; + int32 token; + uint32 flags; + node_monitor *monitor; + }; + + struct node_monitor { + node_monitor *next; + mount_id device; + vnode_id node; + struct list listeners; + }; + + +The relevant part of the I/O context structure is this: + +:: + + struct io_context { + ... + struct list node_monitors; + uint32 num_monitors; + uint32 max_monitors; + }; + + +If you call ``watch_node()`` on a file with a flags parameter unequal to +B_STOP_WATCHING, the following will happen in the node monitor: + +#. The ``add_node_monitor()`` function does a hash lookup for the + device/vnode pair. If there is no ``node_monitor`` yet for this pair, + a new one will be created. +#. The list of listeners is scanned for the provided port/token pair + (the BLooper/BHandler pointer will already be translated in + user-space), and the new flag is or'd to the old field, or a new + ``monitor_listener`` is created if necessary - in the latter case, + the team's node monitor counter is incremented. + +If it's called with B_STOP_WATCHING defined, the reverse operation take +effect, and the ``monitor`` field is used to see if this monitor don't +have any listeners anymore, in which case it will be removed. + +Note the presence of the ``max_monitors`` - there is no hard limit the +kernel exposes to userland applications; the listeners are maintained in +a doubly-linked list. + +If a team is shut down, all listeners from its I/O context will be +removed - since every listener stores a pointer to its monitor, +determining the monitors that can be removed because of this operation +is very cheap. + +The ``notify_listener()`` also only does a hash lookup for the +device/node pair it got from the file system, and sends out as many +notifications as specified by the listeners of the monitor that belong +to that node. + +If a node is deleted from the disk, the corresponding ``node_monitor`` +and its listeners will be removed as well, to prevent watching a new +file that accidently happen to have the same device/node pair (as is +possible with BFS, for example). + +| + +Differences Between Both Implementations +---------------------------------------- + +Although the aim was to create a completely compatible monitoring +implementation, there are some notable differences between the two. + +BeOS reserves a certain number of slots for calls to ``watch_node()`` - +each call to that function will use one slot, even if you call it twice +for the same node. OpenBeOS, however, will always use one slot per node +- you could call ``watch_node()`` several times, but you would waste +only one slot. + +While this is an implementational detail, it also causes a change in +behaviour for applications; in BeOS, applications will get one message +for every ``watch_node()`` call, in OpenBeOS, you'll get only one +message per node. If an application relies on this strange behaviour of +the BeOS kernel, it will no longer work correctly. + +The other difference is that OpenBeOS exports its node monitoring +functionality to kernel modules as well, and provides an extra plain C +API for them to use. + +| + +And Beyond? +----------- + +The current implementation directly iterates over all listeners and +sends out notifications as required synchronously in the context of the +thread that triggered the notification to be sent. + +If a node monitor needs to send out several messages, this could +theoretically greatly decrease file system performance. To optimize for +this case, the required data of the notification could be put into a +queue and be sent by a dedicated worker thread. Since this requires an +additional copy operation and a reserved address space for this queue, +this optimization could be more expensive than the current +implementation, depending on the usage pattern of the node monitoring +mechanism. + +With BFS, it would be possible to introduce the possibility to +automatically watch all files in a specified directory. While this would +be very convenient at application level, it comes with several +disadvantages: + +#. This feature might not be easily accomplishable for many file + systems; a file system must be able to retrieve a node by ID only - + it might not be feasible to find out about the parent directory for + many file systems. +#. Although it could potentially safe node monitors, it might cause the + kernel to send out a lot more messages to the application than it + needs. With the restriction the kernel imposes to the number of + watched nodes for a team, the application's designer might try to be + much stricter with the number of monitors his application will + consume. + +While 1.) might be a real show stopper, 2.) is almost invalidated +because of Tracker's usage of node monitors; it consumes a monitor for +every entry it displays, which might be several thousands. Implementing +this feature would not only greatly speed up maintaining this massive +need of monitors, and cut down memory usage, but also ease the +implementation at application level. + +Even 1.) could be solved if the kernel could query a file system if it +can support this particular feature; it could then automatically monitor +all files in that directory without adding complexity to the application +using this feature. Of course, the effort to provide this functionality +is much larger then - but for applications like Tracker, the complexity +would be removed from the application without extra cost. + +However, none of the discussed feature extensions have been implemented +for the currently developed version R1 of OpenBeOS. diff --git a/docs/develop/kernel/obsolete_pnp_manager b/docs/develop/kernel/obsolete_pnp_manager deleted file mode 100644 index eeb9d31c79..0000000000 --- a/docs/develop/kernel/obsolete_pnp_manager +++ /dev/null @@ -1,406 +0,0 @@ -This file contains the documentation written by Thomas Kurschel that was originally -found in the headers of his pnp_manager. -It's outdated but could be used as a basis for the real documentation. - -// former pnp_manager.h -/* - Copyright (c) 2003-04, Thomas Kurschel - - PnP manager; Takes care of registration and loading of PnP drivers - - Read pnp_driver.h first to understand the basic idea behind PnP drivers. - - To register a driver node, use register_driver. If the device got lost, - use unregister_driver (note: if the parent node is removed, your node - get removed automatically as your driver has obviously nothing to work - with anymore). To get access to a (parent) device, use load_driver/ - unload_driver. - - To let the manager find a consumer (see pnp_driver.h), you can either - specify its name directly during registration, using a - PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the - appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute. - - Searching of dynamic consumers is done as follows: - - - First, the manager searches for a Specific driver in the base - directory (see below) - - If no Specific driver is found, all Generic drivers stored under - "generic" sub-directory are informed in turn until one returns success - - Finally, _all_ Universal drivers, stored in the "universal" sub- - directory, are informed - - Specification of the base directory and of the names of Specific - drivers is done via a file name pattern given by a - PNP_DRIVER_DYNAMIC_CONSUMER attribute. - - First, all substrings of the form "%attribute_name%" are replaced by the - content of the attribute "attribute_name" as follows: - - - if the attribute contains an integer value, its content is converted to hex - (lowercase) with a fixed length according to the attribute's value range - - the content of string attributes is quoted by " and invalid characters - (i.e. /%" and all characters outside 32..126) are replaced by their - unsigned decimal value, delimited by % - - other attribute types cannot be used - - Second, the resulting name is split into chunks according to the presence - of | characters (you can escape % and | with a ^ character). These - characters are only delimiters and get removed before further processing. - The directory before the first | character is the base directory (see - above). It contains the "generic" and the "universal" subdirectories. - The names of the specific drivers are created by first taking the entire - file name, then by removing the last chunk, then by removing the last - two chunks and so on until only the first chunk is left. - - As drivers can contain multiple modules, the module name is constructed - by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file - name, seperated by a slash character (note: this only applies to dynamic - consumers; for fixed consumers, you specify the module name directly via - PNP_DRIVER_FIXED_CONSUMER). - - E.g. given a dynamic consumer pattern of - "pci/vendor=%vendor_id%|, device=%device_id%" for a device with the - attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the - PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and - (if the first one fails/doesn't exist) "pci/vendor=0123". If they both - refuse to handle the device, all drivers under "pci/generic" are tried - until one accepts the device. Finally, all drivers under "pci/universal" - are loaded, whatever happened before. - - In practise, you should try to use specific drivers as much as possible. - If detection based on device IDs is impossible (e.g. because the bus - doesn't support them at all), you can put the driver under "generic". - Generic drivers can also be used to specify wrappers that try to load old- - style drivers if no new driver can be found. Also, they can be used to - report an error or invoke an user program that tries downloading a - proper Specific driver. Universal drivers are mainly used for - informational purposes, e.g. to publish data about each found device, - or to provide raw access to all devices. - - If the device uses physical address space or I/O space or ISA DMA - channels (called I/O resources), the driver has to acquire these - resources. During hardware detection (usually via probe()), - acquire_io_resources() must be called to get exclusive access. - If no hardware could be found, they must be released via - release_io_resources(). If detection was successful, the list of - the (acquired) resources must be passed to register_device(). - Resources can either belong to one hardware detection or to a device. - If a hardware detection collides with another, it has to wait; - if it collides with a device whose driver is not loaded, the - driver loading is blocked. When detection fails, i.e. if - release_io_resources() is called, all blocked drivers can be loaded - again. If the detection fails, i.e. the resources are transferred - via register_device(), all blocked devices are unregistered and - pending load requests aborted. If a hardware detection collides - with a device whose driver is loaded, acquire_io_resources() fails - with B_BUSY. As this makes a hardware rescan impossible if the - driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN - for nodes that use I/O resources (see below). - - To search for new drivers for a given device node, use rescan(). This - marks all consumer devices as being verified and calls probe() - of all consumers drivers (see above) to let them rescan the parent - for devices. The parameter determines the nesting level, e.g. - 2 means that first the consumers are scanned and then the consumers - of the consumers. - - Normally, all devices can be rescanned. If a driver cannot handle - a rescan safely when it is loaded (i.e. used by a consumer), it - must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is - ignored during rescan if the driver is loaded and attempts - to load the driver during a rescan are blocked until the rescan - is finished. If rescanning a device is not possible at all, it must - have set PNP_DRIVER_NEVER_RESCAN to always ignore it. - - To distinguish between new devices, lost devices and redetected - devices, consumer devices should provide a connection code and a - device identifier. They are specified by PNP_DRIVER_CONNECTION and - PNP_DRIVER_CONNECTION respectively, and are expanded in the same way - as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only - one device per connection and that a device can be uniquely identify - by a device identifier. If a consumer device is registered on the - same connection as an existing device but with a different device - identifier, the old device gets unregistered automatically. If both - connection and device identifier are the same, registration is - handled as a redetection and ignored (unless a different type or - driver module is specified - in this case, the device is replaced). - Devices that were not redetected during a rescan get unregistered - unless they were ignored (see above). -*/ - -// interface of PnP manager -typedef struct device_manager_info { - module_info info; - - // load driver - // node - node whos driver is to be loaded - // user_cookie - cookie to be passed to init_device of driver - // interface - interface of loaded driver - // cookie - device cookie issued by loaded driver - status_t (*init_driver)(device_node_handle node, void *userCookie, - driver_module_info **interface, void **cookie); - // unload driver - status_t (*uninit_driver)(device_node_handle node); - - // rescan node for new dynamic drivers - // node - node whose dynamic drivers are to be scanned - status_t (*rescan)(device_node_handle node); - - // register device - // parent - parent node - // attributes - NULL-terminated array of node attributes - // io_resources - NULL-terminated array of I/O resources (can be NULL) - // node - new node handle - // on return, io_resources are invalid: on success I/O resources belong - // to node, on fail they are released; - // if device is already registered, B_OK is returned but *node is NULL - status_t (*register_device)(device_node_handle parent, - const device_attr *attrs, - const io_resource_handle *io_resources, - device_node_handle *node); - // unregister device - // all nodes having this node as their parent are unregistered too. - // if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID - // pairs, the id specified this way is freed too - status_t (*unregister_device)(device_node_handle node); - - // find device by node content - // the given attributes must _uniquely_ identify a device node; - // parent - parent node (-1 for don't-care) - // attrs - list of attributes (can be NULL) - // The node you got will be automatically put on the next call - // to this function. - status_t (*get_next_child_device)(device_node_handle parent, - device_node_handle *_node, const device_attr *attrs); - - // get parent device node - device_node_handle (*get_parent)(device_node_handle node); - - // Must be called after get_next_child_device() (if you don't iterate through) - // and get_parent() to make sure the node is freed when it's not used anymore - void (*put_device_node)(device_node_handle node); - - // acquire I/O resources - // resources - NULL-terminated array of resources to acquire - // handles - NULL-terminated array of handles (one per resource); - // array must be provided by caller - // return B_BUSY if a resource is used by a loaded driver - status_t (*acquire_io_resources)(io_resource *resources, - io_resource_handle *handles); - // release I/O resources - // handles - NULL-terminated array of handles - status_t (*release_io_resources)(const io_resource_handle *handles); - - // create unique id - // generator - name of id set - // if result >= 0 - unique id - // result < 0 - error code - int32 (*create_id)(const char *generator); - // free unique id - status_t (*free_id)(const char *generator, uint32 id); - - // helpers to extract attribute by name. - // if is true, parent nodes are scanned if - // attribute isn't found in current node; unless you declared - // the attribute yourself, use recursive search to handle - // intermittent nodes, e.g. defined by filter drivers, transparently. - // for raw and string attributes, you get a copy that must - // be freed by caller - status_t (*get_attr_uint8)(device_node_handle node, - const char *name, uint8 *value, bool recursive); - status_t (*get_attr_uint16)(device_node_handle node, - const char *name, uint16 *value, bool recursive); - status_t (*get_attr_uint32)(device_node_handle node, - const char *name, uint32 *value, bool recursive); - status_t (*get_attr_uint64)(device_node_handle node, - const char *name, uint64 *value, bool recursive); - status_t (*get_attr_string)(device_node_handle node, - const char *name, char **value, bool recursive); - status_t (*get_attr_raw)(device_node_handle node, - const char *name, void **data, size_t *_size, - bool recursive); - - // get next attribute of node; - // on call, * must contain handle of an attribute; - // on return, * is replaced by the next attribute or - // NULL if it was the last; - // to get the first attribute, must point to NULL; - // the returned handle must be released by either passing it to - // another get_next_attr() call or by using release_attr() - // directly - status_t (*get_next_attr)(device_node_handle node, - device_attr_handle *attrHandle); - - // release attribute handle of ; - // see get_next_attr - status_t (*release_attr)(device_node_handle node, - device_attr_handle attr_handle); - - // retrieve attribute data with handle given; - // is only valid as long as you don't release - // implicitely or explicitely - status_t (*retrieve_attr)(device_attr_handle attr_handle, - const device_attr **attr); - - // change/add attribute of/to node - status_t (*write_attr)(device_node_handle node, - const device_attr *attr); - - // remove attribute of node by name - // is name of attribute - status_t (*remove_attr)(device_node_handle node, const char *name); -} device_manager_info; - -// former pnp_driver.h -/* - Copyright (c) 2003-04, Thomas Kurschel - - Required interface of PnP drivers - - In contrast to standard BeOS drivers, PnP drivers are normal modules - having the interface described below. - - Every device is described by its driver via a PnP node with properties - described in PnP Node Attributes. Devices are organized in a hierarchy, - e.g. a devfs device is a hard disk device that is connected to a - controller, which is a PCI device, that is connected to a PCI bus. - Every device is connected to its lower-level device via a parent link - stored in its Node. The higher-level is called the consumer of the - lower-level device. If the lower-level device gets removed, all its - consumers are removed too. - - In our example, the hierarchy is - - devfs device -> hard disk -> controller -> PCI device -> PCI bus - - If the PCI bus is removed, everything up to including the devfs device - is removed too. - - The driver hierarchy is constructed bottom-up, i.e. the lower-level - driver searches for a corresponding consumer, which in turns searches - for its consumer and so on. The lowest driver is usually something like - a PCI bus, the highest driver is normally a devfs entry (see pnp_devfs.h). - Registration of devices and the search for appropriate consumers is - done via the pnp_manager (see pnp_manager.h). - - When a potential consumer is found, it gets informed about the new - lower-level device and can either refuse its handling or accept it. - On accept, it has to create a new node with the lower-level device - node as its parent. - - Loading of drivers is done on demand, i.e. if the consumer wants to - access its lower-level device, it explicitely loads the corresponding - driver, and once it doesn't need it anymore, the lower-level driver - must be unloaded. Usually, this process happens recursively, i.e. in - our example, the hard disk driver loads the controller driver, which - loads the PCI device driver which loads the PCI bus driver. The same - process applies to unloading. - - Because of this dynamic loading, drivers must store persistent data - in the node of their devices. Please be aware that you cannot modify - a node once published. - - If a device gets removed, you must unregister its node. As said, the - PnP manager will automatically unregister all consumers too. The - corresponding drivers are notified to stop talking to their lower-level - devices and to terminate running requests. Normally, you want to use a - dedicated variable that is verified at each call to make sure that the - parent is still there. The notification is done independantly of the - driver being loaded by its consumer(s) or not. If it isn't loaded, - the notification callback gets NULL as the device cookie; normally, the - driver returns immediately in this case. As soon as both the device - is removed and the driver is unloaded, device_cleanup gets called to - free resources that couldn't be safely removed in device_removed when - the driver was still loaded. - - If a device has exactly one consumer, they often interact in some way. - To simplify that, the consumer can pass a user-cookie to its parent - during load. In this case, it's up to the parent driver to get a - pointer to the interface of the consumer. Effectively, such consumers - have one interface for their consumers (base on pnp_driver_info), and - a another for their parents (with a completely driver-specific - structure). - - In terms of synchronization, loading/unloading/remove-notifications - are executed synchronously, i.e. if e.g. a device is to be unloaded - but the drive currently handles a remove-notification, the unloading - is delayed until the nofication callback returns. If multiple consumers - load a driver, the driver gets initialized only once; subsequent load - requests increase an internal load count only and return immediately. - In turn, unloading only happens once the load count reaches zero. -*/ - -struct driver_module_info { - module_info info; - - float (*supports_device)(device_node_handle parent, bool *_noConnection); - // check whether this parent is supported - - status_t (*register_device)(device_node_handle parent); - // Register your device node. - - status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie); - // driver is loaded. - // node - node of device - // user_cookie - cookie passed by loading driver - // cookie - cookie issued by this driver - - status_t (*uninit_driver)(void *cookie); - // driver gets unloaded. - - void (*device_removed)(device_node_handle node, void *cookie); - // a device node, registered by this driver, got removed. - // if the driver wasn't loaded when this happenes, no (un)init_device - // is called and thus is NULL; - - void (*device_cleanup)(device_node_handle node); - // a device node, registered by this driver, got removed and - // the driver got unloaded - - void (*get_supported_paths)(const char ***_busses, const char ***_devices); -}; - -// former pnp_bus.h -/* - Copyright (c) 2003-04, Thomas Kurschel - - Required interface of PnP bus drivers - - Busses consist of two node layers: the lower layer defines the bus, - the upper layer defines the abstract devices connected to the bus. - Both layers are handled by a bus manager. Actual device nodes are - on top of abstract device nodes. - - E.g. if we have a PCI bus with an IDE controller on it, we get - - IDE controller -> PCI device -> PCI bus - - with: - IDE controller = actual device node - PCI device = abstract device node - PCI bus = bus node - - The PCI bus manager establishes both the PCI devices and the PCI busses. - - Abstract device nodes act as a gateway between actual device nodes - and the corresponding bus node. They are constructed by the bus - node driver via its rescan() hook. To identify a bus node, define - PNP_BUS_IS_BUS as an attribute of it. As a result, the PnP manager - will call the rescan() method of the bus driver whenever the - bus is to be rescanned. Afterwards, all possible dynamic consumers - are informed as done for normal nodes. - - Normally, potential device drivers are notified immediately when - rescan() registers a new abstract device node. But sometimes, device - drivers need to know _all_ devices connected to the bus for correct - detection. To ensure this, the bus node must define - PNP_BUS_NOTIFY_CONSUMERS_AFTER_RESCAN. In this case, scanning for - consumers is postponed until rescan() has finished. - - If hot-plugging of devices can be detected automatically (e.g. USB), - you should define PNP_DRIVER_ALWAYS_LOADED, so the bus driver is - always loaded and thus capable of handling hot-plug events generated - by the bus controller hardware. -*/ - diff --git a/docs/develop/kernel/obsolete_pnp_manager.rst b/docs/develop/kernel/obsolete_pnp_manager.rst new file mode 100644 index 0000000000..68424428a9 --- /dev/null +++ b/docs/develop/kernel/obsolete_pnp_manager.rst @@ -0,0 +1,408 @@ +Plug and Play Manager +===================== + +This file contains the documentation written by Thomas Kurschel that was originally +found in the headers of his pnp_manager. +It's outdated but could be used as a basis for the real documentation. + +PNP Manager +----------- + +PnP manager; Takes care of registration and loading of PnP drivers + +Read pnp_driver.h first to understand the basic idea behind PnP drivers. + +To register a driver node, use register_driver. If the device got lost, +use unregister_driver (note: if the parent node is removed, your node +get removed automatically as your driver has obviously nothing to work +with anymore). To get access to a (parent) device, use load_driver/ +unload_driver. + +To let the manager find a consumer (see pnp_driver.h), you can either +specify its name directly during registration, using a +PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the +appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute. + +Searching of dynamic consumers is done as follows: + +- First, the manager searches for a Specific driver in the base + directory (see below) +- If no Specific driver is found, all Generic drivers stored under + "generic" sub-directory are informed in turn until one returns success +- Finally, _all_ Universal drivers, stored in the "universal" sub- + directory, are informed + +Specification of the base directory and of the names of Specific +drivers is done via a file name pattern given by a +PNP_DRIVER_DYNAMIC_CONSUMER attribute. + +First, all substrings of the form "%attribute_name%" are replaced by the +content of the attribute "attribute_name" as follows: + +- if the attribute contains an integer value, its content is converted to hex + (lowercase) with a fixed length according to the attribute's value range +- the content of string attributes is quoted by " and invalid characters + (i.e. /%" and all characters outside 32..126) are replaced by their + unsigned decimal value, delimited by % +- other attribute types cannot be used + +Second, the resulting name is split into chunks according to the presence +of | characters (you can escape % and | with a ^ character). These +characters are only delimiters and get removed before further processing. +The directory before the first | character is the base directory (see +above). It contains the "generic" and the "universal" subdirectories. +The names of the specific drivers are created by first taking the entire +file name, then by removing the last chunk, then by removing the last +two chunks and so on until only the first chunk is left. + +As drivers can contain multiple modules, the module name is constructed +by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file +name, seperated by a slash character (note: this only applies to dynamic +consumers; for fixed consumers, you specify the module name directly via +PNP_DRIVER_FIXED_CONSUMER). + +E.g. given a dynamic consumer pattern of +"pci/vendor=%vendor_id%|, device=%device_id%" for a device with the +attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the +PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and +(if the first one fails/doesn't exist) "pci/vendor=0123". If they both +refuse to handle the device, all drivers under "pci/generic" are tried +until one accepts the device. Finally, all drivers under "pci/universal" +are loaded, whatever happened before. + +In practise, you should try to use specific drivers as much as possible. +If detection based on device IDs is impossible (e.g. because the bus +doesn't support them at all), you can put the driver under "generic". +Generic drivers can also be used to specify wrappers that try to load old- +style drivers if no new driver can be found. Also, they can be used to +report an error or invoke an user program that tries downloading a +proper Specific driver. Universal drivers are mainly used for +informational purposes, e.g. to publish data about each found device, +or to provide raw access to all devices. + +If the device uses physical address space or I/O space or ISA DMA +channels (called I/O resources), the driver has to acquire these +resources. During hardware detection (usually via probe()), +acquire_io_resources() must be called to get exclusive access. +If no hardware could be found, they must be released via +release_io_resources(). If detection was successful, the list of +the (acquired) resources must be passed to register_device(). +Resources can either belong to one hardware detection or to a device. +If a hardware detection collides with another, it has to wait; +if it collides with a device whose driver is not loaded, the +driver loading is blocked. When detection fails, i.e. if +release_io_resources() is called, all blocked drivers can be loaded +again. If the detection fails, i.e. the resources are transferred +via register_device(), all blocked devices are unregistered and +pending load requests aborted. If a hardware detection collides +with a device whose driver is loaded, acquire_io_resources() fails +with B_BUSY. As this makes a hardware rescan impossible if the +driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN +for nodes that use I/O resources (see below). + +To search for new drivers for a given device node, use rescan(). This +marks all consumer devices as being verified and calls probe() +of all consumers drivers (see above) to let them rescan the parent +for devices. The parameter determines the nesting level, e.g. +2 means that first the consumers are scanned and then the consumers +of the consumers. + +Normally, all devices can be rescanned. If a driver cannot handle +a rescan safely when it is loaded (i.e. used by a consumer), it +must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is +ignored during rescan if the driver is loaded and attempts +to load the driver during a rescan are blocked until the rescan +is finished. If rescanning a device is not possible at all, it must +have set PNP_DRIVER_NEVER_RESCAN to always ignore it. + +To distinguish between new devices, lost devices and redetected +devices, consumer devices should provide a connection code and a +device identifier. They are specified by PNP_DRIVER_CONNECTION and +PNP_DRIVER_CONNECTION respectively, and are expanded in the same way +as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only +one device per connection and that a device can be uniquely identify +by a device identifier. If a consumer device is registered on the +same connection as an existing device but with a different device +identifier, the old device gets unregistered automatically. If both +connection and device identifier are the same, registration is +handled as a redetection and ignored (unless a different type or +driver module is specified - in this case, the device is replaced). +Devices that were not redetected during a rescan get unregistered +unless they were ignored (see above). + +.. code-block:: cpp + + // interface of PnP manager + typedef struct device_manager_info { + module_info info; + + // load driver + // node - node whos driver is to be loaded + // user_cookie - cookie to be passed to init_device of driver + // interface - interface of loaded driver + // cookie - device cookie issued by loaded driver + status_t (*init_driver)(device_node_handle node, void *userCookie, + driver_module_info **interface, void **cookie); + // unload driver + status_t (*uninit_driver)(device_node_handle node); + + // rescan node for new dynamic drivers + // node - node whose dynamic drivers are to be scanned + status_t (*rescan)(device_node_handle node); + + // register device + // parent - parent node + // attributes - NULL-terminated array of node attributes + // io_resources - NULL-terminated array of I/O resources (can be NULL) + // node - new node handle + // on return, io_resources are invalid: on success I/O resources belong + // to node, on fail they are released; + // if device is already registered, B_OK is returned but *node is NULL + status_t (*register_device)(device_node_handle parent, + const device_attr *attrs, + const io_resource_handle *io_resources, + device_node_handle *node); + // unregister device + // all nodes having this node as their parent are unregistered too. + // if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID + // pairs, the id specified this way is freed too + status_t (*unregister_device)(device_node_handle node); + + // find device by node content + // the given attributes must _uniquely_ identify a device node; + // parent - parent node (-1 for don't-care) + // attrs - list of attributes (can be NULL) + // The node you got will be automatically put on the next call + // to this function. + status_t (*get_next_child_device)(device_node_handle parent, + device_node_handle *_node, const device_attr *attrs); + + // get parent device node + device_node_handle (*get_parent)(device_node_handle node); + + // Must be called after get_next_child_device() (if you don't iterate through) + // and get_parent() to make sure the node is freed when it's not used anymore + void (*put_device_node)(device_node_handle node); + + // acquire I/O resources + // resources - NULL-terminated array of resources to acquire + // handles - NULL-terminated array of handles (one per resource); + // array must be provided by caller + // return B_BUSY if a resource is used by a loaded driver + status_t (*acquire_io_resources)(io_resource *resources, + io_resource_handle *handles); + // release I/O resources + // handles - NULL-terminated array of handles + status_t (*release_io_resources)(const io_resource_handle *handles); + + // create unique id + // generator - name of id set + // if result >= 0 - unique id + // result < 0 - error code + int32 (*create_id)(const char *generator); + // free unique id + status_t (*free_id)(const char *generator, uint32 id); + + // helpers to extract attribute by name. + // if is true, parent nodes are scanned if + // attribute isn't found in current node; unless you declared + // the attribute yourself, use recursive search to handle + // intermittent nodes, e.g. defined by filter drivers, transparently. + // for raw and string attributes, you get a copy that must + // be freed by caller + status_t (*get_attr_uint8)(device_node_handle node, + const char *name, uint8 *value, bool recursive); + status_t (*get_attr_uint16)(device_node_handle node, + const char *name, uint16 *value, bool recursive); + status_t (*get_attr_uint32)(device_node_handle node, + const char *name, uint32 *value, bool recursive); + status_t (*get_attr_uint64)(device_node_handle node, + const char *name, uint64 *value, bool recursive); + status_t (*get_attr_string)(device_node_handle node, + const char *name, char **value, bool recursive); + status_t (*get_attr_raw)(device_node_handle node, + const char *name, void **data, size_t *_size, + bool recursive); + + // get next attribute of node; + // on call, * must contain handle of an attribute; + // on return, * is replaced by the next attribute or + // NULL if it was the last; + // to get the first attribute, must point to NULL; + // the returned handle must be released by either passing it to + // another get_next_attr() call or by using release_attr() + // directly + status_t (*get_next_attr)(device_node_handle node, + device_attr_handle *attrHandle); + + // release attribute handle of ; + // see get_next_attr + status_t (*release_attr)(device_node_handle node, + device_attr_handle attr_handle); + + // retrieve attribute data with handle given; + // is only valid as long as you don't release + // implicitely or explicitely + status_t (*retrieve_attr)(device_attr_handle attr_handle, + const device_attr **attr); + + // change/add attribute of/to node + status_t (*write_attr)(device_node_handle node, + const device_attr *attr); + + // remove attribute of node by name + // is name of attribute + status_t (*remove_attr)(device_node_handle node, const char *name); + } device_manager_info; + +PNP Driver +---------- + +Required interface of PnP drivers + +In contrast to standard BeOS drivers, PnP drivers are normal modules +having the interface described below. + +Every device is described by its driver via a PnP node with properties +described in PnP Node Attributes. Devices are organized in a hierarchy, +e.g. a devfs device is a hard disk device that is connected to a +controller, which is a PCI device, that is connected to a PCI bus. +Every device is connected to its lower-level device via a parent link +stored in its Node. The higher-level is called the consumer of the +lower-level device. If the lower-level device gets removed, all its +consumers are removed too. + +In our example, the hierarchy is + + devfs device -> hard disk -> controller -> PCI device -> PCI bus + +If the PCI bus is removed, everything up to including the devfs device +is removed too. + +The driver hierarchy is constructed bottom-up, i.e. the lower-level +driver searches for a corresponding consumer, which in turns searches +for its consumer and so on. The lowest driver is usually something like +a PCI bus, the highest driver is normally a devfs entry (see pnp_devfs.h). +Registration of devices and the search for appropriate consumers is +done via the pnp_manager (see pnp_manager.h). + +When a potential consumer is found, it gets informed about the new +lower-level device and can either refuse its handling or accept it. +On accept, it has to create a new node with the lower-level device +node as its parent. + +Loading of drivers is done on demand, i.e. if the consumer wants to +access its lower-level device, it explicitely loads the corresponding +driver, and once it doesn't need it anymore, the lower-level driver +must be unloaded. Usually, this process happens recursively, i.e. in +our example, the hard disk driver loads the controller driver, which +loads the PCI device driver which loads the PCI bus driver. The same +process applies to unloading. + +Because of this dynamic loading, drivers must store persistent data +in the node of their devices. Please be aware that you cannot modify +a node once published. + +If a device gets removed, you must unregister its node. As said, the +PnP manager will automatically unregister all consumers too. The +corresponding drivers are notified to stop talking to their lower-level +devices and to terminate running requests. Normally, you want to use a +dedicated variable that is verified at each call to make sure that the +parent is still there. The notification is done independantly of the +driver being loaded by its consumer(s) or not. If it isn't loaded, +the notification callback gets NULL as the device cookie; normally, the +driver returns immediately in this case. As soon as both the device +is removed and the driver is unloaded, device_cleanup gets called to +free resources that couldn't be safely removed in device_removed when +the driver was still loaded. + +If a device has exactly one consumer, they often interact in some way. +To simplify that, the consumer can pass a user-cookie to its parent +during load. In this case, it's up to the parent driver to get a +pointer to the interface of the consumer. Effectively, such consumers +have one interface for their consumers (base on pnp_driver_info), and +a another for their parents (with a completely driver-specific +structure). + +In terms of synchronization, loading/unloading/remove-notifications +are executed synchronously, i.e. if e.g. a device is to be unloaded +but the drive currently handles a remove-notification, the unloading +is delayed until the nofication callback returns. If multiple consumers +load a driver, the driver gets initialized only once; subsequent load +requests increase an internal load count only and return immediately. +In turn, unloading only happens once the load count reaches zero. + +.. code-block:: cpp + + struct driver_module_info { + module_info info; + + float (*supports_device)(device_node_handle parent, bool *_noConnection); + // check whether this parent is supported + + status_t (*register_device)(device_node_handle parent); + // Register your device node. + + status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie); + // driver is loaded. + // node - node of device + // user_cookie - cookie passed by loading driver + // cookie - cookie issued by this driver + + status_t (*uninit_driver)(void *cookie); + // driver gets unloaded. + + void (*device_removed)(device_node_handle node, void *cookie); + // a device node, registered by this driver, got removed. + // if the driver wasn't loaded when this happenes, no (un)init_device + // is called and thus is NULL; + + void (*device_cleanup)(device_node_handle node); + // a device node, registered by this driver, got removed and + // the driver got unloaded + + void (*get_supported_paths)(const char ***_busses, const char ***_devices); + }; + +PNP Bus +------- + +Required interface of PnP bus drivers + +Busses consist of two node layers: the lower layer defines the bus, +the upper layer defines the abstract devices connected to the bus. +Both layers are handled by a bus manager. Actual device nodes are +on top of abstract device nodes. + +E.g. if we have a PCI bus with an IDE controller on it, we get + +IDE controller -> PCI device -> PCI bus + +with: + +* IDE controller = actual device node +* PCI device = abstract device node +* PCI bus = bus node + +The PCI bus manager establishes both the PCI devices and the PCI busses. + +Abstract device nodes act as a gateway between actual device nodes +and the corresponding bus node. They are constructed by the bus +node driver via its rescan() hook. To identify a bus node, define +PNP_BUS_IS_BUS as an attribute of it. As a result, the PnP manager +will call the rescan() method of the bus driver whenever the +bus is to be rescanned. Afterwards, all possible dynamic consumers +are informed as done for normal nodes. + +Normally, potential device drivers are notified immediately when +rescan() registers a new abstract device node. But sometimes, device +drivers need to know _all_ devices connected to the bus for correct +detection. To ensure this, the bus node must define +PNP_BUS_NOTIFY_CONSUMERS_AFTER_RESCAN. In this case, scanning for +consumers is postponed until rescan() has finished. + +If hot-plugging of devices can be detected automatically (e.g. USB), +you should define PNP_DRIVER_ALWAYS_LOADED, so the bus driver is +always loaded and thus capable of handling hot-plug events generated +by the bus controller hardware. + diff --git a/docs/develop/kernel/pci_serial_debug.txt b/docs/develop/kernel/pci_serial_debug.rst similarity index 50% rename from docs/develop/kernel/pci_serial_debug.txt rename to docs/develop/kernel/pci_serial_debug.rst index 2eb8dd1903..1426a1728f 100644 --- a/docs/develop/kernel/pci_serial_debug.txt +++ b/docs/develop/kernel/pci_serial_debug.rst @@ -27,23 +27,25 @@ Configuring - Install the card in your computer - Boot Haiku and look in the syslog for the PCI bus scan for the device: -KERN: PCI: [dom 0, bus 5] bus 5, device 0, function 0: vendor 9710, device 9922, revision 00 -KERN: PCI: class_base 07, class_function 00, class_api 02 -KERN: PCI: vendor 9710: MosChip Semiconductor Technology Ltd. -KERN: PCI: device 9922: MCS9922 PCIe Multi-I/O Controller -KERN: PCI: info: Communication controller (Serial controller, 16550) -KERN: PCI: line_size 10, latency 00, header_type 80, BIST 00 -KERN: PCI: ROM base host 00000000, pci 00000000, size 00000000 -KERN: PCI: cardbus_CIS 00000000, subsystem_id 1000, subsystem_vendor_id a000 -KERN: PCI: interrupt_line 0b, interrupt_pin 01, min_grant 00, max_latency 00 -KERN: PCI: base reg 0: host 00004000, pci 0000KERN: 4000, size 00000008, flags 01 -KERN: PCI: base reg 1: host f1c01000, pci f1c01000, size 00001000, flags 00 -KERN: PCI: base reg 2: host 00000000, pci 00000000, size 00000000, flags 00 -KERN: PCI: base reg 3: host 00000000, pci 00000000, size 00000000, flags 00 -KERN: PCI: base reg 4: host 00000000, pci 00000000, size 00000000, flags 00 -KERN: PCI: base reg 5: host f1c00000, pci f1c00000, size 00001000, flags 00 -KERN: PCI: Capabilities: MSI, PM, PCIe -KERN: PCI: Extended capabilities: Virtual Channel, Advanced Error Reporting +.. code-block:: text + + KERN: PCI: [dom 0, bus 5] bus 5, device 0, function 0: vendor 9710, device 9922, revision 00 + KERN: PCI: class_base 07, class_function 00, class_api 02 + KERN: PCI: vendor 9710: MosChip Semiconductor Technology Ltd. + KERN: PCI: device 9922: MCS9922 PCIe Multi-I/O Controller + KERN: PCI: info: Communication controller (Serial controller, 16550) + KERN: PCI: line_size 10, latency 00, header_type 80, BIST 00 + KERN: PCI: ROM base host 00000000, pci 00000000, size 00000000 + KERN: PCI: cardbus_CIS 00000000, subsystem_id 1000, subsystem_vendor_id a000 + KERN: PCI: interrupt_line 0b, interrupt_pin 01, min_grant 00, max_latency 00 + KERN: PCI: base reg 0: host 00004000, pci 0000KERN: 4000, size 00000008, flags 01 + KERN: PCI: base reg 1: host f1c01000, pci f1c01000, size 00001000, flags 00 + KERN: PCI: base reg 2: host 00000000, pci 00000000, size 00000000, flags 00 + KERN: PCI: base reg 3: host 00000000, pci 00000000, size 00000000, flags 00 + KERN: PCI: base reg 4: host 00000000, pci 00000000, size 00000000, flags 00 + KERN: PCI: base reg 5: host f1c00000, pci f1c00000, size 00001000, flags 00 + KERN: PCI: Capabilities: MSI, PM, PCIe + KERN: PCI: Extended capabilities: Virtual Channel, Advanced Error Reporting Write down the address of "base reg 0", this is where the serial port registers @@ -52,9 +54,11 @@ as well?) Configure serial debug in config/settings/kernel/drivers/kernel: -serial_debug_output true -serial_debug_speed 115200 -serial_debug_port 0x4000 +.. code-block:: text + + serial_debug_output true + serial_debug_speed 115200 + serial_debug_port 0x4000 Now your kernel is configured to send its output to the serial port. You can connect another machine to it (using an USB to serial adapter and a NULL modem diff --git a/docs/develop/kernel/vm/swap_file_support b/docs/develop/kernel/vm/swap_file_support.rst similarity index 63% rename from docs/develop/kernel/vm/swap_file_support rename to docs/develop/kernel/vm/swap_file_support.rst index 899c50f299..d693103ea4 100644 --- a/docs/develop/kernel/vm/swap_file_support +++ b/docs/develop/kernel/vm/swap_file_support.rst @@ -1,31 +1,34 @@ - Haiku swap file support +Swap file +####################### -This article describes how to use swap file in Haiku and how the swap system -works. +This section describes how to use swap file in Haiku and how the swap system +works. -1. How to use a swap file? +How to use a swap file? +======================= - Like BeOS, Haiku uses "/var/swap" as default swap file. It is created +Like BeOS, Haiku uses "/var/swap" as default swap file. It is created during the boot process and its size is twice the size of physical memory by default. You can change its size through the VirtualMemory preference application and your settings will take effect after restarting the system. - - The default swap file "/var/swap" may not satisfy your need. Haiku allows + +The default swap file "/var/swap" may not satisfy your need. Haiku allows adding/removing a swap file dynamically. (This is *NOT* implemented yet, since I do not know how to add bin commands "swapon" and "swapoff" in the system. It needs to be done in the future.) -2. How swap system works? - - The virtual memory subsystem of Haiku is very similar to that of FreeBSD, +How swap system works? +====================== + +The virtual memory subsystem of Haiku is very similar to that of FreeBSD, therefore our swap system implementation is borrowed from FreeBSD. - - A swap system has two main functions: (1) maintain a map between anonymous + +A swap system has two main functions: (1) maintain a map between anonymous pages and swap space, so we can page in/out when needed. (2) manage the allocation/deallocation of swap space. Let's see how these are implemented in Haiku. - In order to maintain a map between pages and swap space, we need to record +In order to maintain a map between pages and swap space, we need to record the pages' swap address somewhere. Here we use swap blocks. A "swap_block" structure contains swap address information for 32 (value of SWAP_BLOCK_PAGES) consecutive pages from a same cache. So whenever we look for a page in swap @@ -34,33 +37,33 @@ Here we use hash table. All swap blocks in the system are arranged into a global hash table. The hash table uses a cache's address and page index in this cache as hash key. - Here is an example. Suppose a page has been paged out to swap space and now -its cache wants to page it in. It works as follows: look up the swap hash table -using address of the cache and page index as hash key, if successful, we get -the swap block containing the this page's swap address. Then search the swap -block to get the exact swap address of this page. After that, we can read the +Here is an example. Suppose a page has been paged out to swap space and now +its cache wants to page it in. It works as follows: look up the swap hash table +using address of the cache and page index as hash key, if successful, we get +the swap block containing the this page's swap address. Then search the swap +block to get the exact swap address of this page. After that, we can read the page from swap file using vfs functions. - - I draw a picture and hope it could help you understand the above words. If -the pic becomes a mess on your computer, please set the tab width of your text -editor to 4. + +I draw a picture and hope it could help you understand the above words. + +.. code-block:: text ___________________________________________________________ sSwapHashTable |__________|___NULL___|___NULL___|___________|____NULL____| - | | - | | + | | + | | ___V___ ___V___ - swap_block /----|__0__| /--------|__5__| + swap_block /----|__0__| /--------|__5__| | |__3__|--------\ | /---|__6__| - | |_..._| | | | |_..._| - | |__2__|----\ | | | |__20_|---------------> + | |_..._| | | | |_..._| + | |__2__|----\ | | | |__20_|---------------> | | | | | - | _____________V___V_________V____V_________________________ - swap_file `->|slot|slot|slot|slot|slot|slot|slot|slot|slot|slot|....| - |_0__|_1__|_2__|_3__|_4__|_5__|_6__|_7__|_8__|_9__|____|__ + | _____________V___V_________V____V_________________________ + swap_file `->|slot|slot|slot|slot|slot|slot|slot|slot|slot|slot|....| + |_0__|_1__|_2__|_3__|_4__|_5__|_6__|_7__|_8__|_9__|____|__ - The swap system also manages allocation/deallocation of swap space. In our +The swap system also manages allocation/deallocation of swap space. In our implementation, each swap file is divided into page-sized slots(called "swap pages") and a swap file can be seen as an array of many swap pages(see the above picture). Swap page is the unit for swap space allocation/deallocation @@ -72,29 +75,28 @@ swap file is: 0-99, 101-200, 202-301) Why leave a page gap between swap files? Because in this way, we can easily tell if two adjacent pages are in a same swap file. (See the code in VMAnonymousCache::Read()). - The efficiency of the FreeBSD swap system lies in a special data structure: +The efficiency of the FreeBSD swap system lies in a special data structure: radix bitmap(i.e. bitmap using radix tree for hinting.) It can operate well no matter how much fragmentation there is and no matter how large a bitmap is used. I have ported the radix bitmap structure to Haiku, so our swap system will have a good performance. More information on radix bitmap, please look at the source code. - Swap space allocation takes place when we swap anonymous pages out. +Swap space allocation takes place when we swap anonymous pages out. In order to make the allocation less probable to fail, anonymous cache will reserve swap space when it is initialized. If there is not enough swap space left, physical memory will be reserved. Swap space deallocation happens when available swap space is low. The page daemon will scan a number of pages and if the scanned page has swap space assigned, its swap space will be freed. -3. Acknowledgement - - Special thanks to my mentor Ingo. He is a knowledged person and always +Acknowledgement +--------------- + +Special thanks to my mentor Ingo. He is a knowledged person and always gives me encouragement. Without his consistent and illuminating instructions, this project would not have reached its present status. - If you find bugs or have suggestions for swap system, you can contact me +If you find bugs or have suggestions for swap system, you can contact me via upczhsh@163.com. Thanks in advance. - Zhao Shuai - upczhsh@163.com - 2008-08-21 +Zhao Shuai - upczhsh@163.com - 2008-08-21 diff --git a/docs/develop/midi/design.html b/docs/develop/midi/design.html deleted file mode 100644 index a31f1afe9b..0000000000 --- a/docs/develop/midi/design.html +++ /dev/null @@ -1,532 +0,0 @@ - - - -

Midi Kit design

- -

The Midi Kit consists of the midi_server and two shared libraries, -libmidi2.so and libmidi.so. The latter is the "old" pre-R5 Midi Kit and has -been re-implemented using the facilities from libmidi2, which makes it fully -compatible with the new kit. This document describes the design and -implementation of the OpenBeOS midi_server and libmidi2.so.

- -

The midi_server has two jobs: it keeps track of the endpoints that the -client apps have created, and it publishes endpoints for the devices from -/dev/midi. (This last task could have been done by any other app, but it was -just as convenient to make the midi_server do that.) The libmidi2.so library -also has two jobs: it assists the midi_server with the housekeeping stuff, and -it allows endpoints to send and receive MIDI events. (That's right, the -midi_server has nothing to do with the actual MIDI data.)

- -
- -

Ooh, pictures

- -

The following image shows the center of Midi Kit activity, the midi_server, -and its data structures:

- -
- -

And here is the picture for libmidi2.so:

- -
- -

Note that these diagrams give only a conceptual overview of who is -responsible for which bits of data. The actual implementation details of the -kit may differ.

- -
- -

Housekeeping

- -
    - -
  • The design for our implementation of the midi2 "housekeeping" protocol -roughly follows what Be did, although there are -some differences. In Be's implementation, the BMidiRosters only have -BMidiEndpoints for remote endpoints if they are registered. In our -implementation, the BMidiRosters have BMidiEndpoint objects for all -endpoints, including remote endpoints that aren't published at all. If there -are many unpublished endpoints in the system, our approach is less optimal. -However, it made the implementation of the Midi Kit much easier ;-)

  • - -
  • Be's libmidi2.so exports the symbols "midi_debug_level" and -"midi_dispatcher_priority", both int32's. Our libmidi2 does not use either of -these. But even though these symbols are not present in the headers, some apps -may use them nonetheless. That's why our libmidi2 exports those symbols as -well.

  • - -
  • The name of the message fields in Be's implementation of the protocol -had the "be:" prefix. Our fields have a "midi:" prefix instead. Except for the -fields in the B_MIDI_EVENT notification messages, because that would break -compatibility with existing apps.

  • - -
- -

Initialization

- -
    - -
  • The first time an app uses a midi2 class, the BMidiRoster::MidiRoster() -method sends an 'Mapp' message to the midi_server, and blocks (on a semaphore). -This message includes a messenger to the app's BMidiRosterLooper object. The -server adds the app to its list of registered apps. Then the server -asynchronously sends back a series of 'mNEW' message notifications for all -endpoints on the roster, and 'mCON' messages for all existing connections. The -BMidiRosterLooper creates BMidiEndpoint objects for these endpoints and adds -them to its local roster; if the app is watching, it also sends out -corresponding B_MIDI_EVENT notifications. Finally, the midi_server sends an -'mAPP' message to notify the app that it has been successfully registered. Upon -receipt, BMidiRoster::MidiRoster() unblocks and returns control to the client -code. This handshake is the only asynchronous message exchange; all the other -requests have a synchronous reply.

  • - -
  • If the server detects an error during any of this (incorrect message -format, delivery failure, etc.) it simply ignores the request and does not try -to send anything back to the client (which is most likely impossible anyway). -If the app detects an error (server sends back meaningless info, cannot connect -to server), it pretends that everything is hunkey dorey. (The API has no way of -letting the client know that the initialization succeeded.) Next time the app -tries something, the server either still does not respond, or it ignores the -request (because this app isn't properly registered). However, if the app does -not receive the 'mAPP' message, it will not unblock, and remains frozen for all -eternity.

  • - -
  • BMidiRoster's MidiRoster() method creates the one and only BMidiRoster -instance on the heap the first time it is called. This instance is -automatically destroyed when the app quits.

  • - -
- -

Error handling

- -
    - -
  • If some error occurs, then the reply message is only guaranteed to -contain the "midi:result" field with some non- zero error code. libmidi2 can -only assume that the reply contains other data on success (i.e. when -"midi:result" is B_OK).

  • - -
  • The timeout for delivering and responding to a message is about 2 -seconds. If the client receives no reply within that time, it assumes the -request failed. If the server cannot deliver a message within 2 seconds, it -assumes the client is dead and removes it (and its endpoints) from the roster. -Of course, these assumptions may be false. If the client wasn't dead and tries -to send another request to the server, then the server will now ignore it, -since the client app is no longer registered.

  • - -
  • Because we work with timeouts, we must be careful to avoid -misunderstandings between the midi_server and the client app. Both sides must -recognize the timeout, so they both can ignore the operation. If, however, the -server thinks that everything went okay, but the client flags an error, then -the server and the client will have two different ideas of the current state of -the roster. Of course, those situations must be avoided.

  • - -
  • Although apps register themselves with the midi_server, there is no -corresponding "unregister" message. The only way the server recognizes that an -app and its endpoints are no longer available is when it fails to deliver a -message to that app. In that case, we remove the app and all its endpoints from -the roster. To do this, the server sends "purge endpoint" messages to itself -for all of the app's endpoints. This means we don't immediately throw the app -away, but we schedule that for some time in the future. That makes the whole -event handling mechanism much cleaner. There is no reply to the purge request. -(Actually, we do immediately throw away the app_t object, since that -doesn't really interfere with anything.) (If there are other events pending in -the queue which also cause notifications, then the server may send multiple -purge messages for the same endpoints. That's no biggie, because a purge -message will be ignored if its endpoint no longer exists.)

  • - -
  • As mentioned above, the midi_server ignores messages that do not come -from a registered app, although it does send back an error reply. In the case -of the "purge endpoint" message, the server makes sure the message was local -(i.e. sent by the midi_server itself).

  • - -
  • Note: BMessage's SendReply() apparently succeeds even if you kill the -app that the reply is intended for. This is rather strange, and it means that -you can't test delivery error handling for replies by killing the app. (You -can kill the app for testing the error handling on notifications, -however.)

  • - -
- -

Creating and deleting endpoints

- -
    - -
  • When client code creates a new BMidiLocalProducer or BMidiLocalConsumer -endpoint, we send an 'Mnew' message to the server. Unlike Be's implementation, -the "name" field is always present, even if the name is empty. After adding the -endpoint to the roster, the server sends 'mNEW' notifications to all other -applications. Upon receipt of this notification, the BMidiRosterLoopers of -these apps create a new BMidiEndpoint for the endpoint and add it to their -internal list of endpoints. The app that made the request receives a reply with -a single "midi:result" field.

  • - -
  • When you "new" an endpoint, its refcount is 1, even if the creation -failed. (For example, if the midi_server does not run.) When you Acquire(), the -refcount is bumped. When you Release(), it is decremented. When refcount drops -to 0, the endpoint object "deletes" itself. (So client code should never use an -endpoint after having Release()'d it, because the object may have just been -killed.) When creation succeeds, IsValid() returns true and ID() returns a -valid ID (> 0). Upon failure, IsValid() is false and ID() returns 0.

  • - -
  • After the last Release() of a local endpoint, we send 'Mdel' to let the -midi_server know the endpoint is now deleted. We don't expect a reply back. If -something goes wrong, the endpoint is deleted regardless. We do not send -separate "unregistered" notifications, because deleting an endpoint implies -that it is removed from the roster. For the same reason, we also don't send -separate "disconnected" notifications.

  • - -
  • The 'mDEL' notification triggers a BMidiRosterLooper to remove the -corresponding BMidiEndpoint from its internal list. This object is always a -proxy for a remote endpoint. The remote endpoint is gone, but whether we can -also delete the proxy depends on its reference count. If no one is still using -the object, its refcount is zero, and we can safely delete the object. -Otherwise, we must defer destruction until the client Release()'s the -object.

  • - -
  • If you "delete" an endpoint, your app drops into the debugger.

  • - -
  • If you Release() an endpoint too many times, your app could drop -into the debugger. It might also crash, because you are now using a dead -object. It depends on whether the memory that was previously occupied by your -endpoint object was overwritten in the mean time.

  • - -
  • You are allowed to pass NULL into the constructors of BMidiLocalConsumer -and BMidiLocalProducer, in which case the endpoint's name is simply an empty -string.

  • - -
- -

Changing endpoint attributes

- -
    - -
  • An endpoint can be "invalid". In the case of a proxy this means that the -remote endpoint is unregistered or even deleted. Local endpoints can only be -invalid if something went wrong during their creation (no connection to server, -for example). You can get the attributes of invalid objects, but you cannot set -them. Any attempts to do so will return an error code.

  • - -
  • For changing the name, latency, or properties of an endpoint, libmidi2 -sends an 'Mchg' message with the fields that should be changed, "midi:name", -"midi:latency", or "midi:properties". Registering or unregistering an endpoint -also sends such an 'Mchg' message, because we consider the "registered" state -also an attribute, in "midi:registered". The message obviously also includes -the ID of the endpoint in question. Properties are sent using a different -message, because the properties are not stored inside the -BMidiEndpoints.

  • - -
  • After handling the 'Mchg' request, the midi_server broadcasts an 'mCHG' -notification to all the other apps. This message has the same contents as the -original request.

  • - -
  • If the 'Mchg' message contains an invalid "midi:id" (i.e. no such -endpoint exists or it does not belong to the app that sent the request), the -midi_server returns an error code, and it does not notify the other -apps.

  • - -
  • If you try to Register() an endpoint that is already registered, -libmidi2 does not send a message to the midi_server but simply returns B_OK. -(Be's implementation did send a message, but our libmidi2 also keeps -track whether an endpoint is registered or not.) Although registering an -endpoint more than once doesn't make much sense, it is not considered an error. -Likewise for Unregister()ing an endpoint that is not registered.

  • - -
  • If you try to Register() or Unregister() a remote endpoint, libmidi2 -immediately returns an error code, and does not send a message to the server. -Likewise for a local endpoints that are invalid (i.e. whose IsValid() function -returns false).

  • - -
  • BMidiRoster::Register() and Unregister() do the same thing as -BMidiEndpoint::Register() and Unregister(). If you pass NULL into these -functions, they return B_BAD_VALUE.

  • - -
  • SetName() ignores NULL names. When you call it on a remote endpoint, -SetName() does nothing. SetName() does not send a message if the new name is -the same as the current name.

  • - -
  • SetLatency() ignores negative values. SetLatency() does not send a -message if the new latency is the same as the current latency. (Since -SetLatency() lives in BMidiLocalConsumer, you can never use it on remote -endpoints.)

  • - -
  • We store a copy of the endpoint properties in each BMidiEndpoint. The -properties of new endpoints are empty. GetProperties() copies this BMessage -into the client's BMessage. GetProperties() returns NULL if the message -parameter is NULL.

  • - -
  • SetProperties() returns NULL if the message parameter is NULL. It -returns an error code if the endpoint is remote or invalid. SetProperties() -does not compare the contents of the new BMessage to the old, so it will -always send out the change request.

  • - -
- -

Connections

- -
    - -
  • BMidiProducer::Connect() sends an 'Mcon' request to the midi_server. -This request contains the IDs of the producer and the consumer you want to -connect. The server sends back a reply with a result code. If it is possible to -make this connection, the server broadcasts an 'mCON' notification to all other -apps. In one of these apps the producer is local, so that app's libmidi2 calls -the BMidiLocalProducer::Connected() hook.

  • - -
  • You are not allowed to connect the same producer and consumer more than -once. The midi_server checks for this. It also returns an error code if you try -to disconnect two endpoints that were not connected.

  • - -
  • Disconnect() sends an 'Mdis' request to the server, which contains the -IDs of the producer and consumer that you want to disconnect. The server -replies with a result code. If the connection could be broken, it also sends an -'mDIS' notification to the other apps. libmidi2 calls the local producer's -BMidiLocalProducer::Disconnected() hook.

  • - -
  • Connect() and Disconnect() immediately return an error code if you pass -a NULL argument, or if the producer or consumer is invalid.

  • - -
  • When you Release() a local consumer that is connected, all apps will go -through their producers, and throw away this consumer from their connection -lists. If one of these producers is local, we call its Disconnected() hook. If -you release a local producer, this is not necessary.

  • - -
- -

Watching

- -
    - -
  • When you call StartWatching(), the BMidiRosterLooper remembers the -BMessenger, and sends it B_MIDI_EVENT notifications for all registered remote -endpoints, and the current connections between them. It does not let you know -about local endpoints. When you call StartWatching() a second time with the -same BMessenger, you'll receive the whole bunch of notifications again. -StartWatching(NULL) is not allowed, and will be ignored (so it is not the same -as StopWatching()).

  • - -
- -

Thread safety

- -
    - -
  • Within libmidi2 there are several possible race conditions, because we -are dealing with two threads: the one from BMidiRosterLooper and a thread from -the client app, most likely the BApplication's main thread. Both can access the -same data: BMidiEndpoint objects. To synchronize these threads, we lock the -BMidiRosterLooper, which is a normal BLooper. Anything happening in -BMidiRosterLooper's message handlers is safe, because BLoopers are -automatically locked when handling a message. Any other operations (which run -from a different thread) must first lock the looper if they access the list of -endpoints or certain BMidiEndpoint attributes (name, properties, etc).

  • - -
  • What if you obtain a BMidiEndpoint object from FindEndpoint() and at the -same time the BMidiRosterLooper receives an 'mDEL' request to delete that -endpoint? FindEndpoint() locks the looper, and bumps the endpoint object before -giving it to you. Now the looper sees that the endpoint's refcount is larger -than 0, so it won't delete it (although it will remove the endpoint from its -internal list). What if you Acquire() or Release() a remote endpoint while it -is being deleted by the looper? That also won't happen, because if you have a -pointer to that endpoint, its refcount is at least 1 and the looper won't -delete it.

  • - -
  • It is not safe to use a BMidiEndpoint and/or the BMidiRoster from more -than one client thread at a time; if you want to do that, you should -synchronize access to these objects yourself. The only exception is the Spray() -functions from BMidiLocalProducer, since most producers have a separate thread -to spray their MIDI events. This is fine, as long as that thread isn't used for -anything else, and it is the only one that does the spraying.

  • - -
  • BMidiProducer objects keep a list of consumers they are connected to. -This list can be accessed by several threads at a time: the client's thread, -the BMidiRosterLooper thread, and possibly a separate thread that is spraying -MIDI events. We could have locked the producer using BMidiRosterLooper's lock, -but that would freeze everything else while the producer is spraying events. -Conversely, it would freeze all producers while the looper is talking to the -midi_server. To lock with a finer granularity, each BMidiProducer has its own -BLocker, which is used only to lock the list of connected consumers.

  • - -
- -

Misc remarks

- -
    - -
  • BMidiEndpoint keeps track of its local/remote state with an "isLocal" -variable, and whether it is a producer/consumer with "isConsumer". It also has -an "isRegistered" field to remember whether this endpoint is registered or not. -Why not lump all these different states together into one "flags" bitmask? The -reason is that isLocal only makes sense to this application, not to others. -Also, the values of isLocal and isConsumer never change, but isRegistered does. -It made more sense (and clearer code) to separate them out. Finally, -isRegistered does not need to be protected by a lock, even though it can be -accessed by multiple threads at a time. Reading and writing a bool is atomic, -so this can't get messed up.

  • - -
- -

The messages

- -
-Message: Mapp (MSG_REGISTER_APP)
-    BMessenger midi:messenger
-Reply: 
-    (no reply)
-
-Message: mAPP (MSG_APP_REGISTERED)
-    (no fields)
-
-Message: Mnew (MSG_CREATE_ENDPOINT)
-    bool     midi:consumer
-    bool     midi:registered
-    char[]   midi:name
-    BMessage midi:properties
-    int32    midi:port       (consumer only)
-    int64    midi:latency    (consumer only)
-Reply:
-    int32    midi:result
-    int32    midi:id
-
-Message: mNEW (MSG_ENPOINT_CREATED)
-    int32    midi:id
-    bool     midi:consumer
-    bool     midi:registered
-    char[]   midi:name
-    BMessage midi:properties
-    int32    midi:port       (consumer only)
-    int64    midi:latency    (consumer only)
-
-Message: Mdel (MSG_DELETE_ENDPOINT)
-    int32 midi:id
-Reply: 
-    (no reply)
-
-Message: Mdie (MSG_PURGE_ENDPOINT)
-    int32 midi:id
-Reply: 
-    (no reply)
-
-Message: mDEL (MSG_ENDPOINT_DELETED)
-    int32 midi:id
-
-Message: Mchg (MSG_CHANGE_ENDPOINT)
-    int32    midi:id
-    int32    midi:registered (optional)
-    char[]   midi:name       (optional)
-    int64    midi:latency    (optional)
-    BMessage midi:properties (optional)
-Reply:
-    int32 midi:result
-
-Message: mCHG (MSG_ENDPOINT_CHANGED)
-    int32 midi:id
-    int32    midi:registered (optional)
-    char[]   midi:name       (optional)
-    int64    midi:latency    (optional)
-    BMessage midi:properties (optional)
-
- -
- -

MIDI events

- -
    - -
  • MIDI events are always sent from a BMidiLocalProducer to a -BMidiLocalConsumer. Proxy endpoint objects have nothing to do with this. During -its construction, the local consumer creates a kernel port. The ID of this port -is published, so everyone knows what it is. When a producer sprays an event, it -creates a message that it sends to the ports of all connected consumers.

  • - -
  • This means that the Midi Kit considers MIDI messages as discrete events. -Hardware drivers chop the stream of incoming MIDI data into separate events -that they send out to one or more kernel ports. Consumers never have to worry -about parsing a stream of MIDI data, just about handling a bunch of separate -events.

  • - -
  • Each BMidiLocalConsumer has a (realtime priority) thread associated with -it that waits for data to arrive at the port. As soon as a new MIDI message -comes in, the thread examines it and feeds it to the Data() hook. The Data() -hook ignores the message if the "atomic" flag is false, or passes it on to one -of the other hook functions otherwise. Incoming messages are also ignored if -their contents are not valid; for example, if they have too few or too many -bytes for a certain type of MIDI event.

  • - -
  • Unlike the consumer, BMidiLocalProducer has no thread of its own. As a -result, spraying MIDI events always happens in the thread of the caller. -Because the consumer port's queue is only 1 message deep, spray functions will -block if the consumer thread is already busy handling another MIDI event. (For -this reason, the Midi Kit does not support interleaving of real time messages -with lower priority messages such as sysex dumps, except at the driver -level.)

  • - -
  • The producer does not just send MIDI event data to the consumer, it also -sends a 20-byte header describing the event. The total message looks like -this:

    - -
    - - - - - - - - -
    4 bytesID of the producer
    4 bytesID of the consumer
    8 bytesperformance time
    1 byteatomic (1 = true, 0 = false)
    3 bytespadding (0)
    x bytesMIDI event data
  • - -
  • In the case of a sysex event, the SystemExclusive() hook is only called -if the first byte of the message is 0xF0. The sysex end marker (0xF7) is -optional; only if the last byte is 0xF7 we strip it off. This is unlike Be's -implementation, which all always strips the last byte even when it is not 0xF7. -According to the MIDI spec, 0xF7 is not really required; any non-realtime -status byte ends a sysex message.

  • - -
  • SprayTempoChange() sends 0xFF5103tttttt, where tttttt is 60,000,000/bpm. -This feature is not really part of the MIDI spec, but an extension from the SMF -(Standard MIDI File) format. Of course, the TempoChange() hook is called in -response to this message.

  • - -
  • The MIDI spec allows for a number of shortcuts. A Note On event with -velocity 0 is supposed to be interpreted as a Note Off, for example. The Midi -Kit does not concern itself with these shortcuts. In this case, it still calls -the NoteOn() hook with a velocity parameter of 0.

  • - -
  • The purpose of BMidiLocalConsumer's AllNotesOff() function is not -entirely clear. All Notes Off is a so-called "channel mode message" and is -generated by doing a SprayControlChange(channel, B_ALL_NOTES_OFF, 0). BMidi has -an AllNotesOff() function that sends an All Notes Off event to all channels, -and possible Note Off events to all keys on all channels as well. I suspect -someone at Be was confused by AllNotesOff() being declared "virtual", and -thought it was a hook function. Only that would explain it being in -BMidiLocalConsumer as opposed to BMidiLocalProducer, where it would have made -sense. The disassembly for Be's libmidi2.so shows that AllNotesOff() is empty, -so to cut a long story short, our AllNotesOff() simply does nothing and is -never invoked either.

  • - -
  • There are several types of System Common events, each of which takes a -different number of data bytes (0, 1, or 2). But SpraySystemCommon() and the -SystemCommon() hook are always given 2 data parameters. The Midi Kit simply -ignores the extra data bytes; in fact, in our implementation it doesn't even -send them. (The Be implementation always sends 2 data bytes, but that will -confuse the Midi Kit if the client does a SprayData() of a common event -instead. In our case, that will still invoke the SystemCommon() hook, because -we are not as easily fooled.)

  • - -
  • Handling of timeouts is fairly straightforward. When reading from the -port, we specify an absolute timeout. When the port function returns with a -B_TIMED_OUT error code, we call the Timeout() hook. Then we reset the timeout -value to -1, which means that timeouts are disabled (until the client calls -SetTimeout() again). This design means that a call to SetTimeout() only takes -effect the next time we read from the port, i.e. after at least one new MIDI -event is received (or the previous timeout is triggered). Even though -BMidiLocalConsumer's timeout and timeoutData values are accessed by two -different threads, I did not bother to protect this. Both values are int32's -and reading/writing them should be an atomic operation on most processors -anyway.

  • - -
- - - diff --git a/docs/develop/midi/design.rst b/docs/develop/midi/design.rst new file mode 100644 index 0000000000..87696f922c --- /dev/null +++ b/docs/develop/midi/design.rst @@ -0,0 +1,537 @@ +Midi Kit design +=============== + +The Midi Kit consists of the midi_server and two shared libraries, +libmidi2.so and libmidi.so. The latter is the "old" pre-R5 Midi Kit and +has been re-implemented using the facilities from libmidi2, which makes +it fully compatible with the new kit. This document describes the design +and implementation of the OpenBeOS midi_server and libmidi2.so. + +The midi_server has two jobs: it keeps track of the endpoints that the +client apps have created, and it publishes endpoints for the devices +from /dev/midi. (This last task could have been done by any other app, +but it was just as convenient to make the midi_server do that.) The +libmidi2.so library also has two jobs: it assists the midi_server with +the housekeeping stuff, and it allows endpoints to send and receive MIDI +events. (That's right, the midi_server has nothing to do with the actual +MIDI data.) + +-------------- + +Ooh, pictures +------------- + +The following image shows the center of Midi Kit activity, the +midi_server, and its data structures: + + |image0| + +And here is the picture for libmidi2.so: + + |image1| + +Note that these diagrams give only a conceptual overview of who is +responsible for which bits of data. The actual implementation details of +the kit may differ. + +-------------- + +Housekeeping +------------ + +- The design for our implementation of the midi2 "housekeeping" + protocol roughly follows `what Be did `__, although + there are some differences. In Be's implementation, the BMidiRosters + only have BMidiEndpoints for remote endpoints if they are registered. + In our implementation, the BMidiRosters have BMidiEndpoint objects + for *all* endpoints, including remote endpoints that aren't published + at all. If there are many unpublished endpoints in the system, our + approach is less optimal. However, it made the implementation of the + Midi Kit much easier ;-) + +- Be's libmidi2.so exports the symbols "midi_debug_level" and + "midi_dispatcher_priority", both int32's. Our libmidi2 does not use + either of these. But even though these symbols are not present in the + headers, some apps may use them nonetheless. That's why our libmidi2 + exports those symbols as well. + +- The name of the message fields in Be's implementation of the protocol + had the "be:" prefix. Our fields have a "midi:" prefix instead. + Except for the fields in the B_MIDI_EVENT notification messages, + because that would break compatibility with existing apps. + +Initialization +~~~~~~~~~~~~~~ + +- The first time an app uses a midi2 class, the + BMidiRoster::MidiRoster() method sends an 'Mapp' message to the + midi_server, and blocks (on a semaphore). This message includes a + messenger to the app's BMidiRosterLooper object. The server adds the + app to its list of registered apps. Then the server asynchronously + sends back a series of 'mNEW' message notifications for all endpoints + on the roster, and 'mCON' messages for all existing connections. The + BMidiRosterLooper creates BMidiEndpoint objects for these endpoints + and adds them to its local roster; if the app is watching, it also + sends out corresponding B_MIDI_EVENT notifications. Finally, the + midi_server sends an 'mAPP' message to notify the app that it has + been successfully registered. Upon receipt, BMidiRoster::MidiRoster() + unblocks and returns control to the client code. This handshake is + the only asynchronous message exchange; all the other requests have a + synchronous reply. + +- If the server detects an error during any of this (incorrect message + format, delivery failure, etc.) it simply ignores the request and + does not try to send anything back to the client (which is most + likely impossible anyway). If the app detects an error (server sends + back meaningless info, cannot connect to server), it pretends that + everything is hunkey dorey. (The API has no way of letting the client + know that the initialization succeeded.) Next time the app tries + something, the server either still does not respond, or it ignores + the request (because this app isn't properly registered). However, if + the app does not receive the 'mAPP' message, it will not unblock, and + remains frozen for all eternity. + +- BMidiRoster's MidiRoster() method creates the one and only + BMidiRoster instance on the heap the first time it is called. This + instance is automatically destroyed when the app quits. + +Error handling +~~~~~~~~~~~~~~ + +- If some error occurs, then the reply message is only guaranteed to + contain the "midi:result" field with some non- zero error code. + libmidi2 can only assume that the reply contains other data on + success (i.e. when "midi:result" is B_OK). + +- The timeout for delivering and responding to a message is about 2 + seconds. If the client receives no reply within that time, it assumes + the request failed. If the server cannot deliver a message within 2 + seconds, it assumes the client is dead and removes it (and its + endpoints) from the roster. Of course, these assumptions may be + false. If the client wasn't dead and tries to send another request to + the server, then the server will now ignore it, since the client app + is no longer registered. + +- Because we work with timeouts, we must be careful to avoid + misunderstandings between the midi_server and the client app. Both + sides must recognize the timeout, so they both can ignore the + operation. If, however, the server thinks that everything went okay, + but the client flags an error, then the server and the client will + have two different ideas of the current state of the roster. Of + course, those situations must be avoided. + +- Although apps register themselves with the midi_server, there is no + corresponding "unregister" message. The only way the server + recognizes that an app and its endpoints are no longer available is + when it fails to deliver a message to that app. In that case, we + remove the app and all its endpoints from the roster. To do this, the + server sends "purge endpoint" messages to itself for all of the app's + endpoints. This means we don't immediately throw the app away, but we + schedule that for some time in the future. That makes the whole event + handling mechanism much cleaner. There is no reply to the purge + request. (Actually, we *do* immediately throw away the app_t object, + since that doesn't really interfere with anything.) (If there are + other events pending in the queue which also cause notifications, + then the server may send multiple purge messages for the same + endpoints. That's no biggie, because a purge message will be ignored + if its endpoint no longer exists.) + +- As mentioned above, the midi_server ignores messages that do not come + from a registered app, although it does send back an error reply. In + the case of the "purge endpoint" message, the server makes sure the + message was local (i.e. sent by the midi_server itself). + +- Note: BMessage's SendReply() apparently succeeds even if you kill the + app that the reply is intended for. This is rather strange, and it + means that you can't test delivery error handling for replies by + killing the app. (You *can* kill the app for testing the error + handling on notifications, however.) + +Creating and deleting endpoints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- When client code creates a new BMidiLocalProducer or + BMidiLocalConsumer endpoint, we send an 'Mnew' message to the server. + Unlike Be's implementation, the "name" field is always present, even + if the name is empty. After adding the endpoint to the roster, the + server sends 'mNEW' notifications to all other applications. Upon + receipt of this notification, the BMidiRosterLoopers of these apps + create a new BMidiEndpoint for the endpoint and add it to their + internal list of endpoints. The app that made the request receives a + reply with a single "midi:result" field. + +- When you "new" an endpoint, its refcount is 1, even if the creation + failed. (For example, if the midi_server does not run.) When you + Acquire(), the refcount is bumped. When you Release(), it is + decremented. When refcount drops to 0, the endpoint object "deletes" + itself. (So client code should never use an endpoint after having + Release()'d it, because the object may have just been killed.) When + creation succeeds, IsValid() returns true and ID() returns a valid ID + (> 0). Upon failure, IsValid() is false and ID() returns 0. + +- After the last Release() of a local endpoint, we send 'Mdel' to let + the midi_server know the endpoint is now deleted. We don't expect a + reply back. If something goes wrong, the endpoint is deleted + regardless. We do not send separate "unregistered" notifications, + because deleting an endpoint implies that it is removed from the + roster. For the same reason, we also don't send separate + "disconnected" notifications. + +- The 'mDEL' notification triggers a BMidiRosterLooper to remove the + corresponding BMidiEndpoint from its internal list. This object is + always a proxy for a remote endpoint. The remote endpoint is gone, + but whether we can also delete the proxy depends on its reference + count. If no one is still using the object, its refcount is zero, and + we can safely delete the object. Otherwise, we must defer destruction + until the client Release()'s the object. + +- If you "delete" an endpoint, your app drops into the debugger. + +- If you Release() an endpoint too many times, your app *could* drop + into the debugger. It might also crash, because you are now using a + dead object. It depends on whether the memory that was previously + occupied by your endpoint object was overwritten in the mean time. + +- You are allowed to pass NULL into the constructors of + BMidiLocalConsumer and BMidiLocalProducer, in which case the + endpoint's name is simply an empty string. + +Changing endpoint attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- An endpoint can be "invalid". In the case of a proxy this means that + the remote endpoint is unregistered or even deleted. Local endpoints + can only be invalid if something went wrong during their creation (no + connection to server, for example). You can get the attributes of + invalid objects, but you cannot set them. Any attempts to do so will + return an error code. + +- For changing the name, latency, or properties of an endpoint, + libmidi2 sends an 'Mchg' message with the fields that should be + changed, "midi:name", "midi:latency", or "midi:properties". + Registering or unregistering an endpoint also sends such an 'Mchg' + message, because we consider the "registered" state also an + attribute, in "midi:registered". The message obviously also includes + the ID of the endpoint in question. Properties are sent using a + different message, because the properties are not stored inside the + BMidiEndpoints. + +- After handling the 'Mchg' request, the midi_server broadcasts an + 'mCHG' notification to all the other apps. This message has the same + contents as the original request. + +- If the 'Mchg' message contains an invalid "midi:id" (i.e. no such + endpoint exists or it does not belong to the app that sent the + request), the midi_server returns an error code, and it does not + notify the other apps. + +- If you try to Register() an endpoint that is already registered, + libmidi2 does not send a message to the midi_server but simply + returns B_OK. (Be's implementation *did* send a message, but our + libmidi2 also keeps track whether an endpoint is registered or not.) + Although registering an endpoint more than once doesn't make much + sense, it is not considered an error. Likewise for Unregister()ing an + endpoint that is not registered. + +- If you try to Register() or Unregister() a remote endpoint, libmidi2 + immediately returns an error code, and does not send a message to the + server. Likewise for a local endpoints that are invalid (i.e. whose + IsValid() function returns false). + +- BMidiRoster::Register() and Unregister() do the same thing as + BMidiEndpoint::Register() and Unregister(). If you pass NULL into + these functions, they return B_BAD_VALUE. + +- SetName() ignores NULL names. When you call it on a remote endpoint, + SetName() does nothing. SetName() does not send a message if the new + name is the same as the current name. + +- SetLatency() ignores negative values. SetLatency() does not send a + message if the new latency is the same as the current latency. (Since + SetLatency() lives in BMidiLocalConsumer, you can never use it on + remote endpoints.) + +- We store a copy of the endpoint properties in each BMidiEndpoint. The + properties of new endpoints are empty. GetProperties() copies this + BMessage into the client's BMessage. GetProperties() returns NULL if + the message parameter is NULL. + +- SetProperties() returns NULL if the message parameter is NULL. It + returns an error code if the endpoint is remote or invalid. + SetProperties() does *not* compare the contents of the new BMessage + to the old, so it will always send out the change request. + +Connections +~~~~~~~~~~~ + +- BMidiProducer::Connect() sends an 'Mcon' request to the midi_server. + This request contains the IDs of the producer and the consumer you + want to connect. The server sends back a reply with a result code. If + it is possible to make this connection, the server broadcasts an + 'mCON' notification to all other apps. In one of these apps the + producer is local, so that app's libmidi2 calls the + BMidiLocalProducer::Connected() hook. + +- You are not allowed to connect the same producer and consumer more + than once. The midi_server checks for this. It also returns an error + code if you try to disconnect two endpoints that were not connected. + +- Disconnect() sends an 'Mdis' request to the server, which contains + the IDs of the producer and consumer that you want to disconnect. The + server replies with a result code. If the connection could be broken, + it also sends an 'mDIS' notification to the other apps. libmidi2 + calls the local producer's BMidiLocalProducer::Disconnected() hook. + +- Connect() and Disconnect() immediately return an error code if you + pass a NULL argument, or if the producer or consumer is invalid. + +- When you Release() a local consumer that is connected, all apps will + go through their producers, and throw away this consumer from their + connection lists. If one of these producers is local, we call its + Disconnected() hook. If you release a local producer, this is not + necessary. + +Watching +~~~~~~~~ + +- When you call StartWatching(), the BMidiRosterLooper remembers the + BMessenger, and sends it B_MIDI_EVENT notifications for all + registered remote endpoints, and the current connections between + them. It does not let you know about local endpoints. When you call + StartWatching() a second time with the same BMessenger, you'll + receive the whole bunch of notifications again. StartWatching(NULL) + is not allowed, and will be ignored (so it is not the same as + StopWatching()). + +Thread safety +~~~~~~~~~~~~~ + +- Within libmidi2 there are several possible race conditions, because + we are dealing with two threads: the one from BMidiRosterLooper and a + thread from the client app, most likely the BApplication's main + thread. Both can access the same data: BMidiEndpoint objects. To + synchronize these threads, we lock the BMidiRosterLooper, which is a + normal BLooper. Anything happening in BMidiRosterLooper's message + handlers is safe, because BLoopers are automatically locked when + handling a message. Any other operations (which run from a different + thread) must first lock the looper if they access the list of + endpoints or certain BMidiEndpoint attributes (name, properties, + etc). + +- What if you obtain a BMidiEndpoint object from FindEndpoint() and at + the same time the BMidiRosterLooper receives an 'mDEL' request to + delete that endpoint? FindEndpoint() locks the looper, and bumps the + endpoint object before giving it to you. Now the looper sees that the + endpoint's refcount is larger than 0, so it won't delete it (although + it will remove the endpoint from its internal list). What if you + Acquire() or Release() a remote endpoint while it is being deleted by + the looper? That also won't happen, because if you have a pointer to + that endpoint, its refcount is at least 1 and the looper won't delete + it. + +- It is not safe to use a BMidiEndpoint and/or the BMidiRoster from + more than one client thread at a time; if you want to do that, you + should synchronize access to these objects yourself. The only + exception is the Spray() functions from BMidiLocalProducer, since + most producers have a separate thread to spray their MIDI events. + This is fine, as long as that thread isn't used for anything else, + and it is the only one that does the spraying. + +- BMidiProducer objects keep a list of consumers they are connected to. + This list can be accessed by several threads at a time: the client's + thread, the BMidiRosterLooper thread, and possibly a separate thread + that is spraying MIDI events. We could have locked the producer using + BMidiRosterLooper's lock, but that would freeze everything else while + the producer is spraying events. Conversely, it would freeze all + producers while the looper is talking to the midi_server. To lock + with a finer granularity, each BMidiProducer has its own BLocker, + which is used only to lock the list of connected consumers. + +Misc remarks +~~~~~~~~~~~~ + +- BMidiEndpoint keeps track of its local/remote state with an "isLocal" + variable, and whether it is a producer/consumer with "isConsumer". It + also has an "isRegistered" field to remember whether this endpoint is + registered or not. Why not lump all these different states together + into one "flags" bitmask? The reason is that isLocal only makes sense + to this application, not to others. Also, the values of isLocal and + isConsumer never change, but isRegistered does. It made more sense + (and clearer code) to separate them out. Finally, isRegistered does + not need to be protected by a lock, even though it can be accessed by + multiple threads at a time. Reading and writing a bool is atomic, so + this can't get messed up. + +The messages +~~~~~~~~~~~~ + + :: + + Message: Mapp (MSG_REGISTER_APP) + BMessenger midi:messenger + Reply: + (no reply) + + Message: mAPP (MSG_APP_REGISTERED) + (no fields) + + Message: Mnew (MSG_CREATE_ENDPOINT) + bool midi:consumer + bool midi:registered + char[] midi:name + BMessage midi:properties + int32 midi:port (consumer only) + int64 midi:latency (consumer only) + Reply: + int32 midi:result + int32 midi:id + + Message: mNEW (MSG_ENPOINT_CREATED) + int32 midi:id + bool midi:consumer + bool midi:registered + char[] midi:name + BMessage midi:properties + int32 midi:port (consumer only) + int64 midi:latency (consumer only) + + Message: Mdel (MSG_DELETE_ENDPOINT) + int32 midi:id + Reply: + (no reply) + + Message: Mdie (MSG_PURGE_ENDPOINT) + int32 midi:id + Reply: + (no reply) + + Message: mDEL (MSG_ENDPOINT_DELETED) + int32 midi:id + + Message: Mchg (MSG_CHANGE_ENDPOINT) + int32 midi:id + int32 midi:registered (optional) + char[] midi:name (optional) + int64 midi:latency (optional) + BMessage midi:properties (optional) + Reply: + int32 midi:result + + Message: mCHG (MSG_ENDPOINT_CHANGED) + int32 midi:id + int32 midi:registered (optional) + char[] midi:name (optional) + int64 midi:latency (optional) + BMessage midi:properties (optional) + +-------------- + +MIDI events +----------- + +- MIDI events are always sent from a BMidiLocalProducer to a + BMidiLocalConsumer. Proxy endpoint objects have nothing to do with + this. During its construction, the local consumer creates a kernel + port. The ID of this port is published, so everyone knows what it is. + When a producer sprays an event, it creates a message that it sends + to the ports of all connected consumers. + +- This means that the Midi Kit considers MIDI messages as discrete + events. Hardware drivers chop the stream of incoming MIDI data into + separate events that they send out to one or more kernel ports. + Consumers never have to worry about parsing a stream of MIDI data, + just about handling a bunch of separate events. + +- Each BMidiLocalConsumer has a (realtime priority) thread associated + with it that waits for data to arrive at the port. As soon as a new + MIDI message comes in, the thread examines it and feeds it to the + Data() hook. The Data() hook ignores the message if the "atomic" flag + is false, or passes it on to one of the other hook functions + otherwise. Incoming messages are also ignored if their contents are + not valid; for example, if they have too few or too many bytes for a + certain type of MIDI event. + +- Unlike the consumer, BMidiLocalProducer has no thread of its own. As + a result, spraying MIDI events always happens in the thread of the + caller. Because the consumer port's queue is only 1 message deep, + spray functions will block if the consumer thread is already busy + handling another MIDI event. (For this reason, the Midi Kit does not + support interleaving of real time messages with lower priority + messages such as sysex dumps, except at the driver level.) + +- The producer does not just send MIDI event data to the consumer, it + also sends a 20-byte header describing the event. The total message + looks like this: + + +---------+------------------------------+ + | 4 bytes | ID of the producer | + +---------+------------------------------+ + | 4 bytes | ID of the consumer | + +---------+------------------------------+ + | 8 bytes | performance time | + +---------+------------------------------+ + | 1 byte | atomic (1 = true, 0 = false) | + +---------+------------------------------+ + | 3 bytes | padding (0) | + +---------+------------------------------+ + | x bytes | MIDI event data | + +---------+------------------------------+ + +- In the case of a sysex event, the SystemExclusive() hook is only + called if the first byte of the message is 0xF0. The sysex end marker + (0xF7) is optional; only if the last byte is 0xF7 we strip it off. + This is unlike Be's implementation, which all always strips the last + byte even when it is not 0xF7. According to the MIDI spec, 0xF7 is + not really required; any non-realtime status byte ends a sysex + message. + +- SprayTempoChange() sends 0xFF5103tttttt, where tttttt is + 60,000,000/bpm. This feature is not really part of the MIDI spec, but + an extension from the SMF (Standard MIDI File) format. Of course, the + TempoChange() hook is called in response to this message. + +- The MIDI spec allows for a number of shortcuts. A Note On event with + velocity 0 is supposed to be interpreted as a Note Off, for example. + The Midi Kit does not concern itself with these shortcuts. In this + case, it still calls the NoteOn() hook with a velocity parameter of + 0. + +- The purpose of BMidiLocalConsumer's AllNotesOff() function is not + entirely clear. All Notes Off is a so-called "channel mode message" + and is generated by doing a SprayControlChange(channel, + B_ALL_NOTES_OFF, 0). BMidi has an AllNotesOff() function that sends + an All Notes Off event to all channels, and possible Note Off events + to all keys on all channels as well. I suspect someone at Be was + confused by AllNotesOff() being declared "virtual", and thought it + was a hook function. Only that would explain it being in + BMidiLocalConsumer as opposed to BMidiLocalProducer, where it would + have made sense. The disassembly for Be's libmidi2.so shows that + AllNotesOff() is empty, so to cut a long story short, our + AllNotesOff() simply does nothing and is never invoked either. + +- There are several types of System Common events, each of which takes + a different number of data bytes (0, 1, or 2). But + SpraySystemCommon() and the SystemCommon() hook are always given 2 + data parameters. The Midi Kit simply ignores the extra data bytes; in + fact, in our implementation it doesn't even send them. (The Be + implementation always sends 2 data bytes, but that will confuse the + Midi Kit if the client does a SprayData() of a common event instead. + In our case, that will still invoke the SystemCommon() hook, because + we are not as easily fooled.) + +- Handling of timeouts is fairly straightforward. When reading from the + port, we specify an absolute timeout. When the port function returns + with a B_TIMED_OUT error code, we call the Timeout() hook. Then we + reset the timeout value to -1, which means that timeouts are disabled + (until the client calls SetTimeout() again). This design means that a + call to SetTimeout() only takes effect the next time we read from the + port, i.e. after at least one new MIDI event is received (or the + previous timeout is triggered). Even though BMidiLocalConsumer's + timeout and timeoutData values are accessed by two different threads, + I did not bother to protect this. Both values are int32's and + reading/writing them should be an atomic operation on most processors + anyway. + +.. |image0| image:: midi_server.png +.. |image1| image:: libmidi2.png + diff --git a/docs/develop/midi/index.rst b/docs/develop/midi/index.rst new file mode 100644 index 0000000000..8137852087 --- /dev/null +++ b/docs/develop/midi/index.rst @@ -0,0 +1,11 @@ +The MIDI Kit +============ + +.. toctree:: + + /midi/design + /midi/midi1 + /midi/oldprotocol + /midi/stuff + /midi/testing + /midi/todo diff --git a/docs/develop/midi/midi1.html b/docs/develop/midi/midi1.html deleted file mode 100644 index dd165ab22d..0000000000 --- a/docs/develop/midi/midi1.html +++ /dev/null @@ -1,25 +0,0 @@ - - - -

How libmidi1 works

- -

Midi1 is implemented on top of midi2, which means that libmidi.so depends on libmidi2.so to do the real work. BeOS versions earlier than R5 did not include a midi_server, because midi1 itself did not need it. (A server is only really useful if data must be shared between teams, something that midi1 did not allow.)

- -

Midi2 is backwards compatible with midi1: The old libmidi.so still exists so that applications using the old API will run (providing binary compatibility). The old BMidiPort object is now a wrapper that uses the new BMidiRoster to allow connections to any published MIDI producer or consumer. Published MIDI objects are presented to the old MIDI apps as if they were physical MIDI ports.

- -

Here is a very nice picture of how BMidiPort works:

- -

- -

The softsynth

- -

The General MIDI synthesizer is implemented in BSoftSynth. This is a private class (not usable outside the API). It is not a real BMidiEndpoint, so you will not see it appear on Patchbay. I did this for simplicity's sake, for backwards compatibility (this is how the R5 synth worked too), and because we will have to give the Midi Kit a complete makeover for R2 anyway.

- -

The BMidiSynth and BSynth classes delegate most of the work to BSoftSynth. Not all of their methods are implemented, since some of them are very obscure. It would be a lot of work to figure out what they do, while it is likely that no applications use them anyway. However, BMidiSynth and BSynth should perform most common tasks without problems.

- -

BSamples doesn't do anything; its functions are mostly empty. In other words, with the OpenBeOS Midi Kit you cannot push waveform data into the output of the softsynth.

- -

For simplicity's sake, BMidiSynthFile is implemented using BMidiStore, since the latter already knows how to parse Standard MIDI Files. Duplicating that functionality elsewhere would be pointless. However, this makes the behavior of our BMidiSynthFile a little different from what the BeBook says — as long as your applications are written properly, you shouldn't notice any differences.

- - - diff --git a/docs/develop/midi/midi1.rst b/docs/develop/midi/midi1.rst new file mode 100644 index 0000000000..d2b7643b10 --- /dev/null +++ b/docs/develop/midi/midi1.rst @@ -0,0 +1,50 @@ +How libmidi1 works +~~~~~~~~~~~~~~~~~~ + +Midi1 is implemented on top of midi2, which means that libmidi.so +depends on libmidi2.so to do the real work. BeOS versions earlier than +R5 did not include a midi_server, because midi1 itself did not need it. +(A server is only really useful if data must be shared between teams, +something that midi1 did not allow.) + +Midi2 is backwards compatible with midi1: The old libmidi.so still +exists so that applications using the old API will run (providing binary +compatibility). The old ``BMidiPort`` object is now a wrapper that uses +the new ``BMidiRoster`` to allow connections to any published MIDI +producer or consumer. Published MIDI objects are presented to the old +MIDI apps as if they were physical MIDI ports. + +Here is a very nice picture of how ``BMidiPort`` works: + +|image0| + +The softsynth +~~~~~~~~~~~~~ + +The General MIDI synthesizer is implemented in ``BSoftSynth``. This is a +private class (not usable outside the API). It is not a real +``BMidiEndpoint``, so you will not see it appear on Patchbay. I did this +for simplicity's sake, for backwards compatibility (this is how the R5 +synth worked too), and because we will have to give the Midi Kit a +complete makeover for R2 anyway. + +The ``BMidiSynth`` and ``BSynth`` classes delegate most of the work to +``BSoftSynth``. Not all of their methods are implemented, since some of +them are very obscure. It would be a lot of work to figure out what they +do, while it is likely that no applications use them anyway. However, +``BMidiSynth`` and ``BSynth`` should perform most common tasks without +problems. + +``BSamples`` doesn't do anything; its functions are mostly empty. In +other words, with the OpenBeOS Midi Kit you cannot push waveform data +into the output of the softsynth. + +For simplicity's sake, ``BMidiSynthFile`` is implemented using +``BMidiStore``, since the latter already knows how to parse Standard +MIDI Files. Duplicating that functionality elsewhere would be pointless. +However, this makes the behavior of our ``BMidiSynthFile`` a little +different from what the BeBook says — as long as your applications are +written properly, you shouldn't notice any differences. + +.. |image0| image:: midiport.png + diff --git a/docs/develop/midi/oldprotocol.html b/docs/develop/midi/oldprotocol.html deleted file mode 100644 index 776ef2d37b..0000000000 --- a/docs/develop/midi/oldprotocol.html +++ /dev/null @@ -1,660 +0,0 @@ - - - -

The BeOS R5 Midi Kit protocol

- -

In the course of writing the OpenBeOS Midi Kit, I spent some time looking at -how BeOS R5's libmidi2.so and midi_server communicate. Not out of a compulsion -to clone this protocol, but to learn from it. After all, the Be engineers spent -a lot of time thinking about this already, and it would be foolish not to build -on their experience. Here is what I have found out.

- -

Two kinds of communication happen: administrative tasks and MIDI events. The -housekeeping stuff is done by sending BMessages between the BMidiRoster and the -midi_server. MIDI events are sent between producers and consumers using ports, -without intervention from the server.

- -

This document describes the BMessage protocol. The protocol appears to be -asynchronous, which means that when BMidiRoster sends a message to the -midi_server, it does not wait around for a reply, even though the midi_server -replies to all messages. The libmidi2 functions do block until the reply -is received, though, so client code does not have to worry about any of -this.

- -

Both BMidiRoster and the midi_server can initiate messages. BMidiRoster -typically sends a message when client code calls one of the functions from a -libmidi2 class. When the midi_server sends messages, it is to keep BMidiRoster -up-to-date about changes in the roster. BMidiRoster never replies to messages -from the server. The encoding of the BMessage 'what' codes indicates their -direction. The 'Mxxx' messages are sent from libmidi2 to the midi_server. The -'mXXX' messages go the other way around: from the server to a client.

- -
- -

Who does what?

- -

The players here are the midi_server, which is a normal BApplication, and -all the client apps, also BApplications. The client apps have loaded a copy of -libmidi2 into their own address space. The main class from libmidi2 is -BMidiRoster. The BMidiRoster has a BLooper that communicates with the -midi_server's BLooper.

- -

The midi_server keeps a list of all endpoints in the system, even -local, nonpublished, ones. Each BMidiRoster instance keeps its own list of -remote published endpoints, and all endpoints local to this application. It -does not know about remote endpoints that are not published yet.

- -

Whenever you make a change to one of your own endpoints, your BMidiRoster -notifies the midi_server. If your endpoint is published, the midi_server then -notifies all of the other BMidiRosters, so they can update their local rosters. -It does not notify your own app! (Sometimes, however, the midi_server -also notifies everyone else even if your local endpoint is not -published. The reason for this escapes me, because the other BMidiRosters have -no access to those endpoints anyway.)

- -

By the way, "notification" here means the internal communications between -server and libmidi, not the B_MIDI_EVENT messages you receive when you call -BMidiRoster::StartWatching().

- -
- -

BMidiRoster::MidiRoster()

- -

The first time it is called, this function creates the one-and-only instance -of BMidiRoster. Even if you don't explicitly call it yourself, it is used -behind-the-scenes anyway by any of the other BMidiRoster functions. -MidiRoster() constructs a BLooper and gets it running. Then it sends a -BMessenger with the looper's address to the midi_server:

- -

-OUT BMessage: what = Mapp (0x4d617070, or 1298231408)
-    entry       be:msngr, type='MSNG', c=1, size=24,         
-
- -

The server now responds with mOBJ messages for all remote -published producers and consumers. (Obviously, this list only contains -remote objects because by now you can't have created any local endpoints -yet.)

- -

For a consumer this message looks like:

- -

-IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '')
-    entry     be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry        be:port, type='LONG', c=1, size= 4, data[0]: 0x1dab (7595, '')
-    entry        be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0"
-
- -

(Oddness: why is be:latency a LONG and not a LLNG? Since latency is -expressed in microseconds using a 64-bit bigtime_t, you'd expect the -midi_server to send all 64 of those bits... In the 'Mnew' message, on the other -hand, be:latency is a LLGN.)

- -

And for a producer:

- -

-IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x2 (2, '')
-    entry        be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0"
-
- -

Note that the be:name field is not present if the endpoint has no name. That -is, if the endpoint was constructed by passing a NULL name into the -BMidiLocalConsumer() or BMidiLocalProducer() constructor.

- -

Next up are notifications for all connections, even those between -endpoints that are not registered:

- -

-IN  BMessage: what = mCON (0x6d434f4e, or 1833127758)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
-
- -

These messages are followed by an Msyn message:

- -

-IN  BMessage: what = Msyn (0x4d73796e, or 1299413358)
-
- -

And finally the (asynchronous) reply:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

Only after this reply is received, MidiRoster() returns.

- -

The purpose of the Msyn message is not entirely clear. (Without it, Be's -libmidi2 blocks in the MidiRoster() call.) Does it signify the end of the list -of endpoints? Why doesn't libmidi2 simply wait for the final reply?

- -
- -

BMidiLocalProducer constructor

- -

BMidiRoster, on behalf of the constructor, sends the following to the -midi_server:

- -

-OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567)
-    entry        be:type, type='CSTR', c=1, size=9, data[0]: "producer"
-    entry        be:name, type='CSTR', c=1, size=21, data[0]: "MIDI Keyboard output"
-
- -

The be:name field is optional.

- -

The reply includes the ID for the new endpoint. This means that the -midi_server assigns the IDs, and any endpoint gets an ID whether it is -published or not.

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '')
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

Unlike many other Be API classes, BMidiLocalProducer and BMidiLocalConsumer -don't have an InitCheck() method. But under certain odd circumstances (such as -the midi_server not running), creating the endpoint might fail. How does client -code check for that? Well, it turns out that upon failure, the endpoint is -assigned ID 0, so you can check for that. In that case, the endpoint's refcount -is 0 and you should not Release() it. (That is stupid, actually, because -Release() is the only way that you can destroy the object. Our implementation -should bump the endpoint to 1 even on failure!)

- -

If another app creates a new endpoint, your BMidiRoster is not notified. The -remote endpoint is not published yet, so your app is not supposed to see -it.

- -
- -

BMidiLocalConsumer constructor

- -

This is similar to the BMidiLocalProducer constructor, although the contents -of the message differ slightly. Again, be:name is optional.

- -

-OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567)
-    entry        be:type, type='CSTR', c=1, size=9, data[0]: "consumer"
-    entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x0 (0, '')
-    entry        be:port, type='LONG', c=1, size= 4, data[0]: 0x4c0 (1216, '')
-    entry        be:name, type='CSTR', c=1, size=13, data[0]: "InternalMIDI"  
-
- -

And the reply:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '')
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

Before it sends the message to the server, the constructor creates a new -port with the name "MidiEventPort" and a queue length (capacity) of 1.

- -
- -

BMidiEndpoint::Register()
-BMidiRoster::Register()

- -

Sends the same message for producers and consumers:

- -

-OUT BMessage: what = Mreg (0x4d726567, or 1299342695)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')     
-
- -

The reply:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

If you try to Register() an endpoint that is already registered, libmidi2 -still sends the message. (Which could mean that BMidiRoster does not keep track -of this registered state.) The midi_server simply ignores that request, and -sends back error code 0 (B_OK). So the API does not flag this as an error.

- -

If you send an invalid be:id, the midi_server returns error code -1 (General -OS Error, B_ERROR). If you try to Register() a remote endpoint, libmidi2 -immediately returns error code -1, and does not send a message to the -server.

- -

If another app Register()'s a producer, your BMidiRoster receives:

- -

-IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '')
-    entry        be:name, type='CSTR', c=1, size=7, data[0]: "a name"
-
- -

If the other app registers a consumer, your BMidiRoster -receives:

- -

-IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x19 (25, '')
-    entry     be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry        be:port, type='LONG', c=1, size= 4, data[0]: 0xde9 (3561, '')
-    entry        be:name, type='CSTR', c=1, size=7, data[0]: "a name"
-
- -

These are the same messages you get when your BMidiRoster instance is -constructed. In both messages, the be:name field is optional again.

- -

If the other app Register()'s the endpoint more than once, you still get -only one notification. So the midi_server simply ignores that second publish -request.

- -
- -

BMidiEndpoint::Unregister()
-BMidiRoster::Unregister()

- -

Sends the same message for producers and consumers:

- -

-OUT BMessage: what = Munr (0x4d756e72, or 1299541618)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')       
-
- -

The reply:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

If you try to Unregister() and endpoint that is already unregistered, -libmidi2 still sends the message. The midi_server simply ignores that request, -and sends back error code 0 (B_OK). So the API does not flag this as an error. -If you try to Unregister() a remote endpoint, libmidi2 immediately returns -error code -1, and does not send a message to the server.

- -

When another app Unregister()'s one of its own endpoints, your BMidiRoster -receives:

- -

-IN  BMessage: what = mDEL (0x6d44454c, or 1833190732)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '')             
-
- -

When the other app deletes that endpoint (refcount is now 0) and it is not -unregistered yet, your BMidiRoster also receives that mDEL message. Multiple -Unregisters() are ignored again by the midi_server.

- -

If an app quits without properly cleaning up, i.e. it does not Unregister() -and Release() its endpoints, then the midi_server's roster contains a stale -endpoint. As soon as the midi_server recognizes this (for example, when an -application tries to connect that endpoint), it sends all BMidiRosters an mDEL -message for this endpoint. (This message is sent whenever the midi_server feels -like it, so libmidi2 can receive this message while it is still waiting for a -reply to some other message.) If the stale endpoint is still on the roster and -you (re)start your app, then you receive an mOBJ message for this endpoint -during the startup handshake. A little later you will receive the mDEL.

- -
- -

BMidiEndpoint::Release()

- -

Only sends a message if the refcount of local objects (published or not) -becomes 0:

- -

-OUT BMessage: what = Mdel (0x4d64656c, or 1298425196)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
-
- -

The corresponding reply:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

If you did not Unregister() a published endpoint before you Release()'d it, -no 'Munr' message is sent. Of course, the midi_server is smart enough to -realize that this endpoint should be wiped from the roster now. Likewise, if -this endpoint is connected to another endpoint, Release() will not send a -separate 'Mdis' message, but the server will disconnect them. (This, of -course, only happens when you Release() local objects. Releasing a proxy has no -impact on the connection with the real endpoint.)

- -

When you Release() a proxy (a remote endpoint) and its refcount becomes 0, -libmidi2 does not send an 'Mdel' message to the server. After all, the object -is not deleted, just your proxy. If the remote endpoint still exists (i.e. -IsValid() returns true), the BMidiRoster actually keeps a cached copy of the -proxy object around, just in case you need it again. This means you can do -this: endp = NextEndpoint(); endp->Release(); (now refcount is 0) endp- ->Acquire(); (now refcount is 1 again). But I advice against that since it -doesn't work for all objects; local and dead remote endpoints will be -deleted when their refcount reaches zero.

- -

In Be's implementation, if you Release() a local endpoint that already has a -zero refcount, libmidi still sends out the 'Mdel' message. It also drops you -into the debugger. (I think it should return an error code instead, it already -has a status_t.) However, if you Release() proxies a few times too many, your -app does not jump into the debugger. (Again, I think the return result should -be an error code here -- for OpenBeOS R1 I think we should jump into the -debugger just like with local objects). Hmm, actually, whether you end up in -the debugger depends on the contents of memory after the object is deleted, -because you perform the extra Release() on a dead object. Don't do that.

- -
- -

BMidiEndpoint::SetName()

- -

For local endpoints, both unpublished and published, libmidi2 sends:

- -

-OUT BMessage: what = Mnam (0x4d6e616d, or 1299079533)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
-    entry        be:name, type='CSTR', c=1, size=7, data[0]: "b name"
-
- -

And receives:

- -

-IN BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

You cannot rename remote endpoints. If you try, libmidi2 will simply ignore -your request. It does not send a message to the midi_server.

- -

If another application renames one of its own endpoints, all other -BMidiRosters receive:

- -

-IN  BMessage: what = mREN (0x6d52454e, or 1834108238)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x5 (5, '')
-    entry        be:name, type='CSTR', c=1, size=7, data[0]: "b name"
-
- -

You receive this message even if the other app did not publish its endpoint. -This seems rather strange, because your BMidiRoster has no knowledge of this -particular endpoint yet, so what is it to do with this message? Ignore it, I -guess.

- -
- -

BMidiEndpoint::GetProperties()

- -

For any kind of endpoint (local non-published, local published, -remote) libmidi2 sends the following message to the server:

- -

-OUT BMessage: what = Mgpr (0x4d677072, or 1298624626)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x2b2 (690, '')
-    entry       be:props, type='MSGG', c=1, size= 0,
-
- -

(Why this "get properties" request includes a BMessage is a mistery to me. -The midi_server does not appear to copy its contents into the reply, which -would have made at least some sense. The BMessage from the client is completely -overwritten with the endpoint's properties.)

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry       be:props, type='MSGG', c=1, size= 0,
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

This means that endpoint properties are stored in the server only, not -inside the BMidiEndpoints, and not by the local BMidiRosters.

- -
- -

BMidiEndpoint::SetProperties()

- -

For local endpoints, published or not, libmidi2 sends the following message -to the server:

- -

-OUT BMessage: what = Mspr (0x4d737072, or 1299411058)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
-    entry       be:props, type='MSGG', c=1, size= 0,
-
- -

And expects this back:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

You cannot change the properties of remote endpoints. If you try, libmidi2 -will ignore your request. It does not send a message to the midi_server, and it -returns the -1 error code (B_ERROR).

- -

If another application changes the properties of one of its own endpoints, -all other BMidiRosters receive:

- -

-IN  BMessage: what = mPRP (0x6d505250, or 1833980496)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
-    entry  be:properties, type='MSGG', c=1, size= 0,
-
- -

You receive this message even if the other app did not publish its -endpoint.

- -
- -

BMidiLocalConsumer::SetLatency()

- -

For local endpoints, published or not, libmidi2 sends the following message -to the server:

- -

-OUT BMessage: what = Mlat (0x4d6c6174, or 1298948468)
-    entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '')
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x14f (335, '')
-
- -

And receives:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

If another application changes the latency of one of its own consumers, all -other BMidiRosters receive:

- -

-IN  BMessage: what = mLAT (0x6d4c4154, or 1833714004)
-    entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x15 (21, '')
-    entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '')
-
- -

You receive this message even if the other app did not publish its -endpoint.

- -
- -

BMidiProducer::Connect()

- -

The message:

- -

-OUT BMessage: what = Mcon (0x4d636f6e, or 1298362222)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x376 (886, '')
-
- -

The answer:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

The server sends back a B_ERROR result if you specify wrong ID's. When you -try to connect a producer and consumer that are already connected to each -other, libmidi2 still sends the 'Mcon' message to the server (even though it -could have known these endpoints are already connected). In that case, the -server responds with a B_ERROR code as well.

- -

When another app makes the connection, your BMidiRoster receives:

- -

-IN  BMessage: what = mCON (0x6d434f4e, or 1833127758)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
-
- -

Note: your BMidiRoster receives this notification even if the producer or -the consumer (or both) are not registered endpoints.

- -
- -

BMidiProducer::Disconnect()

- -

The message:

- -

-OUT BMessage: what = Mdis (0x4d646973, or 1298426227)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x309 (777, '')
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x393 (915, '')
-
- -

The answer:

- -

-IN  BMessage: what =  (0x0, or 0)
-    entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
-    entry     _previous_, ...
-
- -

The server sends back a B_ERROR result if you specify wrong ID's. When you -try to disconnect a producer and consumer that are not connected to each other, -libmidi2 still sends the 'Mdis' message to the server (even though it could -have known these endpoints are not connected). In that case, the server -responds with a B_ERROR code as well.

- -

When another app breaks the connection, your BMidiRoster receives:

- -

-IN  BMessage: what = mDIS (0x6d444953, or 1833191763)
-    entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
-    entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
-
- -

Note: your BMidiRoster receives this notification even if the producer or -the consumer (or both) are not registered endpoints.

- -
- -

Watchin'

- -

BMidiRoster::StartWatching() and StopWatching() do not send messages to the -midi_server. This means that the BMidiRoster itself, and not the midi_server, -sends the notifications to the messenger. It does this whenever it receives a -message from the midi_server.

- -

The relationship between midi_server messages and B_MIDI_EVENT notifications -is as follows:

- -
- - - - - - - - - -
messagenotification
mOBJB_MIDI_REGISTERED
mDEL B_MIDI_UNREGISTERED
mCONB_MIDI_CONNECTED
mDISB_MIDI_DISCONNECTED
mRENB_MIDI_CHANGED_NAME
mLATB_MIDI_CHANGED_LATENCY
mPRPB_MIDI_CHANGED_PROPERTIES
-
- -

For each message on the left, the watcher will receive the corresponding -notification on the right.

- -
- -

Other observations

- -

Operations that do not send messages to the midi_server:

- -
    - -
  • BMidiEndpoint::Acquire(). This means reference counting is done locally -by BMidiRoster. Release() doesn't send a message either, unless the refcount -becomes 0 and the object is deleted. (Which suggests that it is actually the -destructor and not Release() that sends the message.)

  • - -
  • BMidiRoster::NextEndpoint(), NextProducer(), NextConsumer(), -FindEndpoint(), FindProducer(), FindConsumer(). None of these functions send -messages to the midi_server. This means that each BMidiRoster instance keeps -its own list of available endpoints. This is why it receives 'mOBJ' messages -during the startup handshake, and whenever a new remote endpoint is registered, -and 'mDEL' messages for every endpoint that disappears. Even though the -NextXXX() functions do not return locally created objects, this "local roster" -does keep track of them, since FindXXX() do return local -endpoints.

  • - -
  • BMidiEndpoint::Name(), ID(), IsProducer(), IsConsumer(), IsRemote(), -IsLocal() IsPersistent(). BMidiConsumer::Latency(). -BMidiLocalConsumer::GetProducerID(), SetTimeout(). These all appear to consult -BMidiRoster's local roster.

  • - -
  • BMidiEndpoint::IsValid(). This function simply looks at BMidiRoster's -local roster to see whether the remote endpoint is still visible, i.e. not -unregistered. It does not determine whether the endpoint's application is still -alive, or "ping" the endpoint or anything fancy like that.

  • - -
  • BMidiProducer::IsConnected(), Connections(). This means that -BMidiRoster's local roster, or maybe the BMidiProducers themselves (including -the proxies) keep track of the various connections.

  • - -
  • BMidiLocalProducer::Connected(), Disconnected(). These methods are -invoked when any app (including your own) makes or breaks a connection on one -of your local producers. These hooks are invoked before the B_MIDI_EVENT -messages are sent to any watchers.

  • - -
  • Quitting your app. Even though the BMidiRoster instance is deleted when -the app quits, it does not let the midi_server know that the application in -question is now gone. Any endpoints you have registered are not automatically -unregistered. This means that the midi_server is left with some stale -information. Undoubtedly, there is a mechanism in place to clean this up. The -same mechanism would be used to clean up apps that did not exit cleanly, or -that crashed.

  • - -
- -

Other stuff:

- -
    - -
  • libmidi2.so exports an int32 symbol called "midi_debug_level". If you -set it to a non-zero value, libmidi2 will dump a lot of interesting debug info -on stdout. To do this, declare the variable in your app with "extern int32 -midi_debug_level;", and then set it to some high value later: "midi_debug_level -= 0x7FFFFFFF;" Now run your app from a Terminal and watch libmidi2 do its -thing.

  • - -
  • libmidi2.so also exports an int32 symbol called -"midi_dispatcher_priority". This is the runtime priority of the thread that -fields MIDI events to consumers.

  • - -
- - - diff --git a/docs/develop/midi/oldprotocol.rst b/docs/develop/midi/oldprotocol.rst new file mode 100644 index 0000000000..700e982933 --- /dev/null +++ b/docs/develop/midi/oldprotocol.rst @@ -0,0 +1,678 @@ +The BeOS R5 Midi Kit protocol +============================= + +In the course of writing the OpenBeOS Midi Kit, I spent some time +looking at how BeOS R5's libmidi2.so and midi_server communicate. Not +out of a compulsion to clone this protocol, but to learn from it. After +all, the Be engineers spent a lot of time thinking about this already, +and it would be foolish not to build on their experience. Here is what I +have found out. + +Two kinds of communication happen: administrative tasks and MIDI events. +The housekeeping stuff is done by sending BMessages between the +BMidiRoster and the midi_server. MIDI events are sent between producers +and consumers using ports, without intervention from the server. + +This document describes the BMessage protocol. The protocol appears to +be asynchronous, which means that when BMidiRoster sends a message to +the midi_server, it does not wait around for a reply, even though the +midi_server replies to all messages. The libmidi2 functions *do* block +until the reply is received, though, so client code does not have to +worry about any of this. + +Both BMidiRoster and the midi_server can initiate messages. BMidiRoster +typically sends a message when client code calls one of the functions +from a libmidi2 class. When the midi_server sends messages, it is to +keep BMidiRoster up-to-date about changes in the roster. BMidiRoster +never replies to messages from the server. The encoding of the BMessage +'what' codes indicates their direction. The 'Mxxx' messages are sent +from libmidi2 to the midi_server. The 'mXXX' messages go the other way +around: from the server to a client. + +-------------- + +Who does what? +-------------- + +The players here are the midi_server, which is a normal BApplication, +and all the client apps, also BApplications. The client apps have loaded +a copy of libmidi2 into their own address space. The main class from +libmidi2 is BMidiRoster. The BMidiRoster has a BLooper that communicates +with the midi_server's BLooper. + +The midi_server keeps a list of *all* endpoints in the system, even +local, nonpublished, ones. Each BMidiRoster instance keeps its own list +of remote published endpoints, and all endpoints local to this +application. It does not know about remote endpoints that are not +published yet. + +Whenever you make a change to one of your own endpoints, your +BMidiRoster notifies the midi_server. If your endpoint is published, the +midi_server then notifies all of the other BMidiRosters, so they can +update their local rosters. It does *not* notify your own app! +(Sometimes, however, the midi_server also notifies everyone else even if +your local endpoint is *not* published. The reason for this escapes me, +because the other BMidiRosters have no access to those endpoints +anyway.) + +By the way, "notification" here means the internal communications +between server and libmidi, not the B_MIDI_EVENT messages you receive +when you call BMidiRoster::StartWatching(). + +-------------- + +BMidiRoster::MidiRoster() +------------------------- + +The first time it is called, this function creates the one-and-only +instance of BMidiRoster. Even if you don't explicitly call it yourself, +it is used behind-the-scenes anyway by any of the other BMidiRoster +functions. MidiRoster() constructs a BLooper and gets it running. Then +it sends a BMessenger with the looper's address to the midi_server: + +:: + + OUT BMessage: what = Mapp (0x4d617070, or 1298231408) + entry be:msngr, type='MSNG', c=1, size=24, + +The server now responds with mOBJ messages for all *remote* *published* +producers and consumers. (Obviously, this list only contains remote +objects because by now you can't have created any local endpoints yet.) + +For a consumer this message looks like: + +:: + + IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '') + entry be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry be:port, type='LONG', c=1, size= 4, data[0]: 0x1dab (7595, '') + entry be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0" + +(Oddness: why is be:latency a LONG and not a LLNG? Since latency is +expressed in microseconds using a 64-bit bigtime_t, you'd expect the +midi_server to send all 64 of those bits... In the 'Mnew' message, on +the other hand, be:latency *is* a LLGN.) + +And for a producer: + +:: + + IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x2 (2, '') + entry be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0" + +Note that the be:name field is not present if the endpoint has no name. +That is, if the endpoint was constructed by passing a NULL name into the +BMidiLocalConsumer() or BMidiLocalProducer() constructor. + +Next up are notifications for *all* connections, even those between +endpoints that are not registered: + +:: + + IN BMessage: what = mCON (0x6d434f4e, or 1833127758) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') + +These messages are followed by an Msyn message: + +:: + + IN BMessage: what = Msyn (0x4d73796e, or 1299413358) + +And finally the (asynchronous) reply: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +Only after this reply is received, MidiRoster() returns. + +The purpose of the Msyn message is not entirely clear. (Without it, Be's +libmidi2 blocks in the MidiRoster() call.) Does it signify the end of +the list of endpoints? Why doesn't libmidi2 simply wait for the final +reply? + +-------------- + +BMidiLocalProducer constructor +------------------------------ + +BMidiRoster, on behalf of the constructor, sends the following to the +midi_server: + +:: + + OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567) + entry be:type, type='CSTR', c=1, size=9, data[0]: "producer" + entry be:name, type='CSTR', c=1, size=21, data[0]: "MIDI Keyboard output" + +The be:name field is optional. + +The reply includes the ID for the new endpoint. This means that the +midi_server assigns the IDs, and any endpoint gets an ID whether it is +published or not. + +:: + + IN BMessage: what = (0x0, or 0) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '') + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +Unlike many other Be API classes, BMidiLocalProducer and +BMidiLocalConsumer don't have an InitCheck() method. But under certain +odd circumstances (such as the midi_server not running), creating the +endpoint might fail. How does client code check for that? Well, it turns +out that upon failure, the endpoint is assigned ID 0, so you can check +for that. In that case, the endpoint's refcount is 0 and you should not +Release() it. (That is stupid, actually, because Release() is the only +way that you can destroy the object. Our implementation should bump the +endpoint to 1 even on failure!) + +If another app creates a new endpoint, your BMidiRoster is not notified. +The remote endpoint is not published yet, so your app is not supposed to +see it. + +-------------- + +BMidiLocalConsumer constructor +------------------------------ + +This is similar to the BMidiLocalProducer constructor, although the +contents of the message differ slightly. Again, be:name is optional. + +:: + + OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567) + entry be:type, type='CSTR', c=1, size=9, data[0]: "consumer" + entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x0 (0, '') + entry be:port, type='LONG', c=1, size= 4, data[0]: 0x4c0 (1216, '') + entry be:name, type='CSTR', c=1, size=13, data[0]: "InternalMIDI" + +And the reply: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '') + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +Before it sends the message to the server, the constructor creates a new +port with the name "MidiEventPort" and a queue length (capacity) of 1. + +-------------- + +BMidiEndpoint::Register() +BMidiRoster::Register() +------------------------- + +Sends the same message for producers and consumers: + +:: + + OUT BMessage: what = Mreg (0x4d726567, or 1299342695) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + +The reply: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +If you try to Register() an endpoint that is already registered, +libmidi2 still sends the message. (Which could mean that BMidiRoster +does not keep track of this registered state.) The midi_server simply +ignores that request, and sends back error code 0 (B_OK). So the API +does not flag this as an error. + +If you send an invalid be:id, the midi_server returns error code -1 +(General OS Error, B_ERROR). If you try to Register() a remote endpoint, +libmidi2 immediately returns error code -1, and does not send a message +to the server. + +If another app Register()'s a producer, your BMidiRoster receives: + +:: + + IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '') + entry be:name, type='CSTR', c=1, size=7, data[0]: "a name" + +If the other app registers a consumer, your BMidiRoster receives: + +:: + + IN BMessage: what = mOBJ (0x6d4f424a, or 1833910858) + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x19 (25, '') + entry be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry be:port, type='LONG', c=1, size= 4, data[0]: 0xde9 (3561, '') + entry be:name, type='CSTR', c=1, size=7, data[0]: "a name" + +These are the same messages you get when your BMidiRoster instance is +constructed. In both messages, the be:name field is optional again. + +If the other app Register()'s the endpoint more than once, you still get +only one notification. So the midi_server simply ignores that second +publish request. + +-------------- + +BMidiEndpoint::Unregister() +BMidiRoster::Unregister() +--------------------------- + +Sends the same message for producers and consumers: + +:: + + OUT BMessage: what = Munr (0x4d756e72, or 1299541618) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + +The reply: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +If you try to Unregister() and endpoint that is already unregistered, +libmidi2 still sends the message. The midi_server simply ignores that +request, and sends back error code 0 (B_OK). So the API does not flag +this as an error. If you try to Unregister() a remote endpoint, libmidi2 +immediately returns error code -1, and does not send a message to the +server. + +When another app Unregister()'s one of its own endpoints, your +BMidiRoster receives: + +:: + + IN BMessage: what = mDEL (0x6d44454c, or 1833190732) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '') + +When the other app deletes that endpoint (refcount is now 0) and it is +not unregistered yet, your BMidiRoster also receives that mDEL message. +Multiple Unregisters() are ignored again by the midi_server. + +If an app quits without properly cleaning up, i.e. it does not +Unregister() and Release() its endpoints, then the midi_server's roster +contains a stale endpoint. As soon as the midi_server recognizes this +(for example, when an application tries to connect that endpoint), it +sends all BMidiRosters an mDEL message for this endpoint. (This message +is sent whenever the midi_server feels like it, so libmidi2 can receive +this message while it is still waiting for a reply to some other +message.) If the stale endpoint is still on the roster and you (re)start +your app, then you receive an mOBJ message for this endpoint during the +startup handshake. A little later you will receive the mDEL. + +-------------- + +BMidiEndpoint::Release() +------------------------ + +Only sends a message if the refcount of local objects (published or not) +becomes 0: + +:: + + OUT BMessage: what = Mdel (0x4d64656c, or 1298425196) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + +The corresponding reply: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +If you did not Unregister() a published endpoint before you Release()'d +it, no 'Munr' message is sent. Of course, the midi_server is smart +enough to realize that this endpoint should be wiped from the roster +now. Likewise, if this endpoint is connected to another endpoint, +Release() will not send a separate 'Mdis' message, but the server *will* +disconnect them. (This, of course, only happens when you Release() local +objects. Releasing a proxy has no impact on the connection with the real +endpoint.) + +When you Release() a proxy (a remote endpoint) and its refcount becomes +0, libmidi2 does not send an 'Mdel' message to the server. After all, +the object is not deleted, just your proxy. If the remote endpoint still +exists (i.e. IsValid() returns true), the BMidiRoster actually keeps a +cached copy of the proxy object around, just in case you need it again. +This means you can do this: endp = NextEndpoint(); endp->Release(); (now +refcount is 0) endp- >Acquire(); (now refcount is 1 again). But I advice +against that since it doesn't work for all objects; local and dead +remote endpoints *will* be deleted when their refcount reaches zero. + +In Be's implementation, if you Release() a local endpoint that already +has a zero refcount, libmidi still sends out the 'Mdel' message. It also +drops you into the debugger. (I think it should return an error code +instead, it already has a status_t.) However, if you Release() proxies a +few times too many, your app does not jump into the debugger. (Again, I +think the return result should be an error code here -- for OpenBeOS R1 +I think we should jump into the debugger just like with local objects). +Hmm, actually, whether you end up in the debugger depends on the +contents of memory after the object is deleted, because you perform the +extra Release() on a dead object. Don't do that. + +-------------- + +BMidiEndpoint::SetName() +------------------------ + +For local endpoints, both unpublished and published, libmidi2 sends: + +:: + + OUT BMessage: what = Mnam (0x4d6e616d, or 1299079533) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + entry be:name, type='CSTR', c=1, size=7, data[0]: "b name" + +And receives: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +You cannot rename remote endpoints. If you try, libmidi2 will simply +ignore your request. It does not send a message to the midi_server. + +If another application renames one of its own endpoints, all other +BMidiRosters receive: + +:: + + IN BMessage: what = mREN (0x6d52454e, or 1834108238) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x5 (5, '') + entry be:name, type='CSTR', c=1, size=7, data[0]: "b name" + +You receive this message even if the other app did not publish its +endpoint. This seems rather strange, because your BMidiRoster has no +knowledge of this particular endpoint yet, so what is it to do with this +message? Ignore it, I guess. + +-------------- + +BMidiEndpoint::GetProperties() +------------------------------ + +For *any* kind of endpoint (local non-published, local published, +remote) libmidi2 sends the following message to the server: + +:: + + OUT BMessage: what = Mgpr (0x4d677072, or 1298624626) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x2b2 (690, '') + entry be:props, type='MSGG', c=1, size= 0, + +(Why this "get properties" request includes a BMessage is a mistery to +me. The midi_server does not appear to copy its contents into the reply, +which would have made at least some sense. The BMessage from the client +is completely overwritten with the endpoint's properties.) + +:: + + IN BMessage: what = (0x0, or 0) + entry be:props, type='MSGG', c=1, size= 0, + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +This means that endpoint properties are stored in the server only, not +inside the BMidiEndpoints, and not by the local BMidiRosters. + +-------------- + +BMidiEndpoint::SetProperties() +------------------------------ + +For local endpoints, published or not, libmidi2 sends the following +message to the server: + +:: + + OUT BMessage: what = Mspr (0x4d737072, or 1299411058) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + entry be:props, type='MSGG', c=1, size= 0, + +And expects this back: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +You cannot change the properties of remote endpoints. If you try, +libmidi2 will ignore your request. It does not send a message to the +midi_server, and it returns the -1 error code (B_ERROR). + +If another application changes the properties of one of its own +endpoints, all other BMidiRosters receive: + +:: + + IN BMessage: what = mPRP (0x6d505250, or 1833980496) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') + entry be:properties, type='MSGG', c=1, size= 0, + +You receive this message even if the other app did not publish its +endpoint. + +-------------- + +BMidiLocalConsumer::SetLatency() +-------------------------------- + +For local endpoints, published or not, libmidi2 sends the following +message to the server: + +:: + + OUT BMessage: what = Mlat (0x4d6c6174, or 1298948468) + entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '') + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x14f (335, '') + +And receives: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +If another application changes the latency of one of its own consumers, +all other BMidiRosters receive: + +:: + + IN BMessage: what = mLAT (0x6d4c4154, or 1833714004) + entry be:id, type='LONG', c=1, size= 4, data[0]: 0x15 (21, '') + entry be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '') + +You receive this message even if the other app did not publish its +endpoint. + +-------------- + +BMidiProducer::Connect() +------------------------ + +The message: + +:: + + OUT BMessage: what = Mcon (0x4d636f6e, or 1298362222) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '') + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x376 (886, '') + +The answer: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +The server sends back a B_ERROR result if you specify wrong ID's. When +you try to connect a producer and consumer that are already connected to +each other, libmidi2 still sends the 'Mcon' message to the server (even +though it could have known these endpoints are already connected). In +that case, the server responds with a B_ERROR code as well. + +When another app makes the connection, your BMidiRoster receives: + +:: + + IN BMessage: what = mCON (0x6d434f4e, or 1833127758) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') + +Note: your BMidiRoster receives this notification even if the producer +or the consumer (or both) are not registered endpoints. + +-------------- + +BMidiProducer::Disconnect() +--------------------------- + +The message: + +:: + + OUT BMessage: what = Mdis (0x4d646973, or 1298426227) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x309 (777, '') + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x393 (915, '') + +The answer: + +:: + + IN BMessage: what = (0x0, or 0) + entry be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '') + entry _previous_, ... + +The server sends back a B_ERROR result if you specify wrong ID's. When +you try to disconnect a producer and consumer that are not connected to +each other, libmidi2 still sends the 'Mdis' message to the server (even +though it could have known these endpoints are not connected). In that +case, the server responds with a B_ERROR code as well. + +When another app breaks the connection, your BMidiRoster receives: + +:: + + IN BMessage: what = mDIS (0x6d444953, or 1833191763) + entry be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '') + entry be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '') + +Note: your BMidiRoster receives this notification even if the producer +or the consumer (or both) are not registered endpoints. + +-------------- + +Watchin' +-------- + +BMidiRoster::StartWatching() and StopWatching() do not send messages to +the midi_server. This means that the BMidiRoster itself, and not the +midi_server, sends the notifications to the messenger. It does this +whenever it receives a message from the midi_server. + +The relationship between midi_server messages and B_MIDI_EVENT +notifications is as follows: + + +---------+---------------------------+ + | message | notification | + +=========+===========================+ + | mOBJ | B_MIDI_REGISTERED | + +---------+---------------------------+ + | mDEL | B_MIDI_UNREGISTERED | + +---------+---------------------------+ + | mCON | B_MIDI_CONNECTED | + +---------+---------------------------+ + | mDIS | B_MIDI_DISCONNECTED | + +---------+---------------------------+ + | mREN | B_MIDI_CHANGED_NAME | + +---------+---------------------------+ + | mLAT | B_MIDI_CHANGED_LATENCY | + +---------+---------------------------+ + | mPRP | B_MIDI_CHANGED_PROPERTIES | + +---------+---------------------------+ + +For each message on the left, the watcher will receive the corresponding +notification on the right. + +-------------- + +Other observations +------------------ + +Operations that do not send messages to the midi_server: + +- BMidiEndpoint::Acquire(). This means reference counting is done + locally by BMidiRoster. Release() doesn't send a message either, + unless the refcount becomes 0 and the object is deleted. (Which + suggests that it is actually the destructor and not Release() that + sends the message.) + +- BMidiRoster::NextEndpoint(), NextProducer(), NextConsumer(), + FindEndpoint(), FindProducer(), FindConsumer(). None of these + functions send messages to the midi_server. This means that each + BMidiRoster instance keeps its own list of available endpoints. This + is why it receives 'mOBJ' messages during the startup handshake, and + whenever a new remote endpoint is registered, and 'mDEL' messages for + every endpoint that disappears. Even though the NextXXX() functions + do not return locally created objects, this "local roster" *does* + keep track of them, since FindXXX() *do* return local endpoints. + +- BMidiEndpoint::Name(), ID(), IsProducer(), IsConsumer(), IsRemote(), + IsLocal() IsPersistent(). BMidiConsumer::Latency(). + BMidiLocalConsumer::GetProducerID(), SetTimeout(). These all appear + to consult BMidiRoster's local roster. + +- BMidiEndpoint::IsValid(). This function simply looks at BMidiRoster's + local roster to see whether the remote endpoint is still visible, + i.e. not unregistered. It does not determine whether the endpoint's + application is still alive, or "ping" the endpoint or anything fancy + like that. + +- BMidiProducer::IsConnected(), Connections(). This means that + BMidiRoster's local roster, or maybe the BMidiProducers themselves + (including the proxies) keep track of the various connections. + +- BMidiLocalProducer::Connected(), Disconnected(). These methods are + invoked when any app (including your own) makes or breaks a + connection on one of your local producers. These hooks are invoked + before the B_MIDI_EVENT messages are sent to any watchers. + +- Quitting your app. Even though the BMidiRoster instance is deleted + when the app quits, it does not let the midi_server know that the + application in question is now gone. Any endpoints you have + registered are not automatically unregistered. This means that the + midi_server is left with some stale information. Undoubtedly, there + is a mechanism in place to clean this up. The same mechanism would be + used to clean up apps that did not exit cleanly, or that crashed. + +Other stuff: + +- libmidi2.so exports an int32 symbol called "midi_debug_level". If you + set it to a non-zero value, libmidi2 will dump a lot of interesting + debug info on stdout. To do this, declare the variable in your app + with "extern int32 midi_debug_level;", and then set it to some high + value later: "midi_debug_level = 0x7FFFFFFF;" Now run your app from a + Terminal and watch libmidi2 do its thing. + +- libmidi2.so also exports an int32 symbol called + "midi_dispatcher_priority". This is the runtime priority of the + thread that fields MIDI events to consumers. diff --git a/docs/develop/midi/stuff.html b/docs/develop/midi/stuff.html deleted file mode 100644 index a19754d661..0000000000 --- a/docs/develop/midi/stuff.html +++ /dev/null @@ -1,48 +0,0 @@ - - - -

Misc notes

- -
    - -
  • MPU401 kernel module. If your soundcard supports MIDI input and -output, chances are that it is powered by an MPU401 chip. Because this -interface is so popular, BeOS comes with a kernel module that makes it easy to -write drivers for the MPU401. Thanks to Greg Crain, we now have an open source -version of this kernel module.

    - -

    The mpu401 module lives in src/add-ons/kernel/generic/mpu401. -It supports both the v1 and (undocumented) v2 protocols, although v2 is not -complete since we don't really know how it works. Unfortunately, almost no -existing drivers use v1; most of the drivers provided by Be require v2. -Currently, the module returns B_ERROR when a MIDI device is opened with -v2.

    - -

    For an example on how to use the MPU401 module in your own driver, see -the source code for the "emuxki" driver elsewhere in the source tree.

  • - -
  • Clients without a BApplication. Sometimes the midi_server's -debug output shows an "Application -1 not registered" error message. This -means it cannot figure out which app an incoming BMessage came from. The -server ignores those messages.

    - -

    How can this happen? libmidi2 has two ways of sending messages to the -midi_server: it either expects a reply back or not. In the first case, it is -obvious to the midi_server what the reply address of the message is. In the -second case, even though it is not necessary for the server to send a message -back, it still uses the reply address to determine which app the message came -from. For this, BMessenger uses be_app_messenger of the client app.

    - -

    However, if the client app has no BApplication object, there is no -be_app_messenger either. Now, the midi_server cannot determine where the -message came from and will ignore it. Is this important? For example, when such -a client app Release()'s its endpoints, it sends a message to the server -without a return address. Now the server ignores that message and does not -remove the endpoint from the roster. Of course, after the client app has died, -the endpoints will be removed eventually. Does all of this matter? Not really, -because only trivial apps will have no BApplication object.

  • - -
- - - diff --git a/docs/develop/midi/stuff.rst b/docs/develop/midi/stuff.rst new file mode 100644 index 0000000000..07c1a1d66d --- /dev/null +++ b/docs/develop/midi/stuff.rst @@ -0,0 +1,42 @@ +Misc notes +========== + +- **MPU401 kernel module.** If your soundcard supports MIDI input and + output, chances are that it is powered by an MPU401 chip. Because + this interface is so popular, BeOS comes with a kernel module that + makes it easy to write drivers for the MPU401. Thanks to Greg Crain, + we now have an open source version of this kernel module. + + The mpu401 module lives in ``src/add-ons/kernel/generic/mpu401``. It + supports both the v1 and (undocumented) v2 protocols, although v2 is + not complete since we don't really know how it works. Unfortunately, + almost no existing drivers use v1; most of the drivers provided by Be + require v2. Currently, the module returns B_ERROR when a MIDI device + is opened with v2. + + For an example on how to use the MPU401 module in your own driver, + see the source code for the "emuxki" driver elsewhere in the source + tree. + +- **Clients without a BApplication.** Sometimes the midi_server's debug + output shows an "Application -1 not registered" error message. This + means it cannot figure out which app an incoming BMessage came from. + The server ignores those messages. + + How can this happen? libmidi2 has two ways of sending messages to the + midi_server: it either expects a reply back or not. In the first + case, it is obvious to the midi_server what the reply address of the + message is. In the second case, even though it is not necessary for + the server to send a message back, it still uses the reply address to + determine which app the message came from. For this, BMessenger uses + be_app_messenger of the client app. + + However, if the client app has no BApplication object, there is no + be_app_messenger either. Now, the midi_server cannot determine where + the message came from and will ignore it. Is this important? For + example, when such a client app Release()'s its endpoints, it sends a + message to the server without a return address. Now the server + ignores that message and does not remove the endpoint from the + roster. Of course, after the client app has died, the endpoints will + be removed eventually. Does all of this matter? Not really, because + only trivial apps will have no BApplication object. diff --git a/docs/develop/midi/testing.html b/docs/develop/midi/testing.html deleted file mode 100644 index e6d434708f..0000000000 --- a/docs/develop/midi/testing.html +++ /dev/null @@ -1,566 +0,0 @@ - - - -

Testing the Midi Kit

- -

Most of the OpenBeOS source code has unit tests in the current/src/tests -directory. I looked into building CppUnit tests for the midi2 kit, but decided -that it doesn't really make much sense. Unit tests work best if you can test -something in isolation, but in the case of the midi2 kit this is very hard to -achieve. Because the classes from libmidi2.so always need to talk to the -midi_server, the tests depend on too many external factors. The available -endpoints, for example, will differ from system to system. The spray and hook -functions are difficult to test this way, too.

- -

So instead of a CppUnit test suite, here is a list of manual tests that I -performed when developing the midi2 kit:

- -
- -

Registering the application

- -

Required: Client app that calls BMidiRoster::MidiRoster()

- -
    - -
  • When a client app starts, it should first receive mNEW notifications for -all endpoints in the system (even unregistered remotes), followed by mCON -notifications for all connections in the system (even those between two -unregistered local endpoints from another app).

  • - -
  • Send invalid Mapp message (without messenger). The midi_server ignores -the request, and the client app blocks forever.

  • - -
  • Fake a delivery error for the mNEW notifications and the mAPP reply. -(Add a snooze() in the midi_server's OnRegisterApplication(). While it is -snoozing, Ctrl-C the client app. Now the server can't deliver the message and -will unregister the application again.)

  • - -
  • Kill the server. Start the client app. It should realize that the server -is not running, and return from MidiRoster(); it does not block -forever.

  • - -
  • Note: The server does not protect against sending two or more Mapp -messages; it will add a new app_t object to the roster and it will also send -out the mNEW and mCON notifications again.

  • - -
  • Verify that when the client app quits, the BMidiRoster instance is -destroyed by the BMidiRosterKiller. The BMidiRosterLooper is also destroyed, -along with any endpoint objects from its list. We don't destroy endpoints with -a refcount > 0, but print a warning message on stderr instead.

  • - -
  • When the app quits before it has created a BMidiRoster instance, the -BMidiRosterKiller should do nothing.

  • - -
- -
- -

Creating endpoints

- -

Required: Client app that creates a new BMidiLocalProducer and/or -BMidiLocalConsumer

- -
    - -
  • Send invalid Mnew message (missing fields). The server will return an -error code.

  • - -
  • Don't send reply from midi_server. The client receives a B_NO_REPLY -error.

  • - -
  • If something goes wrong creating a new local endpoint, you still get a -new BMidiEndpoint object (but it is not added to BMidiRosterLooper's internal -list of endpoints). Verify that its ID() function returns 0, and IsValid() -returns false. Verify that you can Release() it without crashing into the -debugger (i.e. the reference count of the new object should be 1).

  • - -
  • Snooze in midi_server's OnCreateEndpoint() before sending reply to -client to simulate heavy processor load. Client should timeout. When done -snoozing, server fails to deliver the reply because the client is no longer -listening, and it unregisters the app.

  • - -
  • Note: if you kill the client app with Ctrl-C before the server has sent -its reply, SendReply() still returns okay, and the midi_server adds the -endpoint, even though the corresponding app is dead. There is not much we can -do to prevent that (but it is not really a big deal).

  • - -
  • Start the test app from two different Terminals. Verify that the new -local endpoint of app1 is added to the BMidiRosterLooper's list of endpoints, -and that its "isLocal" flag is true. Verify that when you start the second app, -it immediately receives mNEW notifications for the first app's endpoints. It -should also create BMidiEndpoint proxy objects for these endpoints with -"isLocal" set to false, and add them its own list. Vice versa for the endpoints -that app2 creates. Verify that the "registered" field in the mNEW notification -is false, because newly created endpoints are not registered yet. The -"properties" field should contain an empty message.

  • - -
  • Start server. Start client app. The app makes new endpoints and the -server adds them to the roster. Ctrl-C the app. Start client app again. The new -client first receives mNEW notifications for the old app's endpoints. When the -new app tries to create its own endpoints, the server realizes that the old app -is dead, and sends mDEL notifications for the now-defunct endpoints.

  • - -
  • The test app should now create 2 endpoints. Let the midi_server snooze -during the second create message, so the app times out. The server now -unregisters the app and purges its first endpoint (which was successfully -created).

  • - -
  • The test app should now create 3 endpoints. Let the midi_server snooze -during the second create message, so the app times out. (It also times out when -sending the create request for the 3rd endpoint, because the server is still -snoozing.) Because it cannot send a reply for the 2nd create message, the -server now unregisters the app and purges its first endpoint (which was -successfully created). Then it processes the create request for the 3rd -endpoint, but ignores it because the app is now no longer registered with the -server.

  • - -
  • Purging endpoints. The test app should now create 2 endpoints. Let the -midi_server snooze during the _fourth_ create message. Run the server. Run the -test app. Run the test app again in a second Terminal. The server times out, -and unregisters the second app. The first app should receive an mDEL -notification. Repeat, but now the test app should make 3 endpoints and the -server fails on the _sixth_ endpoint. The first app now receives 2 mDEL -notifications.

  • - -
  • You should be allowed to pass NULL into the BMidiLocalProducer and -BMidiLocalConsumer constructor.

  • - -
  • Let the midi_server assign random IDs to new endpoints; the -BMidiRosterLooper should sort the endpoints by their IDs when it adds them to -its internal list.

  • - -
- -
- -

Deleting endpoints

- -

Required: client app that creates one or more endpoints and -Release()'s them

- -
    - -
  • Verify that Acquire() increments the endpoint's refcount and Release() -decrements it. When you Release() a local endpoint so its refcount becomes -zero, the client sends an Mdel request to the server. When you Release() a -local endpoint too many times, your app jumps into the debugger.

  • - -
  • Send an Mdel request with an invalid ID to the server. Examples of -invalid IDs: -1, 0, 1000 (or any other large number).

  • - -
  • Start the test app from two different Terminals. Note that when one of -the apps Release()'s its endpoints, the other receives corresponding mDEL -notifications.

  • - -
  • Snooze in midi_server's OnCreateEndpoint() before sending reply to -"create endpoint" request. The client will timeout and the server will -unregister the app. Now have the client Release() the endpoint. This sends a -"delete endpoint" request to the server, which ignores the request because the -app is no longer registered.

  • - -
  • Override BMidiLocalProducer and BMidiLocalConsumer, and provide a public -destructor. Call "delete prod; delete cons;" from your code, instead of using -Release(). Your app should drop into the debugger.

  • - -
  • Start the client app and let it make its endpoints. Kill the server. -Release() the endpoints. The server doesn't run, so the Mdel request never -arrives, but the BMidiEndpoint objects should be deleted regardless.

  • - -
  • Start the test app from two different Terminals, and let them make their -endpoints. Quit the apps (using the Deskbar's "Quit Application" menu item). -Verify that both clean up and exit correctly. App1 removes its own endpoint -from the BMidiRosterLooper's list of endpoints and sends an 'mDEL' message to -the server, which passes it on to app2. In response, app2 removes the proxy -object from its own list and deletes it. Again, vice versa for the endpoint -from app2.

  • - -
  • Start both apps again and wait until they have notified each other about -the endpoints. Ctrl-C app1, and restart it. Verify that app1 receives the -'mNEW' messages and creates proxies for these remote endpoints. Both apps -should receive an 'mDEL' message for app1's old endpoint (because the -midi_server realizes it no longer exists and purges it), and remove it from -their lists accordingly.

  • - -
- -
- -

Changing attributes

- -

Required: Client app that creates an endpoint and calls Register(), -Unregister(), SetName(), and SetLatency()

- -
    - -
  • Send an Mchg request with an invalid ID to the server.

  • - -
  • Register() a local endpoint that is already registered. This does not -send a message to the server and always returns B_OK. Likewise for -Unregister()ing a local endpoint that is not registered.

  • - -
  • Register() or Unregister() a remote endpoint, or an invalid local -endpoint. That should immediately return an error code.

  • - -
  • Verify that BMidiRoster::Register() does the same thing as -BMidiEndpoint::Register(). Also for BMidiRoster::Unregister() and -BMidiEndpoint::Unregister().

  • - -
  • If you pass NULL into BMidiRoster::Register() or Unregister(), the -functions immediately return with an error code.

  • - -
  • SetName() should ignore NULL names. When you call it on a remote -endpoint, SetName() should do nothing. SetName() does not send a message if the -new name is the same as the current name.

  • - -
  • SetLatency() should ignore negative values. SetLatency() does not send a -message if the new latency is the same as the current latency. (Since -SetLatency() lives in BMidiLocalConsumer, you can never use it on remote -endpoints.)

  • - -
  • Kill the server after making the new endpoint, and call Register(). The -client app should return an error code. Also for Unregister(), SetName(), -SetLatency(), and SetProperties().

  • - -
  • Snooze in the midi_server's OnChangeEndpoint() before sending the reply -to the client. Both sides will flag an error. No mCHG notifications will be -sent. The server unregisters the app and purges its endpoints.

  • - -
  • Verify that other apps will receive mCHG notifications when the test app -successfully calls Register(), Unregister(), SetName(), and SetLatency(), and -that they modify the corresponding BMidiEndpoint objects accordingly. Since -clients are never notified when they change their own endpoints, they should -ignore the notifications that concern local endpoints. Latency changes should -be ignored if the endpoint is not a consumer.

  • - -
  • Send an Mchg request with only the "midi:id" field, so no "midi:name", -"midi:registered", "midi:latency", or "midi:properties". The server will still -notify the other apps, although they will obviously ignore the notification, -because it doesn't contain any useful data.

  • - -
  • The Mchg request is overloaded to change several attributes. Verify that -changing one of these attributes, such as the latency, does not overwrite/wipe -out the others.

  • - -
  • Start app1. Wait until it has created and registered its endpoint. Start -app2. During the initial handshake, app2 should receive an 'mNEW' message for -app1's endpoint. Verify that the "refistered" field in this message is already -true, and that this is passed on correctly to the new BMidiEndpoint proxy -object.

  • - -
  • GetProperties() should return NULL if the message parameter is -NULL.

  • - -
  • The properties of new endpoints are empty. Create a new endpoint and -call GetProperties(). The BMessage that you receive should contain no -fields.

  • - -
  • SetProperties() should return NULL if the message parameter is NULL. It -should return an error code if the endpoint is remote or invalid. It should -work fine on local endpoints, registered or not. SetProperties() does not -compare the contents of the new BMessage to the old, so it will always send out -the change request.

  • - -
  • If you Unregister() an endpoint that is connected, the connection should -not be broken.

  • - -
- -
- -

Consulting the roster

- -

Required: Client app that creates several endpoints, and registers -some of them (not all), and uses the BMidiRoster::FindEndpoint() etc functions -to examine the roster.

- -
    - -
  • Verify that FindEndpoint() returns NULL if you pass it:

    - -
      -
    • invalid ID (localOnly = false)
    • -
    • invalid ID (localOnly = true)
    • -
    • remote non-registered endpoint (localOnly = false)
    • -
    • remote non-registered endpoint (localOnly = true)
    • -
    • remote registered endpoint (localOnly = true)
    • -

    - -

    Verify that FindEndpoint() returns a valid BMidiEndpoint object if you pass -it:

    - -
      -
    • local non-registered endpoint (localOnly = false)
    • -
    • local non-registered endpoint (localOnly = true)
    • -
    • local registered endpoint (localOnly = false)
    • -
    • local registered endpoint (localOnly = true)
    • -
    • remote registered endpoint (localOnly = false)
    • -

    - -
  • - -
  • Verify that FindConsumer() works just like FindEndpoint(), but that it -also returns NULL if the endpoint with the specified ID is not a consumer. -Likewise for FindProducer().

  • - -
  • Verify that NextEndpoint() returns NULL if you pass it NULL. It also -returns NULL if no more endpoints exist. Otherwise, it returns a BMidiEndpoint -object, bumps the endpoint's reference count, and sets the "id" parameter to -the ID of the endpoint. NextEndpoint() should never return local endpoints -(registered or not), nor unregistered remote endpoints. Verify that negative -"id" values also work.

  • - -
  • Verify that you can safely call the Find and Next functions without -having somehow initialized the BMidiRoster first (by making a new endpoint, for -example). The functions themselves should call MidiRoster() and do the -handshake with the server.

  • - -
  • The Find and Next functions should bump the reference count of the -BMidiEndpoint object that they return. However, they should not (inadvertently) -modify the refcounts of any other endpoint objects.

  • - -
  • Get a BMidiEndpoint proxy for a remote published endpoint. Release(). -Now it should not be removed from the endpoint list or even be deleted, even -though its reference count dropped to zero.

  • - -
  • Start app1. Start app2. App2 gets a BMidiEndpoint proxy for a remote -endpoint from app1. Ctrl-C app1. Start app1 again. Now app2 receives an mDEL -message for app1's old endpoint. Verify that the endpoint is removed from the -endpoint list, but not deleted because its reference count isn't zero. If app2 -now Release()s the endpoint, the BMidiEndpoint object should be deleted. Try -again, but now Release() the endpoint before you Ctrl-C; now it should be -deleted and removed from the list when you start app1 again.

  • - -
- -
- -

Making/breaking connections

- -

Required: Client app that creates a producer and consumer endpoint, -optionally registers them, consults the roster for remote endpoints, and makes -various kinds of connections.

- -
    - -
  • Test the following for BMidiProducer::Connect():

    - -
      -
    • Connect(NULL)
    • -
    • Connect(invalid consumer)
    • -
    • Connect() using an invalid producer
    • -
    • Send Mcon request with invalid IDs
    • -
    • Kill the midi_server just before you Connect()
    • -
    • Let the midi_server snooze, so the connect request times out
    • -
    • Have the midi_server return an error result code
    • -
    • On successful connect, verify that the consumer is added to the producer's -list of endpoints
    • -
    • Verify that you can make connections between 2 local endpoints, a local -producer and a remote consumer, a remote producer and a local consumer, and two -2 remote endpoints. Test the local endpoints both registered and -unregistered.
    • -
    • 2x Connect() on same consumer should give an error
    • -
    • The other applications should receive an mCON notification, and adjust -their own local rosters accordingly
    • -
    • If you are calling Connect() on a local producer, its Connected() hook -should be called. If you are calling Connect() on a remote producer, then its -own application should call the Connected() hook.
    • -

  • - -
  • Test the following for BMidiProducer::Disconnect():

    - -
      -
    • Disconnect(NULL)
    • -
    • Disconnect(invalid consumer)
    • -
    • Disconnect() using an invalid producer
    • -
    • Send Mdis request with invalid IDs
    • -
    • Kill the midi_server just before you Disconnect()
    • -
    • Let the midi_server snooze, so the disconnect request times out
    • -
    • Have the midi_server return an error result code
    • -
    • On successful disconnect, verify that the consumer is removed from the -producer's list of endpoints
    • -
    • Verify that you can break connections between 2 local endpoints, a local -producer and a remote consumer, a remote producer and a local consumer, and two -2 remote endpoints. Test the local endpoints both registered and -unregistered.
    • -
    • Disconnecting 2 endpoints that were not connected should give an error
    • -
    • The other applications should receive an mDIS notification, and adjust -their own local rosters accordingly
    • -
    • If you are calling Disconnect() on a local producer, its Disconnected() -hook should be called. If you are calling Disconnect() on a remote producer, -then its own application should call the Disconnected() hook.
    • -

  • - -
  • Make a connection on a local producer. Release() the producer. The other -app should only receive an mDEL notification. Likewise if you have a connection -with a local consumer and you Release() that. However, now all apps should -throw away this consumer from the connection lists, invoking the Disconnected() -hook of local producers. The same thing happens if you Ctrl-C the app and -restart it. (Now the old endpoints are purged.)

  • - -
  • BMidiProducer::IsConnected() should return false if you pass NULL or an -invalid consumer.

  • - -
  • BMidiProducer::Connections() should return a new BList every time you -call it. The objects in this list are the BMidiConsumers that are connected to -this producer; verify that their reference counts are bumped for every call to -Connections().

  • - -
- -
- -

Watching

- -

Required: Client app that creates local consumer and producer -endpoints, and calls Register(), Unregister(), SetName(), SetLatency(), and -SetProperties(). It should also make and break connections.

- -
    - -
  • When you call StartWatching(), you should receive B_MIDI_EVENT -notifications for all remote registered endpoints and the connections between -them. You will get no notifications for local endpoints, or for any connections -that involve unregistered endpoints. The BMidiRosterLooper should make a copy -of the BMessenger, so when the client destroys the original messenger, you will -still receive notifications. Verify that calling StartWatching() with the same -BMessenger twice in a row will also send the initial set of notifications -twice. StartWatching(NULL) should be ignored and does not remove the current -messenger.

  • - -
  • Run the client app from two different Terminals. Verify that you receive -properly formatted B_MIDI_EVENT notifications when the other app changes the -attributes of its registered endpoints with the various Set() functions. -You should also receive notifications if the app Register()s or Unregister()s -its endpoints. That app that makes these changes does not receive the -notifications.

  • - -
  • Run the client app from two different Terminals. Verify that you receive -properly formatted B_MIDI_EVENT notifications when the apps make and break -connections. Every app receives these connection notifications, whether the -endpoints are published or not. The app that makes and breaks the connections -does not receive any notifications.

  • - -
  • StopWatching() should delete BMidiRosterLooper's BMessenger copy, if -any. Verify that you no longer receive B_MIDI_EVENT notifications for remote -endpoints after you have called StopWatching().

  • - -
  • If the client is watching, and the BMidiRosterLooper receives an mDEL -notification for a registered remote endpoint, it should also send an -"unregistered" B_MIDI_EVENT to let the client know that this endpoint is no -longer available. If the endpoint was connected to anything, you'll also -receive "disconnected" B_MIDI_EVENTs.

  • - -
  • If you get a "registered" event, and you do FindEndpoint() for that id, -you'll get its BMidiEndpoint object. If you get an "unregistered" event, then -FindEndpoint() returns NULL. So the events are send after the roster is -modified.

  • - -
- -
- -

Event tests

- -

Required: Several client apps that create and register consumer -endpoints that override the various MIDI event hook functions, as well as -producer endpoints that spray MIDI events. Also useful is a tool that lets you -make connections between all these endpoints (PatchBay), and a tool that lets -you monitor the MIDI events (MidiMonitor).

- -
    - -
  • BMidiLocalProducer's spray functions should only try to send something -if there is one or more connected consumer. If the spray functions cannot -deliver their events, they simply ignore that consumer until the next spray. -(No connections are broken or anything.)

  • - -
  • All spray functions except SprayData() should set the atomic flag to -true, even SpraySystemExclusive().

  • - -
  • When you send a sysex message using SpraySystemExclusive(), it should -add 0xF0 in front of your data and 0xF7 at the back. When you call SprayData() -instead, no bytes are added to the MIDI event data.

  • - -
  • Verify that all events arrive correctly and that the latency is minimal, -even when the load is heavy (i.e. many events are being sprayed to many -different consumers).

  • - -
  • Verify that the BMidiLocalConsumer destructor properly destroys the -corresponding port and event thread before it returns.

  • - -
  • BMidiLocalConsumer should ignore messages that are too small, addressed -to another consumer, or otherwise invalid.

  • - -
  • BMidiLocalConsumer's Data() hook should ignore all non-atomic events. -The rest of the events, provided they contain the correct number of bytes for -that kind of event, are passed on to the other hooks.

  • - -
  • Hook a producer up to a consumer and call all SprayXXX() functions with -a variety of arguments to make sure the correct hooks are being called with the -correct values. Call SprayData() and SpraySystemExclusive() with NULL data -and/or length 0.

  • - -
  • Call GetProducerID() from one of BMidiLocalConsumer's hooks to verify -that this indeed returns the ID of the producer that sprayed the -event.

  • - -
  • To test timeouts, first call SetTimeout(system_time() + 2000000), spray -an event to the consumer, and wait 2 seconds. The consumer's Timeout() hook -should now be called. Try again, but now spray multiple events to the consumer. -The Timeout() hook should still be called after 2 seconds, measured from the -moment the timeout was set. Replace the call to SetTimeout() with -SetTimeout(0). After spraying the first event, you should immediately get the -Timeout() signal, because the target time was set in the past. Verify that -calling SetTimeout() only takes effect after at least one new event has been -received.

  • - -
- -
- -

Other tests

- -
    - -
  • Kill the server. Now run a client app. It should recognize that the -server isn't running, and return error codes on all operations. Also kill the -server while the test app is running. From then on, the client app will return -error codes on all operations. Also bring it back up again while the test app -is still running. Now the client app's request messages will be delivered to -the server again, but the server will ignore them, because our app did not -register with this new instance of the server.

  • - -
  • Start the midi_server and several client apps. Use PatchBay to make and -break a whole bunch of connections. Quit PatchBay. Start it again. Now the same -connections should show up. Run similar tests with MidiKeyboard. Also install -VirtualMidi (and run the old midi_server for the time being) to get a whole -bunch of fake MIDI devices.

  • - -
  • Regression bug: After you quit one client app, another app fails -to send request to the midi_server.

    - -

    Required: Client app that creates a new endpoint and registers it. In -the app's destructor, it unregisters and releases the endpoint.

    - -

    How to reproduce: Run the app from two different Terminals. Ctrl-C -app1. Start app1 again. From the Deskbar quit both apps at the same time (that -is possible because app1 and app2 both have the same signature). When it tries -to send the Unregister() request to the midi_server, app2 gives the error -"Cannot send msg to server". The error code is "Bad Port ID", which means that -the reply port is dead. The Mdel message from Release() is sent without any -problems, however, because that expects no reply back. This is not the only way -to reproduce the problem, but it seems to be the most reliable one.

    - -

    The reason this happens is because you kill app1. When app2 sends a -synchronous request to the midi_server, the server re-used that same message to -notify the other apps. (Because it already contained all the necessary fields.) -But app1 is dead, the notification fails, and this (probably) wipes out the -reply address in the message. I changed the midi_server to create new BMessages -for the notifications, and was no longer able to reproduce the -problem.

  • - -
- - - diff --git a/docs/develop/midi/testing.rst b/docs/develop/midi/testing.rst new file mode 100644 index 0000000000..bfa2f49312 --- /dev/null +++ b/docs/develop/midi/testing.rst @@ -0,0 +1,555 @@ +Testing the Midi Kit +==================== + +Most of the OpenBeOS source code has unit tests in the current/src/tests +directory. I looked into building CppUnit tests for the midi2 kit, but +decided that it doesn't really make much sense. Unit tests work best if +you can test something in isolation, but in the case of the midi2 kit +this is very hard to achieve. Because the classes from libmidi2.so +always need to talk to the midi_server, the tests depend on too many +external factors. The available endpoints, for example, will differ from +system to system. The spray and hook functions are difficult to test +this way, too. + +So instead of a CppUnit test suite, here is a list of manual tests that +I performed when developing the midi2 kit: + +-------------- + +Registering the application +--------------------------- + +*Required:* Client app that calls BMidiRoster::MidiRoster() + +- When a client app starts, it should first receive mNEW notifications + for all endpoints in the system (even unregistered remotes), followed + by mCON notifications for all connections in the system (even those + between two unregistered local endpoints from another app). + +- Send invalid Mapp message (without messenger). The midi_server + ignores the request, and the client app blocks forever. + +- Fake a delivery error for the mNEW notifications and the mAPP reply. + (Add a snooze() in the midi_server's OnRegisterApplication(). While + it is snoozing, Ctrl-C the client app. Now the server can't deliver + the message and will unregister the application again.) + +- Kill the server. Start the client app. It should realize that the + server is not running, and return from MidiRoster(); it does not + block forever. + +- Note: The server does not protect against sending two or more Mapp + messages; it will add a new app_t object to the roster and it will + also send out the mNEW and mCON notifications again. + +- Verify that when the client app quits, the BMidiRoster instance is + destroyed by the BMidiRosterKiller. The BMidiRosterLooper is also + destroyed, along with any endpoint objects from its list. We don't + destroy endpoints with a refcount > 0, but print a warning message on + stderr instead. + +- When the app quits before it has created a BMidiRoster instance, the + BMidiRosterKiller should do nothing. + +-------------- + +Creating endpoints +------------------ + +*Required:* Client app that creates a new BMidiLocalProducer and/or +BMidiLocalConsumer + +- Send invalid Mnew message (missing fields). The server will return an + error code. + +- Don't send reply from midi_server. The client receives a B_NO_REPLY + error. + +- If something goes wrong creating a new local endpoint, you still get + a new BMidiEndpoint object (but it is not added to + BMidiRosterLooper's internal list of endpoints). Verify that its ID() + function returns 0, and IsValid() returns false. Verify that you can + Release() it without crashing into the debugger (i.e. the reference + count of the new object should be 1). + +- Snooze in midi_server's OnCreateEndpoint() before sending reply to + client to simulate heavy processor load. Client should timeout. When + done snoozing, server fails to deliver the reply because the client + is no longer listening, and it unregisters the app. + +- Note: if you kill the client app with Ctrl-C before the server has + sent its reply, SendReply() still returns okay, and the midi_server + adds the endpoint, even though the corresponding app is dead. There + is not much we can do to prevent that (but it is not really a big + deal). + +- Start the test app from two different Terminals. Verify that the new + local endpoint of app1 is added to the BMidiRosterLooper's list of + endpoints, and that its "isLocal" flag is true. Verify that when you + start the second app, it immediately receives mNEW notifications for + the first app's endpoints. It should also create BMidiEndpoint proxy + objects for these endpoints with "isLocal" set to false, and add them + its own list. Vice versa for the endpoints that app2 creates. Verify + that the "registered" field in the mNEW notification is false, + because newly created endpoints are not registered yet. The + "properties" field should contain an empty message. + +- Start server. Start client app. The app makes new endpoints and the + server adds them to the roster. Ctrl-C the app. Start client app + again. The new client first receives mNEW notifications for the old + app's endpoints. When the new app tries to create its own endpoints, + the server realizes that the old app is dead, and sends mDEL + notifications for the now-defunct endpoints. + +- The test app should now create 2 endpoints. Let the midi_server + snooze during the second create message, so the app times out. The + server now unregisters the app and purges its first endpoint (which + was successfully created). + +- The test app should now create 3 endpoints. Let the midi_server + snooze during the second create message, so the app times out. (It + also times out when sending the create request for the 3rd endpoint, + because the server is still snoozing.) Because it cannot send a reply + for the 2nd create message, the server now unregisters the app and + purges its first endpoint (which was successfully created). Then it + processes the create request for the 3rd endpoint, but ignores it + because the app is now no longer registered with the server. + +- Purging endpoints. The test app should now create 2 endpoints. Let + the midi_server snooze during the \_fourth\_ create message. Run the + server. Run the test app. Run the test app again in a second + Terminal. The server times out, and unregisters the second app. The + first app should receive an mDEL notification. Repeat, but now the + test app should make 3 endpoints and the server fails on the + \_sixth\_ endpoint. The first app now receives 2 mDEL notifications. + +- You should be allowed to pass NULL into the BMidiLocalProducer and + BMidiLocalConsumer constructor. + +- Let the midi_server assign random IDs to new endpoints; the + BMidiRosterLooper should sort the endpoints by their IDs when it adds + them to its internal list. + +-------------- + +Deleting endpoints +------------------ + +*Required:* client app that creates one or more endpoints and +Release()'s them + +- Verify that Acquire() increments the endpoint's refcount and + Release() decrements it. When you Release() a local endpoint so its + refcount becomes zero, the client sends an Mdel request to the + server. When you Release() a local endpoint too many times, your app + jumps into the debugger. + +- Send an Mdel request with an invalid ID to the server. Examples of + invalid IDs: -1, 0, 1000 (or any other large number). + +- Start the test app from two different Terminals. Note that when one + of the apps Release()'s its endpoints, the other receives + corresponding mDEL notifications. + +- Snooze in midi_server's OnCreateEndpoint() before sending reply to + "create endpoint" request. The client will timeout and the server + will unregister the app. Now have the client Release() the endpoint. + This sends a "delete endpoint" request to the server, which ignores + the request because the app is no longer registered. + +- Override BMidiLocalProducer and BMidiLocalConsumer, and provide a + public destructor. Call "delete prod; delete cons;" from your code, + instead of using Release(). Your app should drop into the debugger. + +- Start the client app and let it make its endpoints. Kill the server. + Release() the endpoints. The server doesn't run, so the Mdel request + never arrives, but the BMidiEndpoint objects should be deleted + regardless. + +- Start the test app from two different Terminals, and let them make + their endpoints. Quit the apps (using the Deskbar's "Quit + Application" menu item). Verify that both clean up and exit + correctly. App1 removes its own endpoint from the BMidiRosterLooper's + list of endpoints and sends an 'mDEL' message to the server, which + passes it on to app2. In response, app2 removes the proxy object from + its own list and deletes it. Again, vice versa for the endpoint from + app2. + +- Start both apps again and wait until they have notified each other + about the endpoints. Ctrl-C app1, and restart it. Verify that app1 + receives the 'mNEW' messages and creates proxies for these remote + endpoints. Both apps should receive an 'mDEL' message for app1's old + endpoint (because the midi_server realizes it no longer exists and + purges it), and remove it from their lists accordingly. + +-------------- + +Changing attributes +------------------- + +*Required:* Client app that creates an endpoint and calls Register(), +Unregister(), SetName(), and SetLatency() + +- Send an Mchg request with an invalid ID to the server. + +- Register() a local endpoint that is already registered. This does not + send a message to the server and always returns B_OK. Likewise for + Unregister()ing a local endpoint that is not registered. + +- Register() or Unregister() a remote endpoint, or an invalid local + endpoint. That should immediately return an error code. + +- Verify that BMidiRoster::Register() does the same thing as + BMidiEndpoint::Register(). Also for BMidiRoster::Unregister() and + BMidiEndpoint::Unregister(). + +- If you pass NULL into BMidiRoster::Register() or Unregister(), the + functions immediately return with an error code. + +- SetName() should ignore NULL names. When you call it on a remote + endpoint, SetName() should do nothing. SetName() does not send a + message if the new name is the same as the current name. + +- SetLatency() should ignore negative values. SetLatency() does not + send a message if the new latency is the same as the current latency. + (Since SetLatency() lives in BMidiLocalConsumer, you can never use it + on remote endpoints.) + +- Kill the server after making the new endpoint, and call Register(). + The client app should return an error code. Also for Unregister(), + SetName(), SetLatency(), and SetProperties(). + +- Snooze in the midi_server's OnChangeEndpoint() before sending the + reply to the client. Both sides will flag an error. No mCHG + notifications will be sent. The server unregisters the app and purges + its endpoints. + +- Verify that other apps will receive mCHG notifications when the test + app successfully calls Register(), Unregister(), SetName(), and + SetLatency(), and that they modify the corresponding BMidiEndpoint + objects accordingly. Since clients are never notified when they + change their own endpoints, they should ignore the notifications that + concern local endpoints. Latency changes should be ignored if the + endpoint is not a consumer. + +- Send an Mchg request with only the "midi:id" field, so no + "midi:name", "midi:registered", "midi:latency", or "midi:properties". + The server will still notify the other apps, although they will + obviously ignore the notification, because it doesn't contain any + useful data. + +- The Mchg request is overloaded to change several attributes. Verify + that changing one of these attributes, such as the latency, does not + overwrite/wipe out the others. + +- Start app1. Wait until it has created and registered its endpoint. + Start app2. During the initial handshake, app2 should receive an + 'mNEW' message for app1's endpoint. Verify that the "refistered" + field in this message is already true, and that this is passed on + correctly to the new BMidiEndpoint proxy object. + +- GetProperties() should return NULL if the message parameter is NULL. + +- The properties of new endpoints are empty. Create a new endpoint and + call GetProperties(). The BMessage that you receive should contain no + fields. + +- SetProperties() should return NULL if the message parameter is NULL. + It should return an error code if the endpoint is remote or invalid. + It should work fine on local endpoints, registered or not. + SetProperties() does not compare the contents of the new BMessage to + the old, so it will always send out the change request. + +- If you Unregister() an endpoint that is connected, the connection + should not be broken. + +-------------- + +Consulting the roster +--------------------- + +*Required:* Client app that creates several endpoints, and registers +some of them (not all), and uses the BMidiRoster::FindEndpoint() etc +functions to examine the roster. + +- Verify that FindEndpoint() returns NULL if you pass it: + + - invalid ID (localOnly = false) + - invalid ID (localOnly = true) + - remote non-registered endpoint (localOnly = false) + - remote non-registered endpoint (localOnly = true) + - remote registered endpoint (localOnly = true) + + | + + Verify that FindEndpoint() returns a valid BMidiEndpoint object if + you pass it: + + - local non-registered endpoint (localOnly = false) + - local non-registered endpoint (localOnly = true) + - local registered endpoint (localOnly = false) + - local registered endpoint (localOnly = true) + - remote registered endpoint (localOnly = false) + + | + +- Verify that FindConsumer() works just like FindEndpoint(), but that + it also returns NULL if the endpoint with the specified ID is not a + consumer. Likewise for FindProducer(). + +- Verify that NextEndpoint() returns NULL if you pass it NULL. It also + returns NULL if no more endpoints exist. Otherwise, it returns a + BMidiEndpoint object, bumps the endpoint's reference count, and sets + the "id" parameter to the ID of the endpoint. NextEndpoint() should + never return local endpoints (registered or not), nor unregistered + remote endpoints. Verify that negative "id" values also work. + +- Verify that you can safely call the Find and Next functions without + having somehow initialized the BMidiRoster first (by making a new + endpoint, for example). The functions themselves should call + MidiRoster() and do the handshake with the server. + +- The Find and Next functions should bump the reference count of the + BMidiEndpoint object that they return. However, they should not + (inadvertently) modify the refcounts of any other endpoint objects. + +- Get a BMidiEndpoint proxy for a remote published endpoint. Release(). + Now it should not be removed from the endpoint list or even be + deleted, even though its reference count dropped to zero. + +- Start app1. Start app2. App2 gets a BMidiEndpoint proxy for a remote + endpoint from app1. Ctrl-C app1. Start app1 again. Now app2 receives + an mDEL message for app1's old endpoint. Verify that the endpoint is + removed from the endpoint list, but not deleted because its reference + count isn't zero. If app2 now Release()s the endpoint, the + BMidiEndpoint object should be deleted. Try again, but now Release() + the endpoint before you Ctrl-C; now it should be deleted and removed + from the list when you start app1 again. + +-------------- + +Making/breaking connections +--------------------------- + +*Required:* Client app that creates a producer and consumer endpoint, +optionally registers them, consults the roster for remote endpoints, and +makes various kinds of connections. + +- Test the following for BMidiProducer::Connect(): + + - Connect(NULL) + - Connect(invalid consumer) + - Connect() using an invalid producer + - Send Mcon request with invalid IDs + - Kill the midi_server just before you Connect() + - Let the midi_server snooze, so the connect request times out + - Have the midi_server return an error result code + - On successful connect, verify that the consumer is added to the + producer's list of endpoints + - Verify that you can make connections between 2 local endpoints, a + local producer and a remote consumer, a remote producer and a + local consumer, and two 2 remote endpoints. Test the local + endpoints both registered and unregistered. + - 2x Connect() on same consumer should give an error + - The other applications should receive an mCON notification, and + adjust their own local rosters accordingly + - If you are calling Connect() on a local producer, its Connected() + hook should be called. If you are calling Connect() on a remote + producer, then its own application should call the Connected() + hook. + + | + +- Test the following for BMidiProducer::Disconnect(): + + - Disconnect(NULL) + - Disconnect(invalid consumer) + - Disconnect() using an invalid producer + - Send Mdis request with invalid IDs + - Kill the midi_server just before you Disconnect() + - Let the midi_server snooze, so the disconnect request times out + - Have the midi_server return an error result code + - On successful disconnect, verify that the consumer is removed from + the producer's list of endpoints + - Verify that you can break connections between 2 local endpoints, a + local producer and a remote consumer, a remote producer and a + local consumer, and two 2 remote endpoints. Test the local + endpoints both registered and unregistered. + - Disconnecting 2 endpoints that were not connected should give an + error + - The other applications should receive an mDIS notification, and + adjust their own local rosters accordingly + - If you are calling Disconnect() on a local producer, its + Disconnected() hook should be called. If you are calling + Disconnect() on a remote producer, then its own application should + call the Disconnected() hook. + + | + +- Make a connection on a local producer. Release() the producer. The + other app should only receive an mDEL notification. Likewise if you + have a connection with a local consumer and you Release() that. + However, now all apps should throw away this consumer from the + connection lists, invoking the Disconnected() hook of local + producers. The same thing happens if you Ctrl-C the app and restart + it. (Now the old endpoints are purged.) + +- BMidiProducer::IsConnected() should return false if you pass NULL or + an invalid consumer. + +- BMidiProducer::Connections() should return a new BList every time you + call it. The objects in this list are the BMidiConsumers that are + connected to this producer; verify that their reference counts are + bumped for every call to Connections(). + +-------------- + +Watching +-------- + +*Required:* Client app that creates local consumer and producer +endpoints, and calls Register(), Unregister(), SetName(), SetLatency(), +and SetProperties(). It should also make and break connections. + +- When you call StartWatching(), you should receive B_MIDI_EVENT + notifications for all remote registered endpoints and the connections + between them. You will get no notifications for local endpoints, or + for any connections that involve unregistered endpoints. The + BMidiRosterLooper should make a copy of the BMessenger, so when the + client destroys the original messenger, you will still receive + notifications. Verify that calling StartWatching() with the same + BMessenger twice in a row will also send the initial set of + notifications twice. StartWatching(NULL) should be ignored and does + not remove the current messenger. + +- Run the client app from two different Terminals. Verify that you + receive properly formatted B_MIDI_EVENT notifications when the other + app changes the attributes of its *registered* endpoints with the + various Set() functions. You should also receive notifications if the + app Register()s or Unregister()s its endpoints. That app that makes + these changes does not receive the notifications. + +- Run the client app from two different Terminals. Verify that you + receive properly formatted B_MIDI_EVENT notifications when the apps + make and break connections. Every app receives these connection + notifications, whether the endpoints are published or not. The app + that makes and breaks the connections does not receive any + notifications. + +- StopWatching() should delete BMidiRosterLooper's BMessenger copy, if + any. Verify that you no longer receive B_MIDI_EVENT notifications for + remote endpoints after you have called StopWatching(). + +- If the client is watching, and the BMidiRosterLooper receives an mDEL + notification for a registered remote endpoint, it should also send an + "unregistered" B_MIDI_EVENT to let the client know that this endpoint + is no longer available. If the endpoint was connected to anything, + you'll also receive "disconnected" B_MIDI_EVENTs. + +- If you get a "registered" event, and you do FindEndpoint() for that + id, you'll get its BMidiEndpoint object. If you get an "unregistered" + event, then FindEndpoint() returns NULL. So the events are send + *after* the roster is modified. + +-------------- + +Event tests +----------- + +*Required:* Several client apps that create and register consumer +endpoints that override the various MIDI event hook functions, as well +as producer endpoints that spray MIDI events. Also useful is a tool that +lets you make connections between all these endpoints (PatchBay), and a +tool that lets you monitor the MIDI events (MidiMonitor). + +- BMidiLocalProducer's spray functions should only try to send + something if there is one or more connected consumer. If the spray + functions cannot deliver their events, they simply ignore that + consumer until the next spray. (No connections are broken or + anything.) + +- All spray functions except SprayData() should set the atomic flag to + true, even SpraySystemExclusive(). + +- When you send a sysex message using SpraySystemExclusive(), it should + add 0xF0 in front of your data and 0xF7 at the back. When you call + SprayData() instead, no bytes are added to the MIDI event data. + +- Verify that all events arrive correctly and that the latency is + minimal, even when the load is heavy (i.e. many events are being + sprayed to many different consumers). + +- Verify that the BMidiLocalConsumer destructor properly destroys the + corresponding port and event thread before it returns. + +- BMidiLocalConsumer should ignore messages that are too small, + addressed to another consumer, or otherwise invalid. + +- BMidiLocalConsumer's Data() hook should ignore all non-atomic events. + The rest of the events, provided they contain the correct number of + bytes for that kind of event, are passed on to the other hooks. + +- Hook a producer up to a consumer and call all SprayXXX() functions + with a variety of arguments to make sure the correct hooks are being + called with the correct values. Call SprayData() and + SpraySystemExclusive() with NULL data and/or length 0. + +- Call GetProducerID() from one of BMidiLocalConsumer's hooks to verify + that this indeed returns the ID of the producer that sprayed the + event. + +- To test timeouts, first call SetTimeout(system_time() + 2000000), + spray an event to the consumer, and wait 2 seconds. The consumer's + Timeout() hook should now be called. Try again, but now spray + multiple events to the consumer. The Timeout() hook should still be + called after 2 seconds, measured from the moment the timeout was set. + Replace the call to SetTimeout() with SetTimeout(0). After spraying + the first event, you should immediately get the Timeout() signal, + because the target time was set in the past. Verify that calling + SetTimeout() only takes effect after at least one new event has been + received. + +-------------- + +Other tests +----------- + +- Kill the server. Now run a client app. It should recognize that the + server isn't running, and return error codes on all operations. Also + kill the server while the test app is running. From then on, the + client app will return error codes on all operations. Also bring it + back up again while the test app is still running. Now the client + app's request messages will be delivered to the server again, but the + server will ignore them, because our app did not register with this + new instance of the server. + +- Start the midi_server and several client apps. Use PatchBay to make + and break a whole bunch of connections. Quit PatchBay. Start it + again. Now the same connections should show up. Run similar tests + with MidiKeyboard. Also install VirtualMidi (and run the old + midi_server for the time being) to get a whole bunch of fake MIDI + devices. + +- *Regression bug:* After you quit one client app, another app fails to + send request to the midi_server. + + *Required:* Client app that creates a new endpoint and registers it. + In the app's destructor, it unregisters and releases the endpoint. + + *How to reproduce:* Run the app from two different Terminals. Ctrl-C + app1. Start app1 again. From the Deskbar quit both apps at the same + time (that is possible because app1 and app2 both have the same + signature). When it tries to send the Unregister() request to the + midi_server, app2 gives the error "Cannot send msg to server". The + error code is "Bad Port ID", which means that the reply port is dead. + The Mdel message from Release() is sent without any problems, + however, because that expects no reply back. This is not the only way + to reproduce the problem, but it seems to be the most reliable one. + + The reason this happens is because you kill app1. When app2 sends a + synchronous request to the midi_server, the server re-used that same + message to notify the other apps. (Because it already contained all + the necessary fields.) But app1 is dead, the notification fails, and + this (probably) wipes out the reply address in the message. I changed + the midi_server to create new BMessages for the notifications, and + was no longer able to reproduce the problem. diff --git a/docs/develop/midi/todo.html b/docs/develop/midi/todo.html deleted file mode 100644 index c3eec4fb64..0000000000 --- a/docs/develop/midi/todo.html +++ /dev/null @@ -1,45 +0,0 @@ - - - -

OpenBeOS Midi Kit TO DO List

- -

May 14, 2004

- -

Big Things

- -

Softsynth. We need a General MIDI softsynth. We can either write it ourselves or port an existing one. I was thinking about FluidSynth (formerly IIWU Synth) since it is very good and supports SoundFonts, but I had trouble writing a BeOS audio driver for it. FluidSynth is also GPL, but that is not a major problem. Must be implemented in the BSoftSynth class from libmidi.so

- -

Test libmidi.so The BMidiSynth, BMidiSynthFile, BSamples, and BSynth classes have been implemented and briefly tested. They seemed to work fine, even with the R5 MidiPlayer app. However, the only proper way to test them is with sound output, and for that we need the softsynth.

- -

Small Things

- -

Communicating with device drivers. The midi_server already has a pretty good parser that turns an incoming stream of bytes into MIDI messages. It uses read() to read a single byte at a time. However, the midi_driver.h file lists a number of ioctl() opcodes that we are currently not using. Should we? In addition, do we really need to spawn a new thread for each device? The R5 midi_server doesn't appear to do this. An optional feature is to implement "running status" for MIDI OUT ports (i.e. when writing to the device driver). This would be pretty simple to add.

- -

BMidiStore is slow. Importing a Standard MIDI File of a few hundred kilobytes takes too long for my taste. The one from R5 is at least twice as fast. It is important to speed this up since BMidiStore is used by BMidiSynthFile to play MIDI files. We don't want games to slow down too much.

- -

MPU401 kernel module. Greg Crain did a great job of writing this module. Unfortunately, we only know how the v1 interface works; v2 is not documented. What's worse, most Be R5 drivers use v2. Currently, the module returns B_ERROR when a device is opened with v2. Is this going to be a problem for us? It depends on whether we will be able to use the closed-source Be drivers with our own kernel — if not, then we can simply ignore v2.

- -

BSynth::GetAudio() This function fills up a user-provided buffer with recent sample data. Mostly used to display scopes and other visual trickery. Whether we will support this or not depends on the capabilities of the softsynth back-end.

- -

Watching /dev/midi for changes. Whenever a new device appears in /dev/midi, the midi_server must create and publish a new MidiProducer and MidiConsumer for that device. When a device disappears, its endpoints must be removed again. Philippe Houdoin suggested we use the device_watcher for this, but R5 doesn't appear to do it that way. Either it uses node monitoring or doesn't do this at all. Our midi_server already has a DeviceWatcher class, but it only examines the entries from /dev/midi when the server starts, not while the server is running.

- -

BMidiSynthFile::Fade() Right now this simply calls Stop(). We could set a flag in BMidiStore (which handles our playback), which would then slowly reduce the volume and abort the loop after a few seconds. But we need to have the softsynth in order to tune this properly.

- -

Must be_synth be deleted when the app quits? I have not found a word about this, nor a way to test what happens in R5. For example, the BMidiSynth constructor creates a BSynth object (if none already existed), but we cannot destroy be_synth from the BMidiSynth destructor because it may still be used in other places in the code (BSynth is not refcounted). We could add the following code to libmidi.so to clean up properly, but I don't know if it is really necessary:

- -
namespace BPrivate
-{
-    static struct BSynthKiller
-    {
-        ~BSynthKiller()
-        {
-            delete be_synth;
-        }
-    }
-    synth_killer;
-}
- -

midiparser kernel module. midi_driver.h (from the Sonic Vibes driver sample code) contains the definition of a "midiparser" kernel module. This is a very simple module that makes it easy to recognize where MIDI messages begin and end, but apparently doesn't tell you what they mean. In R5, this module lives in /boot/beos/system/add-ons/kernel/media. Does anyone use this module? Is it necessary for us to provide it? Personally, I'd say foggeddaboutit.

- - - diff --git a/docs/develop/midi/todo.rst b/docs/develop/midi/todo.rst new file mode 100644 index 0000000000..e7632f3339 --- /dev/null +++ b/docs/develop/midi/todo.rst @@ -0,0 +1,70 @@ +Midi Kit TO DO List +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Communicating with device drivers.** The midi_server already has a +pretty good parser that turns an incoming stream of bytes into MIDI +messages. It uses read() to read a single byte at a time. However, the +midi_driver.h file lists a number of ioctl() opcodes that we are +currently not using. Should we? In addition, do we really need to spawn +a new thread for each device? The R5 midi_server doesn't appear to do +this. An optional feature is to implement "running status" for MIDI OUT +ports (i.e. when writing to the device driver). This would be pretty +simple to add. + +**BMidiStore is slow.** Importing a Standard MIDI File of a few hundred +kilobytes takes too long for my taste. The one from R5 is at least twice +as fast. It is important to speed this up since BMidiStore is used by +BMidiSynthFile to play MIDI files. We don't want games to slow down too +much. + +**MPU401 kernel module.** Greg Crain did a great job of writing this +module. Unfortunately, we only know how the v1 interface works; v2 is +not documented. What's worse, most Be R5 drivers use v2. Currently, the +module returns B_ERROR when a device is opened with v2. Is this going to +be a problem for us? It depends on whether we will be able to use the +closed-source Be drivers with our own kernel — if not, then we can +simply ignore v2. + +**Watching /dev/midi for changes.** Whenever a new device appears in +/dev/midi, the midi_server must create and publish a new MidiProducer +and MidiConsumer for that device. When a device disappears, its +endpoints must be removed again. Philippe Houdoin suggested we use the +device_watcher for this, but R5 doesn't appear to do it that way. Either +it uses node monitoring or doesn't do this at all. Our midi_server +already has a DeviceWatcher class, but it only examines the entries from +/dev/midi when the server starts, not while the server is running. + +**BMidiSynthFile::Fade()** Right now this simply calls Stop(). We could +set a flag in BMidiStore (which handles our playback), which would then +slowly reduce the volume and abort the loop after a few seconds. But we +need to have the softsynth in order to tune this properly. + +**Must be_synth be deleted when the app quits?** I have not found a word +about this, nor a way to test what happens in R5. For example, the +BMidiSynth constructor creates a BSynth object (if none already +existed), but we cannot destroy be_synth from the BMidiSynth destructor +because it may still be used in other places in the code (BSynth is not +refcounted). We could add the following code to libmidi.so to clean up +properly, but I don't know if it is really necessary: + + :: + + namespace BPrivate + { + static struct BSynthKiller + { + ~BSynthKiller() + { + delete be_synth; + } + } + synth_killer; + } + +**midiparser kernel module.** midi_driver.h (from the Sonic Vibes driver +sample code) contains the definition of a "midiparser" kernel module. +This is a very simple module that makes it easy to recognize where MIDI +messages begin and end, but apparently doesn't tell you what they mean. +In R5, this module lives in /boot/beos/system/add-ons/kernel/media. Does +anyone use this module? Is it necessary for us to provide it? +Personally, I'd say foggeddaboutit. diff --git a/docs/develop/net/HowTo-Synchronize_with_NetBSD.md b/docs/develop/net/HowTo-Synchronize_with_NetBSD.md deleted file mode 100644 index b452663ba2..0000000000 --- a/docs/develop/net/HowTo-Synchronize_with_NetBSD.md +++ /dev/null @@ -1,30 +0,0 @@ -How to Merge Patches from NetBSD Trunk -============================================ -Using the NetBSD CVS is a pain, so instead, the preferred thing to do is to use -[the official Git mirror](https://github.com/NetBSD/src). The code here is -in the tree at a few places:`inet` is at `lib/libc/inet`, irs is scattered -across the tree, and `resolv` is at `lib/libc/resolv`. - -The preferable way to merge is to take the last commit merged from IIJ's mirror -(can be found in the merging commit in Haiku, if the merger has done their work -properly) and check all commits since then to see if they apply or not (some -apply to documentation we don't have, etc.) Cherry-pick the ones that do, and -download them as git-format-patch patches (by adding `.patch` onto the end of the -commit URL). - -To convert the patches to have the correct paths to the resolv/inet/etc. code, use -`sed`: -``` -sed s%lib/libc/resolv%src/kits/network/netresolv/resolv%g -i *.patch -``` -(You'll need to use similar commands for the `inet` and `irs` code.) - -Then apply the patches using `git apply --reject file.patch`. Git will spew a lot of -errors about files in the patch that aren't in the tree, and then it will warn that -some hunks are being rejected. Review the rejected hunks **VERY CAREFULLY**, as -some code in Haiku's NetResolv is not in NetBSD's and vice versa, and so some patches -may not apply cleanly because of that. You might have to resort to merging those -hunks by hand, if they apply at all to Haiku's code. - -Commit the changes all at once, but list all the commits merged from NetBSD -in the commit message (see previous merges for the style to follow). diff --git a/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst b/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst new file mode 100644 index 0000000000..1f016fd5e1 --- /dev/null +++ b/docs/develop/net/HowTo-Synchronize_with_NetBSD.rst @@ -0,0 +1,36 @@ +How to Merge Patches from NetBSD Trunk +====================================== + +Using the NetBSD CVS is a pain, so instead, the preferred thing to do is +to use `the official Git mirror `__. The +code here is in the tree at a few places:\ ``inet`` is at +``lib/libc/inet``, irs is scattered across the tree, and ``resolv`` is +at ``lib/libc/resolv``. + +The preferable way to merge is to take the last commit merged from IIJ’s +mirror (can be found in the merging commit in Haiku, if the merger has +done their work properly) and check all commits since then to see if +they apply or not (some apply to documentation we don’t have, etc.) +Cherry-pick the ones that do, and download them as git-format-patch +patches (by adding ``.patch`` onto the end of the commit URL). + +To convert the patches to have the correct paths to the resolv/inet/etc. +code, use ``sed``: + +:: + + sed s%lib/libc/resolv%src/kits/network/netresolv/resolv%g -i *.patch + +(You’ll need to use similar commands for the ``inet`` and ``irs`` code.) + +Then apply the patches using ``git apply --reject file.patch``. Git will +spew a lot of errors about files in the patch that aren’t in the tree, +and then it will warn that some hunks are being rejected. Review the +rejected hunks **VERY CAREFULLY**, as some code in Haiku’s NetResolv is +not in NetBSD’s and vice versa, and so some patches may not apply +cleanly because of that. You might have to resort to merging those hunks +by hand, if they apply at all to Haiku’s code. + +Commit the changes all at once, but list all the commits merged from +NetBSD in the commit message (see previous merges for the style to +follow). diff --git a/docs/develop/net/Network Stack Overview.html b/docs/develop/net/Network Stack Overview.html deleted file mode 100644 index 001dbe4e66..0000000000 --- a/docs/develop/net/Network Stack Overview.html +++ /dev/null @@ -1,218 +0,0 @@ - - -

Haiku Network Stack Architecture

-

- The Haiku Network Stack is a modular and layered networking stack, very - similar to what you may know as BONE. -

-

- The entry point when talking to the stack is through a dedicated device - driver that publish itself in /dev/net. The userland library libnetwork.so - (which combines libsocket.so, and libbind.so) directly talks to this - driver, mostly via ioctl()1. -

- The driver either creates sockets, or passes on every command to the socket - module2. Depending on the address family and - type of the sockets, the lower layers will be loaded and connected. -

-

- For example, with a TCP/IP socket, the stack could look like this: - - - - - - - - - - - - -
Socket
TCP

Protocols
- defined by the socket (address family, type)

- (session, transport, network layers)
IPv4
Datalink
ARP

Datalink Protocols
- defined by the interface (IP address, device)

- (datalink layer)
Ethernet framing
Ethernet device(physical layer)
- Where TCP, and IPv4 are net_protocol modules, and ARP, and the Ethernet framing are - net_datalink_protocol modules. All modules are connected in a chain, even though the - datalink layer introduces more than one path (one for each interface). -

-

- When sending data through a socket, a net_buffer is created in the socket module, and passed - on to the lower levels where each protocol processes it, before passing it on to the next - protocol in the chain. The last protocol in the chain is always a domain protocol - it will - directly forward the buffers to the datalink module. When the buffer reaches the datalink - level, an accompanied net_route object will determine for which interface (which determines - the datalink protocols in the chain) the buffer is destined. The route has to be specified - by the upper protocols before the buffer gets into the datalink level - if a buffer comes - in without a valid route, it is discarded. -

-

- The protocol modules are loaded and unloaded as needed. The stack itself stays loaded - as long as there are interfaces defined - as soon as the last interface is removed, - the stack gets unloaded (which is, of course, not yet implemented). -

-

The Structures and Classes

-

net_domain

-

- Every supported address family gets its own domain. A domain comprises such a family, - a net_protocol module that handles this domain, and a list of interfaces and routes. - It also gets a name: for example, the IPv4 module registers the "internet" domain - (AF_INET). -

-

- The domain protocol module is responsible for managing the domain; it has to register - it when it's loaded, and it has to unregister it when it is unloaded by the networking - stack. -

-

net_interface

-

- An interface makes an underlying net_device accessible by the stack. When creating - a new interface, you have to specify a domain, and a device to be used. The stack - will then look through the registered datalink protocols, and builds a chain of - them for that interface. -

-

- The interface usually gets a network address, and a route that directs buffers to - be sent to it. If there is no route to an interface, it will never be used for - outgoing data, but may well receive data from other hosts. -

-

- An interface can be "up" (when IFF_UP is set in its flags - member) in which case it accepts data - when that flag is not set, it will discard - all data it gets. The interface also specifies the maximum buffer size that can be - sent over this interface (the mtu member, a.k.a. maximum transmission - unit). -

-

- Interfaces are configured via ioctl()s (SIOCAIFADDR, ...). You can use the command - line tool "ifconfig" to do this for you. -

-

net_device

-

- A networking device is used to actually send and receive the buffers. It either points - to an actual hardware device (in case of ethernet), or to a virtual device (in case of - loopback). Every device has a unique name that identifies it. When creating a device, - the name also decides which net_device module will be chosen; for example, everything - that starts with "loop" will end up in the loopback device, while the ethernet device - accepts names that start with "/dev/net/". -

-

- A device can be shared by many interfaces at the same time. The device to be used by - an interface is specified at the time an interface is created. - It also has an mtu member that determines the upper limit of an interface's - mtu as well. -

-

net_buffer

-

- A buffer holds exactly one packet, and has a source as well as a destination address. - The addresses may be changed in every layer the buffer passes through. For example, - the datalink protocols usually use sockaddr_dl structures with family AF_DLI, while - the upper levels may use sockaddr_in structures with family AF_INET. Every protocol - only supports a small number of address types, and it's the requirement of the upper - protocols to prepare the address for use in the lower protocols (and that's also a - reason why it wouldn't work to arbitrarily stack protocols onto each other). -

-

- The net_buffer module can be used to access the data within the buffer, append new - data to the buffer, or remove chunks of data from it. Internally, the buffer consists - of usually fixed size (2048 byte) buffers that can be shared or connected as needed. -

-

net_socket

-

- The socket is only of interest for the net_protocol modules, as it stores options - that may have an effect on the protocol's performance. It's the direct counterpart - to a socket file descriptor in userland, but it has only little logic bound to it. -

-

- When a socket is created, the networking stack creates a chain of net_protocol - modules for the socket that will then do the real work. When the socket is closed, - the net_protocol chain is freed, and the modules are eventually unloaded (if they - are no longer in use). -

-

net_protocol

-

- The protocols are bound to a specific socket, process the outgoing buffers as needed - (ie. add or remove headers, compute checksums, ...), and pass it on to the next - protocol. The last protocol in the chain is always a domain protocol that will forward - the calls to the datalink module directly, if needed. -

-

- A domain protocol is a net_protocol that registered a domain, ie. IPv4. Other than usual - protocols, domain protocols have some special requirements: -

    -
  • they need to be able to execute send_data(), and get_domain() without a pointer to - its net_protocol object, as those may be called outside of the socket context.
  • -
  • as mentioned, they also don't talk to the next protocol in the chain (as they are - always the last one), but to the datalink module directly.
  • -
-

-

- Similar to the need to perform send_data() outside of the socket context, all protocols - that can receive data need to handle incoming data without the socket context: incoming - data is always handled outside of the socket context, as the actual target socket - is unknown during processing. -

-

- Only the top-most protocol will be able to forward the packet to the target socket(s). - To receive incoming data, a protocol must register itself as receiving protocol with - the networking stack. The domain protocol is usually registered automatically by a - net_datalink_protocol module that knows about both ends (for example, the ARP - module is both IPv4 and ethernet specific, and therefore registers the AF_INET - domain to receive ethernet packets of type IP). -

-

net_datalink_protocol

-

- The datalink protocols are bound to a specific net_interface, and therefore to a - specific net_device as well. Outgoing data is processed so that it can be sent - via the net_device. For example, the ARP protocol will replace sockaddr_in structures - in the buffer with sockaddr_dl structures describing the ethernet MAC address of - the source and destination hosts, the ethernet_frame protocol will add the usual - ethernet header, etc. -

-

- The last protocol in the chain is also a special device interface bridge protocol, - that redirects the calls to the underlying net_device. -

-

- Incoming data is handled differently again; when you want to receive data directly - coming from a device, you can either register a deframing function for it, or a - handler that will be called depending on what data type the deframing module reported. - For example, the ethernet_frame module registers an ethernet deframing function, while - the ARP module registers a handler for ethernet ARP packets with the device. When the - deframing function reports a ETHER_TYPE_ARP packet, the ARP receiving - function will be called. -

-

net_route

-

- A route determines the target interface of an outgoing packet. A route is always - owned by a specific domain, and the route is chosen by comparing the networking - address of the outgoing buffer with the mask and address of the route. -

-

- A protocol will usually not use the routes directly, but use a net_route_info - object (see below), that will make sure that the route is updated automatically - whenever the routing table is changed. -

-

net_route_info

-

- A routing helper for protocol usage: it stores the target address as well as the - route to be used, and has to be registered with the networking stack via - register_route_info(). -

-

- Then, the stack will automatically update the route as needed, whenever the - routing table of the domain changes; it will always matches the address specified - there. When the routing is no longer needed, you must unregister the net_route_info - again. -

-
- - 1 You can find the definition of the driver interface - in headers/private/net/net_stack_interface.h, as well as - the driver itself at src/add-ons/kernel/drivers/network
- 2src/add-ons/kernel/network/stack/ -
- - diff --git a/docs/develop/net/NetworkStackOverview.rst b/docs/develop/net/NetworkStackOverview.rst new file mode 100644 index 0000000000..e4a99dfe5f --- /dev/null +++ b/docs/develop/net/NetworkStackOverview.rst @@ -0,0 +1,227 @@ +Haiku Network Stack Architecture +================================ + +The Haiku Network Stack is a modular and layered networking stack, very +similar to what you may know as BONE. + +The entry point when talking to the stack is through a dedicated device +driver that publish itself in /dev/net. The userland library +libnetwork.so (which combines libsocket.so, and libbind.so) directly +talks to this driver, mostly via ioctl()\ `1 <#foot1>`__. + +The driver either creates sockets, or passes on every command to the +socket module\ `2 <#foot2>`__. Depending on the address family and type +of the sockets, the lower layers will be loaded and connected. + +For example, with a TCP/IP socket, the stack could look like this: + ++------------------+--------------------------------------------------------+ +| **Socket** | ++------------------+--------------------------------------------------------+ +| TCP | Protocols defined by the socket (address family, type) | ++------------------+ | +| IPv4 | (session, transport, network layers) | ++------------------+--------------------------------------------------------+ +| **Datalink** | ++------------------+--------------------------------------------------------+ +| ARP | Datalink Protocols defined by the interface | +| | (IP address, device) | ++------------------+ | +| Ethernet framing | (datalink layer) | ++------------------+--------------------------------------------------------+ +| Ethernet device | (physical layer) | ++------------------+--------------------------------------------------------+ + +Where TCP, and IPv4 are net_protocol modules, and ARP, and the Ethernet +framing are net_datalink_protocol modules. All modules are connected in +a chain, even though the datalink layer introduces more than one path +(one for each interface). + +When sending data through a socket, a net_buffer is created in the +socket module, and passed on to the lower levels where each protocol +processes it, before passing it on to the next protocol in the chain. +The last protocol in the chain is always a domain protocol - it will +directly forward the buffers to the datalink module. When the buffer +reaches the datalink level, an accompanied net_route object will +determine for which interface (which determines the datalink protocols +in the chain) the buffer is destined. The route has to be specified by +the upper protocols before the buffer gets into the datalink level - if +a buffer comes in without a valid route, it is discarded. + +The protocol modules are loaded and unloaded as needed. The stack itself +stays loaded as long as there are interfaces defined - as soon as the +last interface is removed, the stack gets unloaded (which is, of course, +not yet implemented). + +The Structures and Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +net_domain +^^^^^^^^^^ + +Every supported address family gets its own domain. A domain comprises +such a family, a net_protocol module that handles this domain, and a +list of interfaces and routes. It also gets a name: for example, the +IPv4 module registers the "internet" domain (AF_INET). + +The domain protocol module is responsible for managing the domain; it +has to register it when it's loaded, and it has to unregister it when it +is unloaded by the networking stack. + +net_interface +^^^^^^^^^^^^^ + +An interface makes an underlying net_device accessible by the stack. +When creating a new interface, you have to specify a domain, and a +device to be used. The stack will then look through the registered +datalink protocols, and builds a chain of them for that interface. + +The interface usually gets a network address, and a route that directs +buffers to be sent to it. If there is no route to an interface, it will +never be used for outgoing data, but may well receive data from other +hosts. + +An interface can be "up" (when ``IFF_UP`` is set in its ``flags`` +member) in which case it accepts data - when that flag is not set, it +will discard all data it gets. The interface also specifies the maximum +buffer size that can be sent over this interface (the ``mtu`` member, +a.k.a. maximum transmission unit). + +Interfaces are configured via ioctl()s (SIOCAIFADDR, ...). You can use +the command line tool "ifconfig" to do this for you. + +net_device +^^^^^^^^^^ + +A networking device is used to actually send and receive the buffers. It +either points to an actual hardware device (in case of ethernet), or to +a virtual device (in case of loopback). Every device has a unique name +that identifies it. When creating a device, the name also decides which +net_device module will be chosen; for example, everything that starts +with "loop" will end up in the loopback device, while the ethernet +device accepts names that start with "/dev/net/". + +A device can be shared by many interfaces at the same time. The device +to be used by an interface is specified at the time an interface is +created. It also has an ``mtu`` member that determines the upper limit +of an interface's ``mtu`` as well. + +net_buffer +^^^^^^^^^^ + +A buffer holds exactly one packet, and has a source as well as a +destination address. The addresses may be changed in every layer the +buffer passes through. For example, the datalink protocols usually use +sockaddr_dl structures with family AF_DLI, while the upper levels may +use sockaddr_in structures with family AF_INET. Every protocol only +supports a small number of address types, and it's the requirement of +the upper protocols to prepare the address for use in the lower +protocols (and that's also a reason why it wouldn't work to arbitrarily +stack protocols onto each other). + +The net_buffer module can be used to access the data within the buffer, +append new data to the buffer, or remove chunks of data from it. +Internally, the buffer consists of usually fixed size (2048 byte) +buffers that can be shared or connected as needed. + +net_socket +^^^^^^^^^^ + +The socket is only of interest for the net_protocol modules, as it +stores options that may have an effect on the protocol's performance. +It's the direct counterpart to a socket file descriptor in userland, but +it has only little logic bound to it. + +When a socket is created, the networking stack creates a chain of +net_protocol modules for the socket that will then do the real work. +When the socket is closed, the net_protocol chain is freed, and the +modules are eventually unloaded (if they are no longer in use). + +net_protocol +^^^^^^^^^^^^ + +The protocols are bound to a specific socket, process the outgoing +buffers as needed (ie. add or remove headers, compute checksums, ...), +and pass it on to the next protocol. The last protocol in the chain is +always a domain protocol that will forward the calls to the datalink +module directly, if needed. + +A domain protocol is a net_protocol that registered a domain, ie. IPv4. +Other than usual protocols, domain protocols have some special +requirements: + +- they need to be able to execute send_data(), and get_domain() without + a pointer to its net_protocol object, as those may be called outside + of the socket context. +- as mentioned, they also don't talk to the next protocol in the chain + (as they are always the last one), but to the datalink module + directly. + +Similar to the need to perform send_data() outside of the socket +context, all protocols that can receive data need to handle incoming +data without the socket context: incoming data is always handled outside +of the socket context, as the actual target socket is unknown during +processing. + +Only the top-most protocol will be able to forward the packet to the +target socket(s). To receive incoming data, a protocol must register +itself as receiving protocol with the networking stack. The domain +protocol is usually registered automatically by a net_datalink_protocol +module that knows about both ends (for example, the ARP module is both +IPv4 and ethernet specific, and therefore registers the AF_INET domain +to receive ethernet packets of type IP). + +net_datalink_protocol +^^^^^^^^^^^^^^^^^^^^^ + +The datalink protocols are bound to a specific net_interface, and +therefore to a specific net_device as well. Outgoing data is processed +so that it can be sent via the net_device. For example, the ARP protocol +will replace sockaddr_in structures in the buffer with sockaddr_dl +structures describing the ethernet MAC address of the source and +destination hosts, the ethernet_frame protocol will add the usual +ethernet header, etc. + +The last protocol in the chain is also a special device interface bridge +protocol, that redirects the calls to the underlying net_device. + +Incoming data is handled differently again; when you want to receive +data directly coming from a device, you can either register a deframing +function for it, or a handler that will be called depending on what data +type the deframing module reported. For example, the ethernet_frame +module registers an ethernet deframing function, while the ARP module +registers a handler for ethernet ARP packets with the device. When the +deframing function reports a ``ETHER_TYPE_ARP`` packet, the ARP +receiving function will be called. + +net_route +^^^^^^^^^ + +A route determines the target interface of an outgoing packet. A route +is always owned by a specific domain, and the route is chosen by +comparing the networking address of the outgoing buffer with the mask +and address of the route. + +A protocol will usually not use the routes directly, but use a +net_route_info object (see below), that will make sure that the route is +updated automatically whenever the routing table is changed. + +net_route_info +^^^^^^^^^^^^^^ + +A routing helper for protocol usage: it stores the target address as +well as the route to be used, and has to be registered with the +networking stack via ``register_route_info()``. + +Then, the stack will automatically update the route as needed, whenever +the routing table of the domain changes; it will always matches the +address specified there. When the routing is no longer needed, you must +unregister the net_route_info again. + +-------------- + +| 1 You can find the definition of the driver interface in + `headers/private/net/net_stack_interface.h `__, + as well as the driver itself at + `src/add-ons/kernel/drivers/network `__ +| 2\ `src/add-ons/kernel/network/stack/ `__ diff --git a/docs/develop/packages/PackagingPolicy.rst b/docs/develop/packages/PackagingPolicy.rst index 9202eda4d7..5503c9fc45 100644 --- a/docs/develop/packages/PackagingPolicy.rst +++ b/docs/develop/packages/PackagingPolicy.rst @@ -135,6 +135,6 @@ alternative. A typical use would be to create a desktop icon that the user can move around or delete. Pre-Uninstallation Scripts -========================= +========================== These undo the effects of a post-installation script and usually are put into "boot/pre-uninstall". A typical use is to remove desktop icons. diff --git a/docs/develop/packages/README.rst b/docs/develop/packages/README.rst index e58c85a59d..fbc83fc94b 100644 --- a/docs/develop/packages/README.rst +++ b/docs/develop/packages/README.rst @@ -90,3 +90,16 @@ Below are links to source code related to Haiku's package management. - haikuporter_ is the tool to create binary packages from build recipes. .. _haikuporter: https://github.com/haikuports/haikuporter + + +.. toctree:: + /packages/BuildingPackages + /packages/DirectoryStructure + /packages/FileFormat + /packages/HybridBuilds + /packages/Infrastructure + /packages/Migration + /packages/PackagingPolicy + /packages/Bootstrapping + /packages/TODO + /packages/OldIdeas diff --git a/docs/develop/partitioning_systems/sun.rst b/docs/develop/partitioning_systems/sun.rst new file mode 100644 index 0000000000..cdab951fbe --- /dev/null +++ b/docs/develop/partitioning_systems/sun.rst @@ -0,0 +1,113 @@ +Partitioning system for Sun Sparc machines +========================================== + +Infos extracted from `File System Forensic Analysis, Brian Carrier `_ +and in particular the `online copy here `_), tables 6.9 and 6.10. + +The format is called VTOC (volume table of contents). It is stored at offset 0 +on-disk. All values are big endian. + +Note that the x86 version of Solaris uses a different layout. + ++------------+--------------------------------+ +| Byte offset|Description | ++============+================================+ +| 0-127 |ASCII disk label | ++------------+--------------------------------+ +| 128-261 |VTOC * | ++------------+--------------------------------+ +| 262-263 |Sectors to skip when writing | ++------------+--------------------------------+ +| 264-265 |Setors to skip when reading | ++------------+--------------------------------+ +| 266-419 |Reserved | ++------------+--------------------------------+ +| 420-421 |Disk speed | ++------------+--------------------------------+ +| 422-423 |Number of cylinders | ++------------+--------------------------------+ +| 424-425 |Alternates per cylinder | ++------------+--------------------------------+ +| 426-429 |Reserved | ++------------+--------------------------------+ +| 430-431 |Interleave | ++------------+--------------------------------+ +| 432-433 |Number of data cylinders | ++------------+--------------------------------+ +| 434-435 |Number of alternate cylinders | ++------------+--------------------------------+ +| 436-437 |Number of heads | ++------------+--------------------------------+ +| 438-439 |Number of sectors per track | ++------------+--------------------------------+ +| 440-443 |Reserved | ++------------+--------------------------------+ +| 444-451 |Partition 1 disk map | ++------------+--------------------------------+ +| ... |More partition disk maps | ++------------+--------------------------------+ +| 500-507 |Partition 8 disk map | ++------------+--------------------------------+ +| 508-509 |Signature (0xDABE) | ++------------+--------------------------------+ +| 510-511 |Checksum | ++------------+--------------------------------+ + +The VTOC itself: + ++---------+-----------------------------------+ +| 0-3 | Version | ++---------+-----------------------------------+ +| 4-11 | Volume name | ++---------+-----------------------------------+ +| 12-13 | Number of partitions | ++---------+-----------------------------------+ +| 14-15 | Partition 1 type | ++---------+-----------------------------------+ +| 16-17 | Partition 1 flags | ++---------+-----------------------------------+ +| ... | More partition types and flags | ++---------+-----------------------------------+ +| 42-45 | Partition 8 type and flags | ++---------+-----------------------------------+ +| 46-57 | Boot info | ++---------+-----------------------------------+ +| 58-59 | Reserved | ++---------+-----------------------------------+ +| 60-63 | Signature 0x600DDEEE | ++---------+-----------------------------------+ +| 64-101 | Reserved | ++---------+-----------------------------------+ +| 102-105 | Partition 1 timestamp | ++---------+-----------------------------------+ +| ... | More partition timestamps | ++---------+-----------------------------------+ +| 130-133 | Parittion 8 timestamp | ++---------+-----------------------------------+ + +Partition types (informative): + +0. unassigned +1. /boot +2. / +3. swap +4. /usr +5. entire disk +6. /stand +7. /var +8. /home +9. alternate sector +10. cachefs + +Partition flags: + +* 1 - Not mountable +* 128 - read only + +Disk maps: + ++-----+-------------------+ +| 0-3 | Starting cylinder | ++-----+-------------------+ +| 4-7 | Size (in sectors) | ++-----+-------------------+ diff --git a/docs/develop/partitioning_systems/sun.txt b/docs/develop/partitioning_systems/sun.txt deleted file mode 100644 index a280c777d5..0000000000 --- a/docs/develop/partitioning_systems/sun.txt +++ /dev/null @@ -1,72 +0,0 @@ -Partitioning system for Sun Sparc machines -========================================== - -Infos extracted from [File System Forensic Analysis, Brian Carrier](urn:isbn:0-134-43954-6) -and in particular the [online copy here](https://books.google.fr/books?id=Zpm9CgAAQBAJ&lpg=PT159&ots=6LIQ6blJCF&dq=solaris%20vtoc%20structure&hl=fr&pg=PT159#v=onepage&q=solaris%20vtoc%20structure&f=false), tables 6.9 and 6.10. - -The format is called VTOC (volume table of contents). It is stored at offset 0 -on-disk. All values are big endian. - -Note that the x86 version of Solaris uses a different layout. - -Byte offset|Description -0-127 |ASCII disk label -128-261 |VTOC * -262-263 |Sectors to skip when writing -264-265 |Setors to skip when reading -266-419 |Reserved -420-421 |Disk speed -422-423 |Number of cylinders -424-425 |Alternates per cylinder -426-429 |Reserved -430-431 |Interleave -432-433 |Number of data cylinders -434-435 |Number of alternate cylinders -436-437 |Number of heads -438-439 |Number of sectors per track -440-443 |Reserved -444-451 |Partition 1 disk map -... |More partition disk maps -500-507 |Partition 8 disk map -508-509 |Signature (0xDABE) -510-511 |Checksum - -The VTOC itself: - -0-3 Version -4-11 Volume name -12-13 Number of partitions -14-15 Partition 1 type -16-17 Partition 1 flags -... More partition types and flags -42-45 Partition 8 type and flags -46-57 Boot info -58-59 Reserved -60-63 Signature 0x600DDEEE -64-101 Reserved -102-105 Partition 1 timestamp -... More partition timestamps -130-133 Parittion 8 timestamp - -Partition types (informative): - -0 unassigned -1 /boot -2 / -3 swap -4 /usr -5 entire disk -6 /stand -7 /var -8 /home -9 alternate sector -10 cachefs - -Partition flags: -1 Not mountable -128 read only - -Disk maps: - -0-3 Starting cylinder -4-7 Size (in sectors) diff --git a/docs/develop/servers/app_server/AppServer.htm b/docs/develop/servers/app_server/AppServer.htm deleted file mode 100644 index 9b1ad587d7..0000000000 --- a/docs/develop/servers/app_server/AppServer.htm +++ /dev/null @@ -1,705 +0,0 @@ - - -AppServer.htm - - - -
-

AppServer class

-


-

-

The AppServer class sits at the top of the hierarchy, starting and stopping services, monitoring for messages, and so forth.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - -
-

AppServer(void)

-
-

~AppServer(void)

-
-

static int32 Poller(void *data)

-
-

static int32 Picasso(void *data)

-
-

thread_id Run(void)

-
-

void MainLoop(void)

-
-

bool LoadDecorator(const char *path)

-
-

void DispatchMessage(int32 code, int8 *buffer)

-
-

void Broadcast(int32 code)

-
-

void HandleKeyMessage(int32 code, int8 *buffer)

-
-


-
-Global Functions

-


-Decorator * instantiate_decorator(Layer *owner, uint32 wflags, uint32 wlook)

-


-
-


-

-

AppServer(void)

-


-1) Create the message and input ports

-

2) Create any necessary semaphores for regulating the 3 main threads

-

3) Initialize all member variables

-

4) Allocate the application BList

-

5) Read in and process all configuration data

-

6) Initialize the desktop

-

7) Spawn the Picasso and Poller threads

-


-
-~AppServer(void)

-


-1) Shut down the desktop

-

2) Empty and delete the application list

-

3) Wait for Picasso and Poller to exit

-

4) Free any allocated heap space

-


-
-void MainLoop(void)

-


-MainLoop is one large loop used to monitor the main message port in the app_server thread. This is a standard port-monitoring loop code:

-


-1) Call port_buffer_size - which will block if the port is empty

-

2) Allocate a buffer on the heap if the port buffer size is greater than 0

-

3) Read the port

-

4) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized

-

5) Return from DispatchMessage() and free the message buffer if one was allocated

-

6) If the message code matches the B_QUIT_REQUESTED definition and the quit_server flag is true, fall out of the infinite message-monitoring loop

-


-
-void DispatchMessage(int32 code, int8 *buffer)

-


-DispatchMessage implements all the code necessary to respond to a given message sent to the app_server on its main port. This allows for clearer and more manageable code.

-


-CREATE_APP:

-


-Sent by a new BApplication object via synchronous PortLink messaging. Set up the corresponding ServerApp and reply to the BApplication with the new port to which it will send future communications with the App Server.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - -
-

port_id reply_port

-
-

port to which the server is to reply in response to the current message

-
-

port_id app_port

-
-

message port for the requesting BApplication

-
-

int16 sig_length

-
-

length of the following application signature

-
-

const char *signature

-
-

Signature of the requesting BApplication

-
-


-

-


-1) Get all attached data

-

2) Acquire the application list lock

-

3) Allocate a ServerApp object and add it to the list

-

4) Release application list lock

-

5) Acquire active application pointer lock

-

6) Update active application pointer

-

7) Release active application lock

-

8) Send the message SET_SERVER_PORT (with the ServerApp's receiver port attached) to the reply port

-

9) Run() the new ServerApp instance

-


-
-DELETE_APP:

-


-Sent by a ServerApp when told to quit either by its BApplication or the Server itself (during shutdown). It is identified by the unique ID assigned to its thread.

-


-Attached Data:

-


-

-

- - - - - -
-

thread_id app_thread

-
-

Thread id of the ServerApp sending this message

-
-


-

-


-1) Get app's thread_id

-

2) Acquire application list lock

-

3) Iterate through the application list, searching for the ServerApp object with the sent thread_id

-

4) Remove the object from the list and delete it

-

5) Acquire active application lock

-

6) Check to see if the application is active

-

7) If application is/was active, set it to the previous application in the list or NULL if there are no other active applications

-

8) Release application list lock

-

9) Release active application lock

-


-
-GET_SCREEN_MODE:

-


-Received from the OpenBeOS Input Server when requesting the current screen settings via synchronous PortLink messaging. This is a temporary solution which will be deprecated as soon as the BScreen class is complete.

-


-

-

Attached Data:

-


-

-

- - - - - -
-

port_id reply_port

-
-

port to which the server is to reply in response to the current message

-
-


-

-


-1) Get height, width, and color depth from the global graphics driver object

-

2) Attach via PortLink and reply to sender

-


-B_QUIT_REQUESTED:

-


-Encountered only under testing situations where the Server is told to quit.

-


-Attached Data: None

-


-1) Set quit_server flag to true

-

2) Call Broadcast(QUIT_APP)

-


-
-SET_DECORATOR:

-


-Received from just about anything when a new window decorator is chosen

-


-

-

Attached Data:

-


-

-

- - - - - -
-

const char *path

-
-

Path to the proposed new decorator

-
-


-

-


-1) Get the path from the buffer

-

2) Call LoadDecorator()

-


-
-void Run(void)

-


-Run() exists mostly for consistency with other regular applications.

-


-1) Call MainLoop()

-


-
-bool LoadDecorator(const char *path)

-


-Allows for a simple way to change the current window decorator systemwide simply by specifying the path to the desired Decorator addon.

-


-1) Load the passed string as the path to an addon.

-

2) Load all necessary symbols for the decorator

-

3) Return false if things didn't go so well

-

4) Call Broadcast(UPDATE_DECORATOR)

-

5) Return true

-


-static int32 Picasso(void *data)

-


-Picasso is a function, despite its name, dedicated to ensuring that the server deallocates resources to a dead application. It consists of a while(!quit_server) loop as follows:

-


-1) Acquire the appliction list lock

-

2) Iterate through the list, calling each ServerApp object's PingTarget() method.

-

3) If PingTarget returns false, remove the ServerApp from the list and delete it.

-

4) Release the appliction list lock

-

5) snooze for 3 seconds

-


-static int32 Poller(void *data)

-


-Poller is the main workhorse of the AppServer class, polling the Server's input port constantly for any messages from the Input Server and calling the appropriate handlers. Like Picasso, it, too, is mostly a while(!quit_server) loop.

-


-

-

1) Call port_buffer_size_etc() with a timeout of 3 seconds.

-

2) Check to see if the port_buffer_size_etc() timed out and do a continue to next iteration if it did.

-

3) Allocate a buffer on the heap if the port buffer size is greater than 0

-

4) Read the port

-

5) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized

-

6) Return from DispatchMessage() and free the message buffer if one was allocated

-


-
-


-

-

Decorator * instantiate_decorator(Layer *owner, uint32 wflags, uint32 wlook)

-


-instantiate_decorator returns a new instance of the decorator currently in use. The caller is responsible for the memory allocated for the returned object.

-


-1) Acquire the decorator lock

-

2) If create_decorator is NULL, create a new instance of the default decorator

-

3) If create_decorator is non-NULL, create a new decorator instance by calling AppServer::create_decorator().

-

4) Release the decorator lock

-

5) Return the newly allocated instance

-


-void Broadcast(int32 code)

-


-Broadcast() provides the AppServer class with an easy way to send a quick message to all ServerApps. Primarily, this is called when a font or decorator has changed, or when the server is shutting down. It is not intended to do anything except send a quick message which requires no extra data, such as for some upadate signalling.

-


-

-

1) Acquire application list lock

-

2) Create a PortLink instance and set its message code to the passed parameter.

-

3) Iterate through the application list, targeting the PortLink instance to each ServerApp's message port and calling Flush().

-

4) Release application list lock

-


-void HandleKeyMessage(int32 code, int8 *buffer)

-


-

-

Called from DispatchMessage to filter out App Server events and otherwise send keystrokes to the active application.

-


-B_KEY_DOWN:

-


-Sent when the user presses (or holds down) a key that's been mapped to a character.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

int64 when

-
-

event time in seconds since 1/1/70

-
-

int32 rawcode

-
-

code for the physical key pressed

-
-

int32 repeat_count

-
-

number of times a key has been repeated

-
-

int32 modifiers

-
-

flags signifying the states of the modifier keys

-
-

int32 state_count

-
-

number of bytes to follow containing the state of all keys

-
-

int8 *states

-
-

array of the state of all keys at the time of the event

-
-

int8 utf8data[3]

-
-

UTF-8 data generated

-
-

int8 charcount

-
-

number of bytes to follow containing the string generated (usually 1)

-
-

const char *string

-
-

null-terminated string generated by the keystroke

-
-

int32 raw_char

-
-

modifier-independent ASCII code for the character

-
-


-

-


-1) Get all attached data

-

2) If the command modifier is down, check for Left Ctrl+Left Alt+Left Shift+F12 and reset the workspace to 640 x 480 x 256 @ 60Hz and return if true

-

3) If the command modifier is down, check for Alt+F1 through Alt+F12 and set workspace and return if true

-

4) If the control modifier is true, check for B_CONTROL_KEY+Tab and, if true, find and send to the Deskbar.

-

4) Acquire the active application lock

-

5) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_KEY_DOWN, attach the buffer en masse, and send it to the BApplication.

-

6) Release the active application lock

-


-

-

B_KEY_UP:

-


-

-

Sent when the user releases a key that's been mapped to a character.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

int64 when

-
-

event time in seconds since 1/1/70

-
-

int32 rawcode

-
-

code for the physical key pressed

-
-

int32 modifiers

-
-

flags signifying the states of the modifier keys

-
-

int32 state_count

-
-

number of bytes to follow containing the state of all keys

-
-

int8 *states

-
-

array of the state of all keys at the time of the event

-
-

int8 utf8data[3]

-
-

UTF-8 data generated

-
-

int8 charcount

-
-

number of bytes to follow containing the string generated (usually 1)

-
-

const char *string

-
-

null-terminated string generated by the keystroke

-
-

int32 raw_char

-
-

modifier-independent ASCII code for the character

-
-


-

-


-1) Get all attached data

-

2) Acquire the active application lock

-

3) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_KEY_UP, attach the buffer en masse, and send it to the BApplication.

-

4) Release the active application lock

-


-B_UNMAPPED_KEY_DOWN:

-


-

-

Sent when the user presses a key that has not been mapped to a character.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - -
-

int64 when

-
-

event time in seconds since 1/1/70

-
-

int32 rawcode

-
-

code for the physical key pressed

-
-

int32 modifiers

-
-

flags signifying the states of the modifier keys

-
-

int8 state_count

-
-

number of bytes to follow containing the state of all keys

-
-

int8 *states

-
-

array of the state of all keys at the time of the event

-
-


-

-


-1) Acquire the active application lock

-

2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_UNMAPPED_KEY_DOWN, attach the buffer en masse, and send it to the BApplication.

-

3) Release the active application lock

-


-B_UNMAPPED_KEY_UP:

-


-

-

Sent when the user presses a key that has not been mapped to a character.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - -
-

int64 when

-
-

event time in seconds since 1/1/70

-
-

int32 rawcode

-
-

code for the physical key pressed

-
-

int32 modifiers

-
-

flags signifying the states of the modifier keys

-
-

int8 state_count

-
-

number of bytes to follow containing the state of all keys

-
-

int8 *states

-
-

array of the state of all keys at the time of the event

-
-


-

-


-1) Acquire the active application lock

-

2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_UNMAPPED_KEY_UP, attach the buffer en masse, and send it to the BApplication.

-

3) Release the active application lock

-


-

-

B_MODIFIERS_CHANGED:

-


-

-

Sent when the user presses or releases one of the modifier keys

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - -
-

int64 when

-
-

event time in seconds since 1/1/70

-
-

int32 modifiers

-
-

flags signifying the states of the modifier keys

-
-

int32 old_modifiers

-
-

former states of the modifier keys

-
-

int8 state_count

-
-

number of bytes to follow containing the state of all keys

-
-

int8 *states

-
-

array of the state of all keys at the time of the event

-
-


-

-


-1) Acquire the active application lock

-

2) Create a PortLink instance, target the active ServerApp's sender port, set the opcode to B_MODIFIERS_CHANGED, attach the buffer en masse, and send it to the BApplication.

-

3) Release the active application lock

-
-
-
- - diff --git a/docs/develop/servers/app_server/AppServer.rst b/docs/develop/servers/app_server/AppServer.rst new file mode 100644 index 0000000000..d6c755c2c2 --- /dev/null +++ b/docs/develop/servers/app_server/AppServer.rst @@ -0,0 +1,456 @@ + +AppServer class +############### + +The AppServer class sits at the top of the hierarchy, starting and +stopping services, monitoring for messages, and so forth. + +Member Functions +================ + +- AppServer(void) +- ~AppServer(void) +- static int32 Poller(void \*data) +- static int32 Picasso(void \*data) +- thread_id Run(void) +- void MainLoop(void) +- bool LoadDecorator(const char\*path) +- void DispatchMessage(int32 code,int8 \*buffer) +- void Broadcast(int32 code) +- void HandleKeyMessage(int32 code, int8 \*buffer) + +Global Functions +================ + +Decorator \* instantiate_decorator(Layer \*owner, uint32 wflags, uint32 wlook) + +AppServer(void) +=============== + +1. Create the message and input ports +2. Create any necessary semaphores for regulating the 3 main threads +3. Initialize all member variables +4. Allocate the application BList +5. Read in and process all configuration data +6. Initialize the desktop +7. Spawn the Picasso and Poller threads + +~AppServer(void) +================ + +1. Shut down the desktop +2. Empty and delete the application list +3. Wait for Picasso and Poller to exit +4. Free any allocated heap space + +void MainLoop(void) +=================== + +MainLoop is one large loop used to monitor the main message port in +the app_server thread. This is a standard port-monitoring loop code: + + +1. Call port_buffer_size - which will block if the port is empty +2. Allocate a buffer on the heap if the port buffer size is greater than 0 +3. Read the port +4. Pass specified messages to DispatchMessage() for processing, spitting + out an error message to stderr if the message's code is unrecognized +5. Return from DispatchMessage() and free the message buffer if one was + allocated +6. If the message code matches the B_QUIT_REQUESTED definition and the + quit_server flag is true, fall out of the infinite message-monitoring + loop + +void DispatchMessage(int32 code, int8 \*buffer) +=============================================== + +DispatchMessage implements all the code necessary to respond to a +given message sent to the app_server on its main port. This allows for +clearer and more manageable code. + + +CREATE_APP +---------- + +Sent by a new BApplication object via synchronous PortLink messaging. +Set up the corresponding ServerApp and reply to the BApplication with +the new port to which it will send future communications with the App +Server. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| port_id reply_port | port to which the server is to | +| | reply in response to the current | +| | message | ++-----------------------------------+-----------------------------------+ +| port_id app_port | message port for the requesting | +| | BApplication | ++-----------------------------------+-----------------------------------+ +| int16 sig_length | length of the following | +| | application signature | ++-----------------------------------+-----------------------------------+ +| const char \*signature | Signature of the requesting | +| | BApplication | ++-----------------------------------+-----------------------------------+ + + +1. Get all attached data +2. Acquire the application list lock +3. Allocate a ServerApp object and add it to the list +4. Release application list lock +5. Acquire active application pointer lock +6. Update active application pointer +7. Release active application lock +8. Send the message SET_SERVER_PORT (with the ServerApp's receiver port + attached) to the reply port +9. Run() the new ServerApp instance + +DELETE_APP +---------- + +Sent by a ServerApp when told to quit either by its BApplication or +the Server itself (during shutdown). It is identified by the unique ID +assigned to its thread. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| thread_id app_thread | Thread id of the ServerApp | +| | sending this message | ++-----------------------------------+-----------------------------------+ + +1. Get app's thread_id +2. Acquire application list lock +3. Iterate through the application list, searching for the ServerApp + object with the sent thread_id +4. Remove the object from the list and delete it +5. Acquire active application lock +6. Check to see if the application is active +7. If application is/was active, set it to the previous application in + the list or NULL if there are no other active applications +8. Release application list lock +9. Release active application lock + +GET_SCREEN_MODE +--------------- + +Received from the OpenBeOS Input Server when requesting the current +screen settings via synchronous PortLink messaging. This is a +temporary solution which will be deprecated as soon as the BScreen +class is complete. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| port_id reply_port | port to which the server is to | +| | reply in response to the current | +| | message | ++-----------------------------------+-----------------------------------+ + +1. Get height, width, and color depth from the global graphics driver + object +2. Attach via PortLink and reply to sender + +B_QUIT_REQUESTED +---------------- + +Encountered only under testing situations where the Server is told to +quit. + +Attached Data: None + +1. Set quit_server flag to true +2. Call Broadcast(QUIT_APP) + +SET_DECORATOR +------------- + +Received from just about anything when a new window decorator is +chosen + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| const char \*path | Path to the proposed new | +| | decorator | ++-----------------------------------+-----------------------------------+ + +1. Get the path from the buffer +2. Call LoadDecorator() + +void Run(void) +============== + +Run() exists mostly for consistency with other regular applications. + +1) Call MainLoop() + +bool LoadDecorator(const char \*path) +===================================== + +Allows for a simple way to change the current window decorator +systemwide simply by specifying the path to the desired Decorator +addon. + +1. Load the passed string as the path to an addon. +2. Load all necessary symbols for the decorator +3. Return false if things didn't go so well +4. Call Broadcast(UPDATE_DECORATOR) +5. Return true + +static int32 Picasso(void \*data) +================================= + +Picasso is a function, despite its name, dedicated to ensuring that +the server deallocates resources to a dead application. It consists of +a while(!quit_server) loop as follows: + +1) Acquire the appliction list lock +2) Iterate through the list, calling each ServerApp object's + PingTarget() method. +3) If PingTarget returns false, remove the ServerApp from the list and + delete it. +4) Release the appliction list lock +5) snooze for 3 seconds + +static int32 Poller(void \*data) +================================ + +Poller is the main workhorse of the AppServer class, polling the +Server's input port constantly for any messages from the Input Server +and calling the appropriate handlers. Like Picasso, it, too, is mostly +a while(!quit_server) loop. + +1. Call port_buffer_size_etc() with a timeout of 3 seconds. +2. Check to see if the port_buffer_size_etc() timed out and do a + continue to next iteration if it did. +3. Allocate a buffer on the heap if the port buffer size is greater than 0 +4. Read the port +5. Pass specified messages to DispatchMessage() for processing, spitting + out an error message to stderr if the message's code is unrecognized +6. Return from DispatchMessage() and free the message buffer if one was + allocated + +Decorator \* instantiate_decorator(Layer \*owner, uint32 wflags, uint32 wlook) +============================================================================== + +instantiate_decorator returns a new instance of the decorator +currently in use. The caller is responsible for the memory allocated +for the returned object. + +1. Acquire the decorator lock +2. If create_decorator is NULL, create a new instance of the default + decorator +3. If create_decorator is non-NULL, create a new decorator instance by + calling AppServer::create_decorator(). +4. Release the decorator lock +5. Return the newly allocated instance + +void Broadcast(int32 code) +========================== + +Broadcast() provides the AppServer class with an easy way to send a +quick message to all ServerApps. Primarily, this is called when a font +or decorator has changed, or when the server is shutting down. It is +not intended to do anything except send a quick message which requires +no extra data, such as for some upadate signalling. + +1. Acquire application list lock +2. Create a PortLink instance and set its message code to the passed + parameter. +3. Iterate through the application list, targeting the PortLink instance + to each ServerApp's message port and calling Flush(). +4. Release application list lock + +void HandleKeyMessage(int32 code, int8 \*buffer) +================================================ + +Called from DispatchMessage to filter out App Server events and +otherwise send keystrokes to the active application. + +B_KEY_DOWN +---------- + +Sent when the user presses (or holds down) a key that's been mapped to +a character. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int64 when | event time in seconds since | +| | 1/1/70 | ++-----------------------------------+-----------------------------------+ +| int32 rawcode | code for the physical key pressed | ++-----------------------------------+-----------------------------------+ +| int32 repeat_count | number of times a key has been | +| | repeated | ++-----------------------------------+-----------------------------------+ +| int32 modifiers | flags signifying the states of | +| | the modifier keys | ++-----------------------------------+-----------------------------------+ +| int32 state_count | number of bytes to follow | +| | containing the state of all keys | ++-----------------------------------+-----------------------------------+ +| int8 \*states | array of the state of all keys at | +| | the time of the event | ++-----------------------------------+-----------------------------------+ +| int8 utf8data[3] | UTF-8 data generated | ++-----------------------------------+-----------------------------------+ +| int8 charcount | number of bytes to follow | +| | containing the string generated | +| | (usually 1) | ++-----------------------------------+-----------------------------------+ +| const char \*string | null-terminated string generated | +| | by the keystroke | ++-----------------------------------+-----------------------------------+ +| int32 raw_char | modifier-independent ASCII code | +| | for the character | ++-----------------------------------+-----------------------------------+ + +1. Get all attached data +2. If the command modifier is down, check for Left Ctrl+Left Alt+Left + Shift+F12 and reset the workspace to 640 x 480 x 256 @ 60Hz and return + if true +3. If the command modifier is down, check for Alt+F1 through Alt+F12 and + set workspace and return if true +4. If the control modifier is true, check for B_CONTROL_KEY+Tab and, if + true, find and send to the Deskbar. +5. Acquire the active application lock +6. Create a PortLink instance, target the active ServerApp's sender + port, set the opcode to B_KEY_DOWN, attach the buffer en masse, and send + it to the BApplication. +7. Release the active application lock + +B_KEY_UP +-------- + +Sent when the user releases a key that's been mapped to a character. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int64 when | event time in seconds since | +| | 1/1/70 | ++-----------------------------------+-----------------------------------+ +| int32 rawcode | code for the physical key pressed | ++-----------------------------------+-----------------------------------+ +| int32 modifiers | flags signifying the states of | +| | the modifier keys | ++-----------------------------------+-----------------------------------+ +| int32 state_count | number of bytes to follow | +| | containing the state of all keys | ++-----------------------------------+-----------------------------------+ +| int8 \*states | array of the state of all keys at | +| | the time of the event | ++-----------------------------------+-----------------------------------+ +| int8 utf8data[3] | UTF-8 data generated | ++-----------------------------------+-----------------------------------+ +| int8 charcount | number of bytes to follow | +| | containing the string generated | +| | (usually 1) | ++-----------------------------------+-----------------------------------+ +| const char \*string | null-terminated string generated | +| | by the keystroke | ++-----------------------------------+-----------------------------------+ +| int32 raw_char | modifier-independent ASCII code | +| | for the character | ++-----------------------------------+-----------------------------------+ + +1. Get all attached data +2. Acquire the active application lock +3. Create a PortLink instance, target the active ServerApp's sender + port, set the opcode to B_KEY_UP, attach the buffer en masse, and send + it to the BApplication. +4. Release the active application lock + +B_UNMAPPED_KEY_DOWN +------------------- + +Sent when the user presses a key that has not been mapped to a +character. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int64 when | event time in seconds since | +| | 1/1/70 | ++-----------------------------------+-----------------------------------+ +| int32 rawcode | code for the physical key pressed | ++-----------------------------------+-----------------------------------+ +| int32 modifiers | flags signifying the states of | +| | the modifier keys | ++-----------------------------------+-----------------------------------+ +| int8 state_count | number of bytes to follow | +| | containing the state of all keys | ++-----------------------------------+-----------------------------------+ +| int8 \*states | array of the state of all keys at | +| | the time of the event | ++-----------------------------------+-----------------------------------+ + +1. Acquire the active application lock +2. Create a PortLink instance, target the active ServerApp's sender + port, set the opcode to B_UNMAPPED_KEY_DOWN, attach the buffer en masse, + and send it to the BApplication. +3. Release the active application lock + +B_UNMAPPED_KEY_UP +----------------- + +Sent when the user presses a key that has not been mapped to a +character. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int64 when | event time in seconds since | +| | 1/1/70 | ++-----------------------------------+-----------------------------------+ +| int32 rawcode | code for the physical key pressed | ++-----------------------------------+-----------------------------------+ +| int32 modifiers | flags signifying the states of | +| | the modifier keys | ++-----------------------------------+-----------------------------------+ +| int8 state_count | number of bytes to follow | +| | containing the state of all keys | ++-----------------------------------+-----------------------------------+ +| int8 \*states | array of the state of all keys at | +| | the time of the event | ++-----------------------------------+-----------------------------------+ + +1. Acquire the active application lock +2. Create a PortLink instance, target the active ServerApp's sender + port, set the opcode to B_UNMAPPED_KEY_UP, attach the buffer en masse, + and send it to the BApplication. +3. Release the active application lock + +B_MODIFIERS_CHANGED +------------------- + +Sent when the user presses or releases one of the modifier keys + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int64 when | event time in seconds since | +| | 1/1/70 | ++-----------------------------------+-----------------------------------+ +| int32 modifiers | flags signifying the states of | +| | the modifier keys | ++-----------------------------------+-----------------------------------+ +| int32 old_modifiers | former states of the modifier | +| | keys | ++-----------------------------------+-----------------------------------+ +| int8 state_count | number of bytes to follow | +| | containing the state of all keys | ++-----------------------------------+-----------------------------------+ +| int8 \*states | array of the state of all keys at | +| | the time of the event | ++-----------------------------------+-----------------------------------+ + +1. Acquire the active application lock +2. Create a PortLink instance, target the active ServerApp's sender + port, set the opcode to B_MODIFIERS_CHANGED, attach the buffer en masse, + and send it to the BApplication. +3. Release the active application lock + diff --git a/docs/develop/servers/app_server/BitmapManager.htm b/docs/develop/servers/app_server/BitmapManager.htm deleted file mode 100644 index f8ed7a09e8..0000000000 --- a/docs/develop/servers/app_server/BitmapManager.htm +++ /dev/null @@ -1,123 +0,0 @@ - - -BitmapManager.htm - - - -
-

BitmapManager class

-


-

-

The BitmapManager object handles all ServerBitmap allocation and deallocation. The rest of the server uses CreateBitmap and DeleteBitmap instead of new and delete. It utilizes the outside pool manager BGET.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - -
-

BitmapManager(void)

-
-

~BitmapManager(void)

-
-

ServerBitmap *CreateBitmap(BRect bounds, color_space space, int32 flags, int32 bytes_per_row=-1, screen_id screen=B_MAIN_SCREEN_ID)

-
-

void DeleteBitmap(ServerBitmap *bitmap)

-
-


-
-Global Functions

-


-extern "C" void set_area_buffer_management(void);

-

void * expand_area_storage(long size)

-

void contract_area_storage(void *buffer)

-


-


-

-

BitmapManager(void)

-


-1) Create the bitmap list

-

2) Create the bitmap area

-

3) Allocate the access semaphore

-

4) Call set_buffer_area_management

-

5) Set up the buffer pool via bpool

-


-~BitmapManager(void)

-


-1) Iterate over each item in the bitmap list, removing each item, calling brel() on its buffer, and deleting it.

-

2) Delete the bitmap list

-

3) Delete the bitmap area

-

4) Free the access semaphore

-


-ServerBitmap *CreateBitmap(BRect bounds, color_space space, int32 flags, int32 bytes_per_row=-1, screen_id screen=B_MAIN_SCREEN_ID)

-


-CreateBitmap is called by outside objects to allocate a ServerBitmap object. If a problem occurs, it returns NULL.

-


-1) Acquire the access semaphore

-

2) Verify parameters and if any are invalid, spew an error to stderr and return NULL

-

3) Allocate a new ServerBitmap

-

4) Allocate a buffer for the bitmap via bget() with the bitmap's theoretical buffer length

-

5) If NULL, delete the bitmap and return NULL

-

6) Set the bitmap's area and buffer to the appropriate values (area_for buffer and buffer)

-

7) Add the bitmap to the bitmap list

-

8) Release the access semaphore

-

9) Return the bitmap

-


-void DeleteBitmap(ServerBitmap *bitmap)

-


-Frees a ServerBitmap allocated by CreateBitmap()

-


-1) Acquire the access semaphore

-

2) Find the bitmap in the list

-

3) Remove the bitmap from the list or release the semaphore and return if not found

-

4) call brel() on the bitmap's buffer if it is non-NULL

-

5) delete the bitmap

-

6) Release the access semaphore

-


-
extern "C" void set_area_buffer_management(void)

-


-C function defined externally to point the BGET manager to our homegrown area allocation and deallocation functions.

-


-
void * expand_area_storage(long size)

-


-"Internal" global function accessed only by set_area_buffer_management and BGET to handle the task of adding more area space to make room for more bitmaps.

-


-1) If size is less than B_PAGE_SIZE, set the area size to B_PAGE_SIZE

-

2) If size % B_PAGE_SIZE, set area size to (size/B_PAGE_SIZE)+1)*B_PAGE_SIZE, otherwise setting it to the given size

-

3) Call create_area with the area size.

-

4) If it couldn't allocate an area, write a panic message to stderr and return NULL, otherwise, return the pointer to the area.

-


-void contract_area_storage(void *buffer)

-


-
"Internal" global function accessed only by set_area_buffer_management and BGET to remove the area which was previously used for the bitmap pool

-


-1) Call area_for on the buffer

-

2) If the area_id is not B_ERROR, call delete_area on its area_id.

-
-
-
- - diff --git a/docs/develop/servers/app_server/BitmapManager.rst b/docs/develop/servers/app_server/BitmapManager.rst new file mode 100644 index 0000000000..4335da8ad1 --- /dev/null +++ b/docs/develop/servers/app_server/BitmapManager.rst @@ -0,0 +1,60 @@ +BitmapManager class +################### + +The BitmapManager object handles all ServerBitmap allocation and +deallocation. The rest of the server uses CreateBitmap and DeleteBitmap +instead of new and delete. + +Member Functions +================ + +BitmapManager(void) +------------------- + +1. Create the bitmap list +2. Create the bitmap area +3. Allocate the access semaphore +4. Call set_buffer_area_management +5. Set up the buffer pool via bpool + +~BitmapManager(void) +-------------------- + +1. Iterate over each item in the bitmap list, removing each item, + calling brel() on its buffer, and deleting it. +2. Delete the bitmap list +3. Delete the bitmap area +4. Free the access semaphore + +ServerBitmap \*CreateBitmap(BRect bounds, color_space space, int32 flags, int32 bytes_per_row=-1, screen_id screen=B_MAIN_SCREEN_ID) +------------------------------------------------------------------------------------------------------------------------------------ + +CreateBitmap is called by outside objects to allocate a ServerBitmap +object. If a problem occurs, it returns NULL. + +1. Acquire the access semaphore +2. Verify parameters and if any are invalid, spew an error to stderr and + return NULL +3. Allocate a new ServerBitmap +4. Allocate a buffer for the bitmap with the bitmap's + theoretical buffer length +5. If NULL, delete the bitmap and return NULL +6. Set the bitmap's area and buffer to the appropriate values (area_for + buffer and buffer) +7. Add the bitmap to the bitmap list +8. Release the access semaphore +9. Return the bitmap + +void DeleteBitmap(ServerBitmap \*bitmap) +---------------------------------------- + +Frees a ServerBitmap allocated by CreateBitmap() + +1. Acquire the access semaphore +2. Find the bitmap in the list +3. Remove the bitmap from the list or release the semaphore and return + if not found +4. call brel() on the bitmap's buffer if it is non-NULL +5. delete the bitmap +6. Release the access semaphore + diff --git a/docs/develop/servers/app_server/ColorSet.htm b/docs/develop/servers/app_server/ColorSet.htm deleted file mode 100644 index 9067340309..0000000000 --- a/docs/develop/servers/app_server/ColorSet.htm +++ /dev/null @@ -1,112 +0,0 @@ - - -ColorSet.htm - - - -
-

ColorSet class

-


-

-

The ColorSet class provides an easy manner to manage system attribute colors, such as window tabs, panel background colors, etc. Each member is an RGBColor. The attributes are list below and are publicly accessible.

-


-

-

panel_background

-

panel_text

-

document_background

-

document_text

-

control_background

-

control_text

-

control_border

-

control_highlight

-

tooltip_background

-

tooltip_text

-

menu_background

-

menu_selected_background

-

menu_text

-

menu_selected_text

-

menu_separator_high

-

menu_separator_low

-

menu_triggers

-

window_tab

-

window_tab_text

-

inactive_window_tab

-

inactive_window_tab_text

-

keyboard_navigation

-

desktop

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - -
-

ColorSet(void)

-
-

ColorSet(const ColorSet &cs)

-
-

ColorSet & operator=(const ColorSet &cs)

-
-

void SetColors(const ColorSet &cs)

-
-

void PrintToStream(void)

-
-   -
-


-
-
-


-

-


-ColorSet(void)

-


-Does nothing.

-


-
-ColorSet(const ColorSet &cs)

-

ColorSet & operator=(const ColorSet &cs)

-


-Calls SetColors on the passed ColorSet object

-


-
-void SetColors(const ColorSet &cs)

-


-Copies all data members of the passed color set to those of the current one

-


-
-void PrintToStream(void)

-


-Prints the name of each attribute color and then calls the color's PrintToStream member.

-
-
-
- - diff --git a/docs/develop/servers/app_server/ColorUtils.htm b/docs/develop/servers/app_server/ColorUtils.htm deleted file mode 100644 index 72d1e407b3..0000000000 --- a/docs/develop/servers/app_server/ColorUtils.htm +++ /dev/null @@ -1,123 +0,0 @@ - - -ColorUtils.htm - - - -
-

ColorUtils

-


-

-

These functions are used for general purpose color-related tasks.

-


-
-


-

-

Global Functions

-


-void SetRGBColor32(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a=255)

-

void SetRGBAColor32(rgb_color *col, uint16 color16)

-

void SetRGBColor16(uint16 *col, uint8 r, uint8 g, uint8 b)

-

void SetRGBAColor15(uint16 *col, uint8 r, uint8 g, uint8 b, bool opaque=true)

-


-uint8 FindClosestColor(rgb_color *palette,rgb_color col)

-

uint16 FindClosestColor16(rgb_color col)

-

uint16 FindClosestColor15(rgb_color col)

-


-rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position)

-


-


-

-

void SetRGBColor32(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a=255)

-


-Simply assigns the passed parameters to the internal members of the passed color

-


-
-void SetRGBAColor32(rgb_color *col, uint16 color16)

-


-Maps a 16-bit color to a 32-bit one.

-


-gggbbbbb arrrrrgg

-

1) Extract component values using the following calculations:

-


- red16 = (uint8[1] & 124) >> 2

-


- green16 = ((uint8[0] & 224) >> 5) | ((uint8[1] & 3) << 3)

-


- blue16 = uint8[0] & 31

-

2) Use cross-multiplication to map each 16-bit color component from 0-31 space to 0-255 space, i.e. red32 = (red16 / 31) * 255

-

3) Assign mapped values to the rgb_color passed to the function

-


-
-void SetRGBColor16(uint16 *col, uint8 r, uint8 g, uint8 b)

-


-Used for easy assignment of opaque (B_RGB16) 16-bit colors.

-


-1) Clip parameters via a bitwise AND with 31 (var &=31)

-

2) Create a uint8 * to the passed color

-

3) Assign as follows and return:

-

a) uint8[0] = ( (g & 7) << 5) | (b & 31)

-

b) uint8[1] = ( (r & 31) << 3) | ( (g & 56) >> 3)

-


-
-void SetRGBAColor15(uint16 *col, uint8 r, uint8 g, uint8 b, bool opaque=true)

-


-Used for easy assignment of alpha-aware (B_RGBA16) 16-bit colors.

-


-1) Clip parameters via a bitwise AND with 31 (var &=31)

-

2) Create a uint8 * to the passed color

-

3) Assign as follows and return:

-

a) uint8[0] = ( (g & 7) << 5) | (b & 31)

-

b) uint8[1] = ( (r & 31) << 2) | ( (g & 24) >> 3) | (a) ? 128 : 0

-


-
-uint8 FindClosestColor(rgb_color *palette,rgb_color col)

-


-Finds the color which most closely resembles the given one in the given palette.

-


-1) Set the saved delta value to 765 (maximum difference)

-

2) Loop through all the colors in the palette. For each color,

-

a) calculate the delta value for each color component and add them together

-

b) compare the new combined delta with the saved one

-

c) if the delta is 0, immediately return the current index

-

d) if the new one is smaller, save it and also the palette index

-


-
-uint16 FindClosestColor16(rgb_color col)

-


-Returns a 16-bit approximation of the given 32-bit color. Alpha values are ignored.

-

1) Create an opaque, 16-bit approximation of col using the following calculations:

-

r16=(31*col.red)/255

-

g16=(31*col.green)/255

-

b16=(31*col.blue)/255

-

2) Assign it to a uint16 using the same code as in SetRGBColor16() and return it.

-


-
-uint16 FindClosestColor15(rgb_color col)

-


-This functions almost exactly like the 16-bit version, but this also takes into account the alpha transparency bit and works in the color space B_RGBA15. Follow the same algorithm as FindClosestColor16(), but assign the return value using SetRGBColor15.

-


-
-rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position)

-


-MakeBlendColor calculates a color that is somewhere between start color col and end color col2, based on position, where 0<= position <= 1. If position is out of these bounds, a color of {0,0,0,0} is returned. If position is 0, the start color is returned. If position is 1, col2 is returned. Otherwise, the color is calculated thus:

-


-1) calculate delta values for each channel, i.e. int16 delta_r=col.red-col2.red

-

2) Based on these delta values, calculate the blend values for each channel, i.e. blend_color.red=uint8(col1.red - (delta_r * position) )

-
-
-
- - diff --git a/docs/develop/servers/app_server/ColorUtils.rst b/docs/develop/servers/app_server/ColorUtils.rst new file mode 100644 index 0000000000..8c8a2f8587 --- /dev/null +++ b/docs/develop/servers/app_server/ColorUtils.rst @@ -0,0 +1,114 @@ +ColorUtils +########## + +These functions are used for general purpose color-related tasks. + +Global Functions +================ + +void SetRGBColor32(rgb_color \*col, uint8 r, uint8 g, uint8 b, uint8 a=255) +--------------------------------------------------------------------------- + +Simply assigns the passed parameters to the internal members of the +passed color + +void SetRGBAColor32(rgb_color \*col, uint16 color16) +---------------------------------------------------- + +Maps a 16-bit color to a 32-bit one. + +gggbbbbb arrrrrgg + +1. Extract component values using the following calculations: + + .. code-block:: cpp + + red16 = (uint8[1] & 124) >> 2; + green16 = ((uint8[0] & 224) >> 5) | ((uint8[1] & 3) << 3); + blue16 = uint8[0] & 31; + +2. Use cross-multiplication to map each 16-bit color component from 0-31 + space to 0-255 space, i.e. red32 = (red16 / 31) \* 255 +3. Assign mapped values to the rgb_color passed to the function + +void SetRGBColor16(uint16 \*col, uint8 r, uint8 g, uint8 b) +----------------------------------------------------------- + +Used for easy assignment of opaque (B_RGB16) 16-bit colors. + +1. Clip parameters via a bitwise AND with 31 (var &=31) +2. Create a uint8 * to the passed color +3. Assign as follows and return: + + .. code-block:: cpp + + uint8[0] = ( (g & 7) << 5) | (b & 31); + uint8[1] = ( (r & 31) << 3) | ( (g & 56) >> 3); + +void SetRGBAColor15(uint16 \*col, uint8 r, uint8 g, uint8 b, bool opaque=true) +------------------------------------------------------------------------------ + +Used for easy assignment of alpha-aware (B_RGBA16) 16-bit colors. + +1. Clip parameters via a bitwise AND with 31 (var &=31) +2. Create a uint8 * to the passed color +3. Assign as follows and return: + + .. code-block:: cpp + + uint8[0] = ( (g & 7) << 5) | (b & 31); + uint8[1] = ( (r & 31) << 2) | ( (g & 24) >> 3) | (a) ? 128 : 0; + +uint8 FindClosestColor(rgb_color \*palette,rgb_color col) +--------------------------------------------------------- + +Finds the color which most closely resembles the given one in the +given palette. + +1. Set the saved delta value to 765 (maximum difference) +2. Loop through all the colors in the palette. For each color, + + a. calculate the delta value for each color component and add them + together + b. compare the new combined delta with the saved one + c. if the delta is 0, immediately return the current index + d. if the new one is smaller, save it and also the palette index + +uint16 FindClosestColor16(rgb_color col) +---------------------------------------- + +Returns a 16-bit approximation of the given 32-bit color. Alpha values +are ignored. + +1. Create an opaque, 16-bit approximation of col using the following + calculations: + + .. code-block:: cpp + + r16 = (31 * col.red) / 255; + g16 = (31 * col.green) / 255; + b16 = (31 * col.blue) / 255; + +2. Assign it to a uint16 using the same code as in SetRGBColor16() and + return it. + +uint16 FindClosestColor15(rgb_color col) +---------------------------------------- + +This functions almost exactly like the 16-bit version, but this also +takes into account the alpha transparency bit and works in the color +space B_RGBA15. Follow the same algorithm as FindClosestColor16(), but +assign the return value using SetRGBColor15. + +rgb_color MakeBlendColor(rgb_color col, rgb_color col2, float position) +----------------------------------------------------------------------- + +MakeBlendColor calculates a color that is somewhere between start +color col and end color col2, based on position, where 0<= position <= +1. If position is out of these bounds, a color of {0,0,0,0} is +returned. If position is 0, the start color is returned. If position +is 1, col2 is returned. Otherwise, the color is calculated thus: + +1. calculate delta values for each channel, i.e. int16 delta_r=col.red-col2.red +2. Based on these delta values, calculate the blend values for each + channel, i.e. blend_color.red=uint8(col1.red - (delta_r \* position) ) diff --git a/docs/develop/servers/app_server/CursorManager.htm b/docs/develop/servers/app_server/CursorManager.htm deleted file mode 100644 index 2164c31b28..0000000000 --- a/docs/develop/servers/app_server/CursorManager.htm +++ /dev/null @@ -1,215 +0,0 @@ - - -CursorManager.htm - - - -
-

CursorManager class

-


-

-

The CursorManager class handles token creation, calling the cursor-related graphics driver functions, and freeing heap memory for all ServerCursor instances.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

CursorManager(void)

-
-

~CursorManager(void)

-
-

int32 AddCursor(ServerCursor *c)

-
-

void DeleteCursor(int32 token)

-
-

void RemoveAppCursors(ServerApp *a)

-
-

void ShowCursor(void)

-
-

void HideCursor(void)

-
-

void ObscureCursor(void)

-
-

void SetCursor(int32 token)

-
-

ServerCursor *GetCursor(cursor_which which)

-
-

void SetCursor(cursor_which which)

-
-

void ChangeCursor(cursor_which which,

-

int32 token)

-
-

cursor_which GetCursorWhich(void)

-
-   -
-


-
-Enumerated Types:

-


-cursor_which {

-

CURSOR_DEFAULT

-

CURSOR_TEXT

-

CURSOR_MOVE

-

CURSOR_DRAG

-

CURSOR_RESIZE

-

CURSOR_RESIZE_NW

-

CURSOR_RESIZE_SE

-

CURSOR_RESIZE_NS

-

CURSOR_RESIZE_EW

-

CURSOR_OTHER

-

}

-


-
-


-

-

CursorManager(void)

-


-
-1) Create the cursor list empty

-

2) Set the token index to 0

-

3) Allocate the default system cursor and pass it to AddCursor

-

4) Initialize the member pointer for the graphics driver

-

5) Create the cursorlock semaphore

-

6) Call SetDefaultCursor

-


-
-~CursorManager(void)

-


-1) Empty and delete the cursor list

-

2) Delete the cursorlock semaphore

-


-
-int32 AddCursor(ServerCursor *sc)

-


-AddCursor() is used to register the cursor in question with the manager, allowing for the user application to have the identifying token, if necessary. The cursor becomes the property of the manager. If a user application deletes a BCursor, its ServerApp will call DeleteCursor().

-


-1) Acquire cursor lock

-

2) Add *sc to the cursor list

-

3) Set sc->token to the current token index value

-

4) Increment the token index

-

5) Assign sc->token to temporary variable

-

6) Release cursor lock

-

7) Return the saved token value

-


-
-void DeleteCursor(int32 ctoken)

-


-1) Acquire cursor lock

-

2) Iterate through the cursor list, looking for ctoken

-

3) If any ServerCursor->token equals ctoken, remove and delete it

-

4) Release cursor lock

-


-
-void RemoveAppCursors(ServerApp *app)

-


-1) Acquire cursor lock

-

2) Iterate through the cursor list, checking each cursor's ServerApp pointer

-

3) If any have a ServerApp pointer which matches the passed pointer, remove and delete them

-

4) Release cursor lock

-


-
-void ShowCursor(void)

-

void HideCursor(void)

-

void ObscureCursor(void)

-


-Simple pass-through functions which call the graphics driver's functions. Note that acquiring the cursor lock will be necessary for all three calls.

-


-
-void SetCursor(int32 token)

-

void SetCursor(cursor_which cursor)

-


-These set the current cursor for the graphics driver to the passed cursor, either one previously added via AddCursor or a system cursor.

-


-1) Acquire cursor lock

-


-Token version:

-

2) Find the cursor in the cursor list and call the graphics driver if non-NULL

-

3) Iterate through list of system cursor tokens and see if there's a match. If so, set the internal cursor_which to the match.

-


-cursor_which version:

-

2) determine which cursor to use via a switch statement and call the graphics driver with the internal pointer for the appropriate cursor

-

3) set the internal cursor_which to the one passed to the function

-


-4) Release cursor lock

-


-
-ServerCursor *GetCursor(cursor_which which)

-


-GetCursor is intended for use in figuring out what cursor is in use for a particular system cursor.

-


-1) Acquire cursor lock

-

2) use a switch statement to figure which cursor to return and assign a temporary pointer its value

-

3) Release cursor lock

-

4) Return the temporary pointer

-


-
-void ChangeCursor(cursor_which which, int32 token)

-


-Calling ChangeCursor will allow a user to change a system cursor's appearance. Note that in calling this, the cursor changes ownership and belongs to the system. Thus, the BCursor destructor will not ultimately cause the cursor to be deleted.

-


-1) Acquire cursor lock

-

2) Call FindCursor and, if NULL, release the cursor lock and return

-

3) Look up the pointer for the system cursor in question and check to see if it is active. If active, then set the local active flag to true. Set the system cursor pointer to the one looked up.

-

4) If active flag is true, call SetCursor()

-

5) Release cursor lock

-


-
-cursor_which GetCursorWhich(void)

-


-Returns the current cursor_which attribute which describes the currently active cursor. If the active cursor is not a system cursor, it will return CURSOR_OTHER.

-


-1) Acquire cursor lock

-

2) Create a local cursor_which and assign it the value of the CursorManager's cursor_which

-

3) Release cursor lock

-

4) Return the local copy

-
-
-
- - diff --git a/docs/develop/servers/app_server/CursorManager.rst b/docs/develop/servers/app_server/CursorManager.rst new file mode 100644 index 0000000000..281bb5368f --- /dev/null +++ b/docs/develop/servers/app_server/CursorManager.rst @@ -0,0 +1,151 @@ +CursorManager class +################### + +The CursorManager class handles token creation, calling the +cursor-related graphics driver functions, and freeing heap memory for +all ServerCursor instances. + +Enumerated Types +================ + +cursor_which +------------ + +- CURSOR_DEFAULT +- CURSOR_TEXT +- CURSOR_MOVE +- CURSOR_DRAG +- CURSOR_RESIZE +- CURSOR_RESIZE_NW +- CURSOR_RESIZE_SE +- CURSOR_RESIZE_NS +- CURSOR_RESIZE_EW +- CURSOR_OTHER + +Member Functions +================ + +CursorManager(void) +------------------- + +1. Create the cursor list empty +2. Set the token index to 0 +3. Allocate the default system cursor and pass it to AddCursor +4. Initialize the member pointer for the graphics driver +5. Create the cursorlock semaphore +6. Call SetDefaultCursor + +~CursorManager(void) +-------------------- + +1. Empty and delete the cursor list +2. Delete the cursorlock semaphore + +int32 AddCursor(ServerCursor \*sc) +---------------------------------- + +AddCursor() is used to register the cursor in question with the +manager, allowing for the user application to have the identifying +token, if necessary. The cursor becomes the property of the manager. +If a user application deletes a BCursor, its ServerApp will call +DeleteCursor(). + +1. Acquire cursor lock +2. Add \*sc to the cursor list +3. Set sc->token to the current token index value +4. Increment the token index +5. Assign sc->token to temporary variable +6. Release cursor lock +7. Return the saved token value + +void DeleteCursor(int32 ctoken) +------------------------------- + +1. Acquire cursor lock +2. Iterate through the cursor list, looking for ctoken +3. If any ServerCursor->token equals ctoken, remove and delete it +4. Release cursor lock + +void RemoveAppCursors(ServerApp \*app) +-------------------------------------- + +1. Acquire cursor lock +2. Iterate through the cursor list, checking each cursor's ServerApp + pointer +3. If any have a ServerApp pointer which matches the passed pointer, + remove and delete them +4. Release cursor lock + +void ShowCursor(void), void HideCursor(void), void ObscureCursor(void) +---------------------------------------------------------------------- + +Simple pass-through functions which call the graphics driver's +functions. Note that acquiring the cursor lock will be necessary for +all three calls. + +void SetCursor(int32 token), void SetCursor(cursor_which cursor) +---------------------------------------------------------------- + +These set the current cursor for the graphics driver to the passed +cursor, either one previously added via AddCursor or a system cursor. + +1. Acquire cursor lock + +Token version: + +2. Find the cursor in the cursor list and call the graphics driver if + non-NULL +3. Iterate through list of system cursor tokens and see if there's a + match. If so, set the internal cursor_which to the match. + +cursor_which version: + +2. determine which cursor to use via a switch statement and call the + graphics driver with the internal pointer for the appropriate cursor +3. set the internal cursor_which to the one passed to the function + +.. + +4. Release cursor lock + +ServerCursor \*GetCursor(cursor_which which) +-------------------------------------------- + +GetCursor is intended for use in figuring out what cursor is in use +for a particular system cursor. + +1. Acquire cursor lock +2. use a switch statement to figure which cursor to return and assign a + temporary pointer its value +3. Release cursor lock +4. Return the temporary pointer + +void ChangeCursor(cursor_which which, int32 token) +-------------------------------------------------- + +Calling ChangeCursor will allow a user to change a system cursor's +appearance. Note that in calling this, the cursor changes ownership +and belongs to the system. Thus, the BCursor destructor will not +ultimately cause the cursor to be deleted. + +1. Acquire cursor lock +2. Call FindCursor and, if NULL, release the cursor lock and return +3. Look up the pointer for the system cursor in question and check to + see if it is active. If active, then set the local active flag to true. + Set the system cursor pointer to the one looked up. +4. If active flag is true, call SetCursor() +5. Release cursor lock + +cursor_which GetCursorWhich(void) +--------------------------------- + +Returns the current cursor_which attribute which describes the +currently active cursor. If the active cursor is not a system cursor, +it will return CURSOR_OTHER. + +1. Acquire cursor lock +2. Create a local cursor_which and assign it the value of the + CursorManager's cursor_which +3. Release cursor lock +4. Return the local copy + diff --git a/docs/develop/servers/app_server/DebugTools.htm b/docs/develop/servers/app_server/DebugTools.htm deleted file mode 100644 index 2045799d71..0000000000 --- a/docs/develop/servers/app_server/DebugTools.htm +++ /dev/null @@ -1,50 +0,0 @@ - - -DebugTools.htm - - - -
-

DebugUtils

-


-

-

These functions are used to make print-based debugging easier.

-


-
-


-

-

Global Functions

-


-BString TranslateStatusToBString(status_t value)

-

BString TranslateColorSpaceToBString(color_space value)

-

BString TranslateMessageCodeToBString(int32 value)

-


-
-


-

-

BString TranslateStatusToBString(status_t value)

-

BString TranslateColorSpaceToBString(color_space value)

-

BString TranslateMessageCodeToBString(int32 value)

-


-const char * TranslateStatusToString(status_t value)

-

const char * TranslateColorSpaceToString(color_space value)

-

const char * TranslateMessageCodeToString(int32 value)

-


-All of these functions are essentially big switch() statements which assign an appropriate string for the passed parameter and return the assigned string. This way the string can be printed or otherwise easily used.

-
-
-
- - diff --git a/docs/develop/servers/app_server/DebugTools.rst b/docs/develop/servers/app_server/DebugTools.rst new file mode 100644 index 0000000000..5a9d02f358 --- /dev/null +++ b/docs/develop/servers/app_server/DebugTools.rst @@ -0,0 +1,20 @@ +Debug Utility functions +####################### + +These functions are used to make print-based debugging easier. + +- BString TranslateStatusToBString(status_t value) +- BString TranslateColorSpaceToBString(color_space value) +- BString TranslateMessageCodeToBString(int32 value) +- BString TranslateStatusToBString(status_t value) +- BString TranslateColorSpaceToBString(color_space value) +- BString TranslateMessageCodeToBString(int32 value) +- const char \* TranslateStatusToString(status_t value) +- const char \* TranslateColorSpaceToString(color_space value) +- const char \* TranslateMessageCodeToString(int32 value) + +All of these functions are essentially big switch() statements which +assign an appropriate string for the passed parameter and return the +assigned string. This way the string can be printed or otherwise +easily used. + diff --git a/docs/develop/servers/app_server/Decorator.htm b/docs/develop/servers/app_server/Decorator.htm deleted file mode 100644 index d4bcd703e8..0000000000 --- a/docs/develop/servers/app_server/Decorator.htm +++ /dev/null @@ -1,401 +0,0 @@ - - -Decorator.htm - - - -
-

Decorator class

-


-

-

Decorators provide the actual drawing for a window's looks.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Decorator(BRect int32 wlook, int32 wfeel, int32 wflags)

-
-

~Decorator(void)

-
-

void SetColors(color_set colors)

-
-

void SetDriver(DisplayDriver *driver)

-
-

void SetClose(bool is_down)

-
-

void SetMinimize(bool is_down)

-
-

void SetZoom(bool is_down)

-
-

void SetFlags(int32 wflags)

-
-

void SetFeel(int32 wfeel)

-
-

void SetLook(int32 wlook)

-
-

bool GetClose(void)

-
-

bool GetMinimize(void)

-
-

bool GetZoom(void)

-
-

int32 GetLook(void)

-
-

int32 GetFeel(void)

-
-

int32 GetFlags(void)

-
-

void SetTitle(const char *string)

-
-

void SetFont(SFont *sf)

-
-

int32 _ClipTitle(float width)

-
-

void SetFocus(bool is_active)

-
-

bool GetFocus(void)

-
-

int32 _TitleWidth(void)

-
-


-
-
-Virtual Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

void MoveBy(float x, float y)

-
-

void MoveBy(BPoint pt)

-
-

void ResizeBy(float x, float y)

-
-

void ResizeBy(BPoint pt)

-
-

void Draw(BRect r)

-
-

void Draw(void)

-
-

void DrawClose(void)

-
-

void DrawFrame(void)

-
-

void DrawMinimize(void)

-
-

void DrawTab(void)

-
-

void DrawTitle(void)

-
-

void DrawZoom(void)

-
-

void _DrawClose(BRect r)

-
-

void _DrawFrame(BRect r)

-
-

void _DrawMinimize(BRect r)

-
-

void _DrawTab(BRect r)

-
-

void _DrawTitle(BRect r)

-
-

void _DrawZoom(BRect r)

-
-

SRegion GetFootprint(void)

-
-

click_type Clicked(BPoint pt, int32 buttons, int32 modifiers)

-
-

void _SetFocus(void)

-
-

BRect SlideTab(float dx, float dy=0)

-
-


-
-_ Indicates a protected member function

-


-Exported C Functions

-


-Decorator *create_decorator(BRect frame, int32 wlook, int32 wfeel, int32 wflags)

-

float get_decorator_version(void)

-


-
-Enumerated Types

-


-click_type {

-

CLICK_NONE

-

CLICK_ZOOM

-

CLICK_CLOSE

-

CLICK_MINIMIZE

-

CLICK_TAB

-

CLICK_MOVE

-

CLICK_MOVETOBACK

-

CLICK_MOVETOFRONT

-

CLICK_RESIZE

-

CLICK_RESIZE_L

-

CLICK_RESIZE_T

-

CLICK_RESIZE_R

-

CLICK_RESIZE_B

-

CLICK_RESIZE_LT

-

CLICK_RESIZE_RT

-

CLICK_RESIZE_LB

-

CLICK_RESIZE_RB

-

}

-


-


-

-

Decorator(BRect int32 wlook, int32 wfeel, int32 wflags)

-


-Sets up internal variables common to all decorators.

-


-1) Assign parameters to respective data members

-


-
-~Decorator(void)

-


-Empty.

-


-void SetColors(color_set colors)

-

void SetDriver(DisplayDriver *driver)

-

void SetClose(bool is_down)

-

void SetMinimize(bool is_down)

-

void SetZoom(bool is_down)

-

void SetFlags(int32 wflags)

-

void SetFeel(int32 wfeel)

-

void SetLook(int32 wlook)

-

bool GetClose(void)

-

bool GetMinimize(void)

-

bool GetZoom(void)

-

int32 GetLook(void)

-

int32 GetFeel(void)

-

int32 GetFlags(void)

-

void SetTitle(const char *string)

-

void SetFont(SFont *sf)

-


-These functions work with the internal members common to all Decorators - assigning them and returning them. Additionally, SetTitle() and SetFont() set the clip_font flag to true.

-


-int32 _ClipTitle(float width)

-


-ClipTitle calculates how much of the title, in characters, can be displayed in the given width.

-


-1) Call StringWidth() on the title.

-

2) If the string's width is less thanwidth, return the string's character count

-

3) while the character count to display is > 0

-

a) calculate the string's width

-

b) if the string's width is less than width, return the character count

-

c) decrement the character count

-

4) If the loop completes itself without returning a value, it can't fit, so return 0.

-


-
-void SetFocus(bool is_active)

-


-This is for handling color states when a window receives or loses the focus.

-


-1) Set focus flag to whatever is_active is.

-

2) call hook function _SetFocus()

-


-
-bool GetFocus(void)

-


-Returns the focus state held by the decorator

-


-1) Return the focus flag

-


-
-int32 _TitleWidth(void)

-


-Returns the character count of the title or 0 if it is NULL.

-


-
-Virtual Functions

-


-Most of these functions have a default behavior which can be overridden, but are implemented to handle the more common implementations.

-


-void MoveBy(float x, float y)

-

void MoveBy(BPoint pt)

-


-Move all member rectangles of Decorator by the specified amount.

-


-
-void ResizeBy(float x, float y)

-

void ResizeBy(BPoint pt)

-


-Resize the client frame, window frame, and the tab frame (width only) by the specified amount. Button rectangles - close, minimize, and zoom - are not modified.

-


-
-void Draw(BRect r)

-

void Draw(void)

-


-Main drawing call which checks the intersection of the rectangle passed to it and draws all items which intersect it. Draw(void) simply performs drawing calls to draw the entire decorator's footprint area.

-


-1) Check for intersection with BRect which encompasses the decorator's footprint and return if no intersection.

-

2) Call _DrawFrame(intersection)

-

3) Call _DrawTab(intersection)

-


-
-void DrawClose(void)

-

protected: void _DrawClose(BRect r)

-

void DrawMinimize(void)

-

protected: void _DrawMinimize(BRect r)

-

void DrawZoom(void)

-

protected: void _DrawZoom(BRect r)

-


-Each of these is designed to utilize their respective button rectangles. The public (void) versions simply call the internal protected ones with the button rectangle. These protected versions are, by default, empty. The rectangle passed to them is the invalid area to be drawn, which is not necessarily the entire button's rectangle.

-


-
-void DrawFrame(void)

-

protected: void _DrawFrame(BRect r)

-


-Draws the frame, if any. The public version amounts to _DrawFrame(framerect). The protected version is expected to not cover up the client frame when drawing. Any drawing within the clientrect member will end up being drawn over by the window's child views.

-


-
-void DrawTab(void)

-

protected: void _DrawTab(BRect r)

-


-Draws the window's tab, if any. DrawTab() amounts to _DrawTab(tabrect). If window titles are displayed, the _DrawTitle call is expected to be made here. Button-drawing calls, assuming that a window's buttons are in the tab, should be made here, as well.

-


-
-void DrawTitle(void)

-

protected: void _DrawTitle(BRect r)

-


-These cause the window's title to be drawn. DrawTitle() amounts to _DrawTitle(titlerect).

-


-
-void _SetFocus(void)

-


-This hook function is primarily used to change colors used when a window changes focus states and is called immediately after the state is changed. If, for example, a decorator does not use OpenBeOS' GUI color set, it would change its drawing colors to reflect the change in focus.

-


-
-SRegion GetFootprint(void)

-


-This returns the "footprint" of the decorator, i.e. the area which is occupied by the window which is is the border surrounding the main client rectangle. It is possible to have oddly-shaped window borders, like ellipses and circles, but the resulting performance hit would reduce the said decorator to a novelty and not something useable. All versions are to construct an SRegion which the border occupies. This footprint is permitted to include the client rectangle area, but this area must not be actually drawn upon by the decorator itself. The default version returns the frame which encompasses all other rectangles - the "frame" member which belongs to its window border.

-


-
-click_type Clicked(BPoint pt, int32 buttons, int32 modifiers)

-


-Clicked() performs hit testing for the decorator, given input conditions. This function is required by ALL subclasses expecting to do more than display itself. The return type will cause the server to take the appropriate actions, such as close the window, get ready to move it, etc.

-


-
-BRect SlideTab(float dx, dy=0)

-


-SlideTab is implemented only for those decorators which allow the user to somehow slide the tab (if there is one) along the window. Currently, only the horizontal direction is supported. It returns the rectangle of the invalid region which needs redrawn as a result of the slide.

-


-extern "C" Decorator *create_decorator(BRect frame, int32 wlook, int32 wfeel, int32 wflags)

-


-Required export function which simply allocates an instance of the decorator and returns it.

-


-extern "C" float get_decorator_version(void)

-


-This should, for now, return 1.00.

-


-

-
-
-
- - diff --git a/docs/develop/servers/app_server/Decorator.rst b/docs/develop/servers/app_server/Decorator.rst new file mode 100644 index 0000000000..ef663b93b2 --- /dev/null +++ b/docs/develop/servers/app_server/Decorator.rst @@ -0,0 +1,289 @@ +Decorator class +############### + +Decorators provide the actual drawing for a window's looks. + +\_ Indicates a protected member function + +Member Functions +================ + +Decorator(BRect int32 wlook, int32 wfeel, int32 wflags) +------------------------------------------------------- + +Sets up internal variables common to all decorators. + +1) Assign parameters to respective data members + +~Decorator(void) +---------------- + +Empty. + +void SetColors(color_set colors) +-------------------------------- + +void SetDriver(DisplayDriver \*driver) +-------------------------------------- + +void SetClose(bool is_down) +--------------------------- + +void SetMinimize(bool is_down) +------------------------------ + +void SetZoom(bool is_down) +-------------------------- + +void SetFlags(int32 wflags) +--------------------------- + +void SetFeel(int32 wfeel) +------------------------- + +void SetLook(int32 wlook) +------------------------- + +bool GetClose(void) +------------------- + +bool GetMinimize(void) +---------------------- + +bool GetZoom(void) +------------------ + +int32 GetLook(void) +------------------- + +int32 GetFeel(void) +------------------- + +int32 GetFlags(void) +-------------------- + +void SetTitle(const char \*string) +---------------------------------- + +void SetFont(SFont \*sf) +------------------------ + +These functions work with the internal members common to all +Decorators - assigning them and returning them. Additionally, +SetTitle() and SetFont() set the clip_font flag to true. + +int32 \_ClipTitle(float width) +------------------------------ + +ClipTitle calculates how much of the title, in characters, can be +displayed in the given width. + +1. Call StringWidth() on the title. +2. If the string's width is less thanwidth, return the string's + character count +3. while the character count to display is > 0 + + a. calculate the string's width + b. if the string's width is less than width, return the character count + c. decrement the character count + +4. If the loop completes itself without returning a value, it can't fit, + so return 0. + +void SetFocus(bool is_active) +----------------------------- + +This is for handling color states when a window receives or loses the +focus. + +1. Set focus flag to whatever is_active is. +2. call hook function \_SetFocus() + +bool GetFocus(void) +------------------- + +Returns the focus state held by the decorator + +1) Return the focus flag + +int32 \_TitleWidth(void) +------------------------ + +Returns the character count of the title or 0 if it is NULL. + +Virtual Functions +================= + +Most of these functions have a default behavior which can be +overridden, but are implemented to handle the more common +implementations. + +void MoveBy(float x, float y) +----------------------------- + +void MoveBy(BPoint pt) +---------------------- + +Move all member rectangles of Decorator by the specified amount. + +void ResizeBy(float x, float y) +------------------------------- + +void ResizeBy(BPoint pt) +------------------------ + +Resize the client frame, window frame, and the tab frame (width only) +by the specified amount. Button rectangles - close, minimize, and zoom +- are not modified. + +void Draw(BRect r) +------------------ + +void Draw(void) +--------------- + +Main drawing call which checks the intersection of the rectangle +passed to it and draws all items which intersect it. Draw(void) simply +performs drawing calls to draw the entire decorator's footprint area. + +1. Check for intersection with BRect which encompasses the decorator's + footprint and return if no intersection. +2. Call \_DrawFrame(intersection) +3. Call \_DrawTab(intersection) + +void DrawClose(void) +-------------------- + +protected: void \_DrawClose(BRect r) +------------------------------------ + +void DrawMinimize(void) +----------------------- + +protected: void \_DrawMinimize(BRect r) +--------------------------------------- + +void DrawZoom(void) +------------------- + +protected: void \_DrawZoom(BRect r) +----------------------------------- + +Each of these is designed to utilize their respective button +rectangles. The public (void) versions simply call the internal +protected ones with the button rectangle. These protected versions +are, by default, empty. The rectangle passed to them is the invalid +area to be drawn, which is not necessarily the entire button's +rectangle. + +void DrawFrame(void) +-------------------- + +protected: void \_DrawFrame(BRect r) +------------------------------------ + +Draws the frame, if any. The public version amounts to +\_DrawFrame(framerect). The protected version is expected to not cover +up the client frame when drawing. Any drawing within the clientrect +member will end up being drawn over by the window's child views. + +void DrawTab(void) +------------------ + +protected: void \_DrawTab(BRect r) +---------------------------------- + +Draws the window's tab, if any. DrawTab() amounts to +\_DrawTab(tabrect). If window titles are displayed, the \_DrawTitle +call is expected to be made here. Button-drawing calls, assuming that +a window's buttons are in the tab, should be made here, as well. + +void DrawTitle(void) +-------------------- + +protected: void \_DrawTitle(BRect r) +------------------------------------ + +These cause the window's title to be drawn. DrawTitle() amounts to +\_DrawTitle(titlerect). + +void \_SetFocus(void) +--------------------- + +This hook function is primarily used to change colors used when a +window changes focus states and is called immediately after the state +is changed. If, for example, a decorator does not use OpenBeOS' GUI +color set, it would change its drawing colors to reflect the change in +focus. + +SRegion GetFootprint(void) +-------------------------- + +This returns the "footprint" of the decorator, i.e. the area which is +occupied by the window which is is the border surrounding the main +client rectangle. It is possible to have oddly-shaped window borders, +like ellipses and circles, but the resulting performance hit would +reduce the said decorator to a novelty and not something useable. All +versions are to construct an SRegion which the border occupies. This +footprint is permitted to include the client rectangle area, but this +area must not be actually drawn upon by the decorator itself. The +default version returns the frame which encompasses all other +rectangles - the "frame" member which belongs to its window border. + +click_type Clicked(BPoint pt, int32 buttons, int32 modifiers) +------------------------------------------------------------- + +Clicked() performs hit testing for the decorator, given input +conditions. This function is required by ALL subclasses expecting to +do more than display itself. The return type will cause the server to +take the appropriate actions, such as close the window, get ready to +move it, etc. + + +BRect SlideTab(float dx, dy=0) +------------------------------ + +SlideTab is implemented only for those decorators which allow the user +to somehow slide the tab (if there is one) along the window. +Currently, only the horizontal direction is supported. It returns the +rectangle of the invalid region which needs redrawn as a result of the +slide. + +Exported C Functions +==================== + +extern "C" Decorator \*create_decorator(BRect frame, int32 wlook, int32 wfeel, int32 wflags) +-------------------------------------------------------------------------------------------- + +Required export function which simply allocates an instance of the +decorator and returns it. + +extern "C" float get_decorator_version(void) +-------------------------------------------- + +This should, for now, return 1.00. + +Enumerated Types +================ + +click_type +---------- + +- CLICK_NONE +- CLICK_ZOOM +- CLICK_CLOSE +- CLICK_MINIMIZE +- CLICK_TAB +- CLICK_MOVE +- CLICK_MOVETOBACK +- CLICK_MOVETOFRONT +- CLICK_RESIZE +- CLICK_RESIZE_L +- CLICK_RESIZE_T +- CLICK_RESIZE_R +- CLICK_RESIZE_B +- CLICK_RESIZE_LT +- CLICK_RESIZE_RT +- CLICK_RESIZE_LB +- CLICK_RESIZE_RB + diff --git a/docs/develop/servers/app_server/Desktop.htm b/docs/develop/servers/app_server/Desktop.htm deleted file mode 100644 index b54ed482e3..0000000000 --- a/docs/develop/servers/app_server/Desktop.htm +++ /dev/null @@ -1,150 +0,0 @@ - - -Desktop.htm - - - -
-

Desktop module

-


-

-

There are no globally accessible objects in this section of code, but many function definitions to work with workspaces, screen attributes, and other such things. These functions work with the private desktop classes Screen and Workspace.

-


-

-

-


-

-

Global Functions

-


-void InitDesktop(void)

-

void ShutdownDesktop(void)

-


-void AddWorkspace(int32 index=-1)

-

void DeleteWorkspace(int32 index)

-

int32 CountWorkspaces(void)

-

void SetWorkspaceCount(int32 count)

-

int32 CurrentWorkspace(screen_id screen=B_MAIN_SCREEN_ID)

-

void SetWorkspace(int32 workspace, screen_id screen=B_MAIN_SCREEN_ID)

-


-void SetScreen(screen_id id)

-

int32 CountScreens(void)

-

screen_id ActiveScreen(void)

-

DisplayDriver *GetGfxDriver(screen_id screen=B_MAIN_SCREEN_ID)

-

status_t SetSpace(int32 index, int32 res, bool stick=true, screen_id screen=B_MAIN_SCREEN_ID)

-


-void AddWindowToDesktop(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)

-

void RemoveWindowFromDesktop(ServerWindow *win)

-

ServerWindow *GetActiveWindow(void)

-

void SetActiveWindow(ServerWindow *win)

-

Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE, screen_id s

-

screen=B_MAIN_SCREEN_ID)

-


-void set_drag_message(int32 size, int8 *flattened)

-

int8* get_drag_message(int32 *size)

-

void empty_drag_ message(void)

-


-Namespaces

-


-desktop_private {

-

int8 *dragmessage

-

int32 dragmessagesize

-

sem_id draglock

-

}

-


-


-

-

void InitDesktop(void)

-


-Sets up all the stuff necessary for the system's desktop.

-


-1) Create a graphics module list by looping through allocation and initialization of display modules until failure is returned. If app_server exists, just create a ViewDriver module

-

2) Create and populate Screen list, pointing each Screen instance to its Driver instance

-

3) Create layer and workspace locks

-

4) Set screen 0 to active

-

5) Create the desktop_private::draglock semaphore

-


-
-void ShutdownDesktop(void)

-


-Undoes everything done in InitDesktop().

-


-1) Delete all locks

-

2) Delete all screens in the list

-

3) Delete the desktop_private::draglock semaphore

-

4) If desktop_private::dragmessage is non-NULL, delete it.

-


-
-void AddWorkspace(int32 index=-1)

-

void DeleteWorkspace(int32 index)

-

int32 CountWorkspaces(void)

-

void SetWorkspaceCount(int32 count)

-

int32 CurrentWorkspace(screen_id screen=B_MAIN_SCREEN_ID)

-

void SetWorkspace(int32 workspace, screen_id screen=B_MAIN_SCREEN_ID)

-


-Each of these calls the appropriate method in the Screen class. Add and Delete workspace functions operate on all screens.

-


-
-void SetScreen(screen_id id)

-

int32 CountScreens(void)

-

screen_id ActiveScreen(void)

-

DisplayDriver *GetGfxDriver(screen_id screen=B_MAIN_SCREEN_ID)

-

status_t SetSpace(int32 index, int32 res, bool stick=true, screen_id screen=B_MAIN_SCREEN_ID)

-


-Each of these calls operate on the objects in the Screen list, calling methods as appropriate.

-


-
-void AddWindowToDesktop(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)

-

void RemoveWindowFromDesktop(ServerWindow *win)

-

ServerWindow *GetActiveWindow(void)

-

void SetActiveWindow(ServerWindow *win)

-

Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID)

-


-These operate on the layer structure in the active Screen object, calling methods as appropriate.

-


-
-void set_drag_message(int32 size, int8 *flattened)

-


-This assigns a BMessage in its flattened state to the internal storage. Only one message can be stored at a time. Once an assignment is made, another cannot be made until the current one is emptied. If additional calls are made while there is a drag message assigned, the new assignment will not be made. Note that this merely passes a pointer around. No copies are made and the caller is responsible for freeing any allocated objects from the heap.

-


-1) Acquire the draglock

-

2) release the lock and return if winborder_private::dragmessage is non-NULL

-

3) Assign parameters to the private variables

-

4) Release the draglock

-


-
-int8* get_drag_message(int32 *size)

-


-Retrieve the current drag message in use. This function will fail if a NULL pointer is passed to it. Note that this does not free the current drag message from use. The size of the flattened message is stored in the size parameter. Note that if there is no message in use, it will return NULL and set size to 0.

-


-1) return NULL if size pointer is NULL

-

2) acquire the draglock

-

3) set value of size parameter to winborder_private::dragmessagesize

-

4) assign a temporary pointer the value of desktop_private::dragmessage

-

5) release the draglock

-

6) return the temporary pointer

-


-
-void empty_drag_ message(void)

-


-This empties the current drag message from use and allows for other messages to be assigned.

-


-1) acquire draglock

-

2) assign 0 to desktop_private::dragmessagesize and set desktop_private::dragmessage to NULL

-

3) release draglock

-
-
-
- - diff --git a/docs/develop/servers/app_server/Desktop.rst b/docs/develop/servers/app_server/Desktop.rst new file mode 100644 index 0000000000..a2ea7b6346 --- /dev/null +++ b/docs/develop/servers/app_server/Desktop.rst @@ -0,0 +1,147 @@ +Desktop module +############## + +There are no globally accessible objects in this section of code, but +many function definitions to work with workspaces, screen attributes, +and other such things. These functions work with the private desktop +classes Screen and Workspace. + +Global Functions +================ + +void InitDesktop(void) +---------------------- + +Sets up all the stuff necessary for the system's desktop. + +1. Create a graphics module list by looping through allocation and + initialization of display modules until failure is returned. If + app_server exists, just create a ViewDriver module +2. Create and populate Screen list, pointing each Screen instance to its + Driver instance +3. Create layer and workspace locks +4. Set screen 0 to active +5. Create the desktop_private::draglock semaphore + +void ShutdownDesktop(void) +-------------------------- + +Undoes everything done in InitDesktop(). + +1. Delete all locks +2. Delete all screens in the list +3. Delete the desktop_private::draglock semaphore +4. If desktop_private::dragmessage is non-NULL, delete it. + +void AddWorkspace(int32 index=-1) +--------------------------------- + +void DeleteWorkspace(int32 index) +--------------------------------- + +int32 CountWorkspaces(void) +--------------------------- + +void SetWorkspaceCount(int32 count) +----------------------------------- + +int32 CurrentWorkspace(screen_id screen=B_MAIN_SCREEN_ID) +--------------------------------------------------------- + +void SetWorkspace(int32 workspace, screen_id screen=B_MAIN_SCREEN_ID) +--------------------------------------------------------------------- + +Each of these calls the appropriate method in the Screen class. Add +and Delete workspace functions operate on all screens. + +void SetScreen(screen_id id) +---------------------------- + +int32 CountScreens(void) +------------------------ + +screen_id ActiveScreen(void) +---------------------------- + +DisplayDriver \*GetGfxDriver(screen_id screen=B_MAIN_SCREEN_ID) +--------------------------------------------------------------- + +status_t SetSpace(int32 index, int32 res, bool stick=true, screen_id screen=B_MAIN_SCREEN_ID) +--------------------------------------------------------------------------------------------- + +Each of these calls operate on the objects in the Screen list, calling +methods as appropriate. + +void AddWindowToDesktop(ServerWindow \*win, int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID) +------------------------------------------------------------------------------------------------------------------- + +void RemoveWindowFromDesktop(ServerWindow \*win) +------------------------------------------------ + +ServerWindow \*GetActiveWindow(void) +------------------------------------ + +void SetActiveWindow(ServerWindow \*win) +---------------------------------------- + +Layer \*GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE, screen_id screen=B_MAIN_SCREEN_ID) +-------------------------------------------------------------------------------------------- + +These operate on the layer structure in the active Screen object, +calling methods as appropriate. + +void set_drag_message(int32 size, int8 \*flattened) +--------------------------------------------------- + +This assigns a BMessage in its flattened state to the internal +storage. Only one message can be stored at a time. Once an assignment +is made, another cannot be made until the current one is emptied. If +additional calls are made while there is a drag message assigned, the +new assignment will not be made. Note that this merely passes a +pointer around. No copies are made and the caller is responsible for +freeing any allocated objects from the heap. + +1. Acquire the draglock +2. release the lock and return if winborder_private::dragmessage is + non-NULL +3. Assign parameters to the private variables +4. Release the draglock + +int8\* get_drag_message(int32 \*size) +------------------------------------- + +Retrieve the current drag message in use. This function will fail if a +NULL pointer is passed to it. Note that this does not free the current +drag message from use. The size of the flattened message is stored in +the size parameter. Note that if there is no message in use, it will +return NULL and set size to 0. + + +1. return NULL if size pointer is NULL +2. acquire the draglock +3. set value of size parameter to winborder_private::dragmessagesize +4. assign a temporary pointer the value of desktop_private::dragmessage +5. release the draglock +6. return the temporary pointer + +void empty_drag\_ message(void) +------------------------------- + +This empties the current drag message from use and allows for other +messages to be assigned. + + +1. acquire draglock +2. assign 0 to desktop_private::dragmessagesize and set + desktop_private::dragmessage to NULL +3. release draglock + +Namespaces +========== + +desktop_private +--------------- + +- int8 \*dragmessage +- int32 dragmessagesize +- sem_id draglock diff --git a/docs/develop/servers/app_server/DesktopClasses.htm b/docs/develop/servers/app_server/DesktopClasses.htm deleted file mode 100644 index c52b12b6e3..0000000000 --- a/docs/develop/servers/app_server/DesktopClasses.htm +++ /dev/null @@ -1,343 +0,0 @@ - - -DesktopClasses.htm - - - -
-

Screen class

-

Workspace class

-

RootLayer class

-


-The Screen class handles all infrastructure needed for each monitor/video card pair. The Workspace class holds data and supplies the infrastructure for drawing the screen.

-


-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Screen(DisplayDriver *gfxmodule, uint8 workspaces)

-
-

~Screen(void)

-
-

void AddWorkspace(int32 index=-1)

-
-

void DeleteWorkspace(int32 index)

-
-

int32 CountWorkspaces(void)

-
-

void SetWorkspaceCount(int32 count)

-
-

int32 CurrentWorkspace(void)

-
-

void SetWorkspace(int32 workspace)

-
-

void Activate(bool active=true)

-
-

DisplayDriver *GetDriver(void)

-
-

status_t SetSpace(int32 index, int32 res, bool stick=true)

-
-

void AddWindow(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE)

-
-

void RemoveWindow(ServerWindow *win)

-
-

ServerWindow *ActiveWindow(void)

-
-

void SetActiveWindow(ServerWindow *win)

-
-

Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE)

-
-

bool IsInitialized(void)

-
-

Workspace *GetActiveWorkspace(void)

-
-


-
-
-


-

-


-Screen(DisplayDriver *gfxmodule, uint8 workspaces)

-


-1) Set driver pointer to gfxmodule

-

2) If driver pointer is non-NULL and driver->Initialize() is true, set initialized flag to true

-

3) If initialized, get the appropriate display driver info and save it internally

-

4) Create and populate workspace list

-

5) Clear all workspaces

-


-~Screen(void)

-


-1) Remove all workspaces from the list and delete them

-

2) Delete the workspace list

-


-
-void AddWorkspace(int32 index=-1)

-


-Adds a workspace to the screen object, setting its settings to the default, and adding it to the list in the specified index or the end of the list if the index is -1

-


-1) Create a workspace object

-

2) Add it to the workspace list - to the end if the index is -1, and to the particular index if not

-


-
-void DeleteWorkspace(int32 index)

-


-Deletes the workspace at the specified index.

-


-1) Remove the item at the specified index and if non-NULL, delete it.

-


-
-int32 CountWorkspaces(void)

-


-Returns the number of workspaces kept by the particular Screen objects

-


-1) Return the workspace list's CountItems() value

-


-
-void SetWorkspaceCount(int32 count)

-


-Sets the number of workspaces available to count. If count is less than the number of current workspaces, the last workspaces are deleted first. Workspaces are added to the end of the list. If a delete workspace should include the active workspace, then the workspace with the index count-1 is activated. There must be at least one workspace.

-


-1) if count equals the workspace list's CountItems value, return

-

2) If count is less than 1, set count to 1. If greater than 32, set to 32.

-

3) If active workspace index is greater than count-1, call SetWorkspace(count-1)

-

4) If count is greater than the workspace list's CountItems value, call AddWorkspace the appropriate number of times.

-

5) If count is less than the workspace list's CountItems, call RemoveWorkspace the appropriate number of times

-


-
-int32 CurrentWorkspace(void)

-


-Returns the active workspace index

-


-
-void SetWorkspace(int32 workspace)

-

void Activate(bool active=true)

-

DisplayDriver *GetDriver(void)

-

status_t SetSpace(int32 index, int32 res, bool stick=true)

-

void AddWindow(ServerWindow *win, int32 workspace=B_CURRENT_WORKSPACE)

-

void RemoveWindow(ServerWindow *win)

-

ServerWindow *ActiveWindow(void)

-

void SetActiveWindow(ServerWindow *win)

-

Layer *GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE)

-

bool IsInitialized(void)

-

Workspace *GetActiveWorkspace(void)

-


-


-

-

Workspace class members

-


-

- - - - - - - - - - - - - - - - - -
-

Workspace(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)

-
-

~Workspace(void)

-
-

void SetBGColor(const RGBColor &c)

-
-

RGBColor BGColor(void)

-
-

RootLayer *GetRoot(void)

-
-

void SetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)

-
-

void GetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)

-
-   -
-


-
-
-Workspace(void)

-


-1) Set background color to RGB(51,102,160)

-

2) Copy frame_buffer_info and graphics_card_info structure values

-

3) Create a RootLayer object using the values from the two structures

-


-
-~Workspace(void)

-


-1) Call the RootLayer object's PruneTree method and delete it

-


-
-void SetBGColor(const RGBColor &c)

-


-Sets the particular color for the workspace. Note that this does not refresh the display.

-


-1) Set the internal background RGBColor object to the color parameter

-


-
-RGBColor BGColor(void)

-


-Returns the internal background color

-


-
-RootLayer *GetRoot(void)

-


-Returns the pointer to the RootLayer object

-


-
-void SetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)

-


-Changes the graphics data and resizes the RootLayer accordingly.

-


-1) Copy the two structures to the internal one

-

2) Resize the RootLayer

-

3) If the RootLayer was resized larger, Invalidate the new areas

-


-
-void GetData(graphics_card_info *gcinfo, frame_buffer_info *fbinfo)

-


-Copies the two data structures into the parameters passed.

-


-


-

-

RootLayer class members

-


-

- - - - - - - - - - - - - - - - - -
-

RootLayer(BRect frame, const char *name)

-
-

~RootLayer(void)

-
-

void RequestDraw(const BRect &r)

-
-

void MoveBy(float x, float y)

-
-

void MoveBy(BPoint pt)

-
-

void SetDriver(DisplayDriver *d)

-
-

void RebuildRegions(bool recursive=false)

-
-   -
-


-
-RootLayer(BRect frame, const char *name)

-


-1) passes B_FOLLOW_NONE to Layer constructor

-

2) set level to 0

-

3) set the background color to the color for the workspace set in the system preferences

-


-
-~RootLayer(void)

-


-Does nothing.

-


-
-void RequestDraw(const BRect &r)

-


-Requests that the layer be drawn on screen. The rectangle passed is in the layer's own coordinates.

-


-1) call the display driver's FillRect on the rectangle, filling with the layer's background color

-

2) recurse through each child and call its RequestDraw() function if it intersects the child's frame

-


-
-void MoveBy(BPoint pt)

-

void MoveBy(float x, float y)

-


-Made empty so that the root layer cannot be moved

-


-
-void SetDriver(DisplayDriver *d)

-


-Assigns a particular display driver object to the root layer if non-NULL.

-


-
-void RebuildRegions(bool recursive=false)

-


-Rebuilds the visible and invalid layers based on the layer hierarchy. Used to update the regions after a call to remove or add a child layer is made or when a layer is hidden or shown.

-


-1) get the frame

-

2) set full and visible regions to frame

-

3) iterate through each child and exclude its full region from the visible region if the child is visible.

-
-
-
- - diff --git a/docs/develop/servers/app_server/DesktopClasses.rst b/docs/develop/servers/app_server/DesktopClasses.rst new file mode 100644 index 0000000000..8604fcbd1f --- /dev/null +++ b/docs/develop/servers/app_server/DesktopClasses.rst @@ -0,0 +1,216 @@ +Screen class +############ + +The Screen class handles all infrastructure needed for each +monitor/video card pair. The Workspace class holds data and supplies +the infrastructure for drawing the screen. + +Member Functions +================ + +Screen(DisplayDriver \*gfxmodule, uint8 workspaces) +--------------------------------------------------- + +1. Set driver pointer to gfxmodule +2. If driver pointer is non-NULL and driver->Initialize() is true, set + initialized flag to true +3. If initialized, get the appropriate display driver info and save it + internally +4. Create and populate workspace list +5. Clear all workspaces + + +~Screen(void) +------------- + +1. Remove all workspaces from the list and delete them +2. Delete the workspace list + +void AddWorkspace(int32 index=-1) +--------------------------------- + +Adds a workspace to the screen object, setting its settings to the +default, and adding it to the list in the specified index or the end +of the list if the index is -1 + + +1. Create a workspace object +2. Add it to the workspace list - to the end if the index is -1, and to + the particular index if not + +void DeleteWorkspace(int32 index) +--------------------------------- + +Deletes the workspace at the specified index. + + +1. Remove the item at the specified index and if non-NULL, delete it. + +int32 CountWorkspaces(void) +--------------------------- + +Returns the number of workspaces kept by the particular Screen objects + +1. Return the workspace list's CountItems() value + +void SetWorkspaceCount(int32 count) +----------------------------------- + +Sets the number of workspaces available to count. If count is less +than the number of current workspaces, the last workspaces are deleted +first. Workspaces are added to the end of the list. If a delete +workspace should include the active workspace, then the workspace with +the index count-1 is activated. There must be at least one workspace. + +1. if count equals the workspace list's CountItems value, return +2. If count is less than 1, set count to 1. If greater than 32, set to 32. +3. If active workspace index is greater than count-1, call SetWorkspace(count-1) +4. If count is greater than the workspace list's CountItems value, call + AddWorkspace the appropriate number of times. +5. If count is less than the workspace list's CountItems, call + RemoveWorkspace the appropriate number of times + +int32 CurrentWorkspace(void) +---------------------------- + +Returns the active workspace index + +void SetWorkspace(int32 workspace) +---------------------------------- + +void Activate(bool active=true) +------------------------------- + +DisplayDriver \*GetDriver(void) +------------------------------- + +status_t SetSpace(int32 index, int32 res, bool stick=true) +---------------------------------------------------------- + +void AddWindow(ServerWindow \*win, int32 workspace=B_CURRENT_WORKSPACE) +----------------------------------------------------------------------- + +void RemoveWindow(ServerWindow \*win) +------------------------------------- + +ServerWindow \*ActiveWindow(void) +--------------------------------- + +void SetActiveWindow(ServerWindow \*win) +---------------------------------------- + +Layer \*GetRootLayer(int32 workspace=B_CURRENT_WORKSPACE) +--------------------------------------------------------- + +bool IsInitialized(void) +------------------------ + +Workspace \*GetActiveWorkspace(void) +------------------------------------ + +Workspace class members +======================= + +Workspace(void) +--------------- + +1. Set background color to RGB(51,102,160) +2. Copy frame_buffer_info and graphics_card_info structure values +3. Create a RootLayer object using the values from the two structures + +~Workspace(void) +---------------- + +1. Call the RootLayer object's PruneTree method and delete it + +void SetBGColor(const RGBColor &c) +---------------------------------- + +Sets the particular color for the workspace. Note that this does not +refresh the display. + +1. Set the internal background RGBColor object to the color parameter + +RGBColor BGColor(void) +---------------------- + +Returns the internal background color + + +RootLayer \*GetRoot(void) +------------------------- + +Returns the pointer to the RootLayer object + + +void SetData(graphics_card_info \*gcinfo, frame_buffer_info \*fbinfo) +--------------------------------------------------------------------- + +Changes the graphics data and resizes the RootLayer accordingly. + + +1. Copy the two structures to the internal one +2. Resize the RootLayer +3. If the RootLayer was resized larger, Invalidate the new areas + + +void GetData(graphics_card_info \*gcinfo, frame_buffer_info \*fbinfo) +--------------------------------------------------------------------- + +Copies the two data structures into the parameters passed. + +RootLayer class members +======================= + +RootLayer(BRect frame, const char \*name) + + +1. passes B_FOLLOW_NONE to Layer constructor +2. set level to 0 +3. set the background color to the color for the workspace set in the + system preferences + + +~RootLayer(void) +---------------- + +Does nothing. + + +void RequestDraw(const BRect &r) +-------------------------------- + +Requests that the layer be drawn on screen. The rectangle passed is in +the layer's own coordinates. + + +1. call the display driver's FillRect on the rectangle, filling with + the layer's background color +2. recurse through each child and call its RequestDraw() function if it + intersects the child's frame + +void MoveBy(BPoint pt), void MoveBy(float x, float y) +----------------------------------------------------- + +Made empty so that the root layer cannot be moved + +void SetDriver(DisplayDriver \*d) +--------------------------------- + +Assigns a particular display driver object to the root layer if +non-NULL. + + +void RebuildRegions(bool recursive=false) +----------------------------------------- + +Rebuilds the visible and invalid layers based on the layer hierarchy. +Used to update the regions after a call to remove or add a child layer +is made or when a layer is hidden or shown. + + +1. get the frame +2. set full and visible regions to frame +3. iterate through each child and exclude its full region from the + visible region if the child is visible. + diff --git a/docs/develop/servers/app_server/DisplayDriver.htm b/docs/develop/servers/app_server/DisplayDriver.htm deleted file mode 100644 index b6d0dd14c3..0000000000 --- a/docs/develop/servers/app_server/DisplayDriver.htm +++ /dev/null @@ -1,290 +0,0 @@ - - -DisplayDriver.htm - - - -
-

DisplayDriver class

-


-

-

The DisplayDriver class is not a useful class unto itself. It is to provide a consistent interface for the rest of the app_server to whatever rendering context it is utilizing, whether it be a remote screen, a ServerBitmap, installed graphics hardware, or whatever. Documentation below will describe the role of each function.

-

-


-

-

Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

DisplayDriver(void)

-
-

~DisplayDriver(void)

-
-

bool Initialize(void)

-
-

void Shutdown(void)

-
-

void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest)

-
-

void DrawChar(char c, BPoint pt)

-
-

void DrawString(const char *string, int32 length, BPoint pt, escapement_delta *delta=NULL)

-
-

void Stroke/FillBezier(BPoint *pts, layerdata *d, int8 *pat)

-
-

void Stroke/FillEllipse(BRect r, layerdata *d, int8 *pattern)

-
-

void Stroke/FillArc(BRect r, float angle, float span, layerdata *d, int8 *pattern)

-
-

void StrokeLine(BPoint start, BPoint end, layerdata *d, int8 *pattern)

-
-

void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern, bool is_closed=true)

-
-

void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern)

-
-

void Stroke/FillRect(BRect r, layerdata *d, int8 *pattern)

-
-

void Stroke/FillRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern)

-
-

void Stroke/FillShape(SShape *sh, layerdata *d, int8 *pattern)

-
-

void Stroke/FillTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern)

-
-

void StrokeLineArray(BPoint *pts, int32 numlines, rgb_color *colors, layerdata *d)

-
-

void DrawPicture(SPicture *pic, BPoint pt)

-
-

void CopyBits(BRect src, BRect dest)

-
-

void InvertRect(BRect r)

-
-

uint8 GetDepth(void)

-
-

uint16 GetHeight(void)

-
-

uint16 GetWidth(void)

-
-

screen_mode GetMode(void)

-
-

void SetMode(screen_mode mode)

-
-

bool DumpToFile(const char *path)

-
-

void ShowCursor(void)

-
-

void HideCursor(void)

-
-

void ObscureCursor(void)

-
-

bool IsCursorHidden(void)

-
-

void SetCursor(ServerCursor *csr)

-
-

virtual float StringWidth(const char *string, int32 length, LayerData *d)

-
-

virtual float StringHeight(const char *string, int32 length, LayerData *d)

-
-


-
-Protected Functions

-


-

- - - - - - - - - - - - - - - - - -
-

void Lock(void)

-
-

void Unlock(void)

-
-

void SetDepth(void)

-
-

void SetHeight(void)

-
-

void SetWidth(void)

-
-

void SetMode(void)

-
-

void SetCursorHidden(void)

-
-

void SetCursorObscured(void)

-
-


-
-


-

-

DisplayDriver(void)

-

~DisplayDriver(void)

-

bool Initialize(void)

-

void Shutdown(void)

-


-These four are for general start and stop procedures. The constructor and destructor concern themselves with the internal members common to all drivers, such as the current cursor and the access semaphore. Subclasses will probably end up using these to handle memory allocation-related issues, but likely not much else. Initialize() and Shutdown() are for general setup internal to the module. Note that if Initialize() returns false, the server will not use the module, call Shutdown(), and then delete it as accordingly.

-


-void CopyBits(BRect src, BRect dest)

-

void InvertRect(BRect r)

-

void DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest, render_mode mode)

-

void DrawPicture(SPicture *pic, BPoint pt)

-

void DrawChar(char c, BPoint pt)

-

void DrawString(const char *string, int32 length, BPoint pt, escapement_delta *delta=NULL)

-


-void StrokeArc(BRect r, float angle, float span, layerdata *d, int8 *pattern)

-

void FillArc(BRect r, float angle, float span, layerdata *d, int8 *pattern)

-

void StrokeBezier(BPoint *pts, layerdata *d, int8 *pat)

-

void FillBezier(BPoint *pts, layerdata *d, int8 *pat)

-

void StrokeEllipse(BRect r, layerdata *d, int8 *pattern)

-

void FillEllipse(BRect r, layerdata *d, int8 *pattern)

-

void StrokeLine(BPoint start, BPoint end, layerdata *d, int8 *pattern)

-

void StrokeLineArray(BPoint *pts, int32 numlines, rgb_color *colors, layerdata *d)

-

void StrokePolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern, bool is_closed=true)

-

void FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, layerdata *d, int8 *pattern)

-

void StrokeRect(BRect r, layerdata *d, int8 *pattern)

-

void FillRect(BRect r, layerdata *d, int8 *pattern)

-

void StrokeRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern)

-

void FillRoundRect(BRect r, float xrad, float yrad, layerdata *d, int8 *pattern)

-

void StrokeShape(SShape *sh, layerdata *d, int8 *pattern)

-

void FillShape(SShape *sh, layerdata *d, int8 *pattern)

-

void StrokeTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern)

-

void FillTriangle(BPoints *pts, BRect r, layerdata *d, int8 *pattern)

-

void ShowCursor(void)

-

void HideCursor(void)

-

void ObscureCursor(void)

-

bool IsCursorHidden(void)

-

void SetCursor(ServerCursor *csr)

-

float StringWidth(const char *string, int32 length, LayerData *d)

-

float StringHeight(const char *string, int32 length, LayerData *d)

-


-These drawing functions are the meat and potatoes of the graphics module. Defining any or all of them is completely optional. However, the default versions of these functions will do nothing. Thus, implementing them is likely a good idea, even if not required.

-


-
-uint8 GetDepth(void)

-

uint16 GetHeight(void)

-

uint16 GetWidth(void)

-

screen_mode GetMode(void)

-

void SetMode(screen_mode mode)

-


-These five functions are called internally in order to get information about the current state of the buffer in the module. GetDepth should return 8, 16, or 32, in any event because the server handles RGB color spaces of these depths only.

-


-bool DumpToFile(const char *path)

-


-DumpToFile is completely optional, providing a hook which allows screenshots to be taken. The default version does nothing but return false. If a screenshot is successful, return true.

-


-
-void Lock(void)

-

void Unlock(void)

-


-These two functions provide a locking scheme for the driver in order to easily make it thread safe. Note that it is not publicly callable.

-


-
-void SetDepthInternal(uint8 d)

-

void SetHeightInternal(uint16 h)

-

void SetWidthInternal(uint16 w)

-

void SetModeInternal(int32 m)

-


-These four functions set the internal state variables for height, width, etc. If the driver reimplements the public members SetDepth(), etc, be sure to call the respective internal call so that calls to GetDepth(), etc. return the proper values.

-


-
-void SetCursorHidden(bool state)

-

void SetCursorObscured(bool state)

-

bool IsCursorObscured(void)

-


-These calls handle internal state tracking so that subclasses don't have to.

-
-
-
- - diff --git a/docs/develop/servers/app_server/DisplayDriver.rst b/docs/develop/servers/app_server/DisplayDriver.rst new file mode 100644 index 0000000000..a120bd4899 --- /dev/null +++ b/docs/develop/servers/app_server/DisplayDriver.rst @@ -0,0 +1,210 @@ +DisplayDriver class +################### + +The DisplayDriver class is not a useful class unto itself. It is to +provide a consistent interface for the rest of the app_server to +whatever rendering context it is utilizing, whether it be a remote +screen, a ServerBitmap, installed graphics hardware, or whatever. +Documentation below will describe the role of each function. + +Member Functions +================ + +DisplayDriver(void) +------------------- + +~DisplayDriver(void) +-------------------- + +bool Initialize(void) +--------------------- + +void Shutdown(void) +------------------- + +These four are for general start and stop procedures. The constructor +and destructor concern themselves with the internal members common to +all drivers, such as the current cursor and the access semaphore. +Subclasses will probably end up using these to handle memory +allocation-related issues, but likely not much else. Initialize() and +Shutdown() are for general setup internal to the module. Note that if +Initialize() returns false, the server will not use the module, call +Shutdown(), and then delete it as accordingly. + +void CopyBits(BRect src, BRect dest) +------------------------------------ + +void InvertRect(BRect r) +------------------------ + +void DrawBitmap(ServerBitmap \*bmp, BRect src, BRect dest, render_mode mode) +---------------------------------------------------------------------------- + +void DrawPicture(SPicture \*pic, BPoint pt) +------------------------------------------- + +void DrawChar(char c, BPoint pt) +-------------------------------- + +void DrawString(const char \*string, int32 length, BPoint pt, escapement_delta \*delta=NULL) +-------------------------------------------------------------------------------------------- + +void StrokeArc(BRect r, float angle, float span, layerdata \*d, int8 \*pattern) +------------------------------------------------------------------------------- + +void FillArc(BRect r, float angle, float span, layerdata \*d, int8 \*pattern) +----------------------------------------------------------------------------- + +void StrokeBezier(BPoint \*pts, layerdata \*d, int8 \*pat) +---------------------------------------------------------- + +void FillBezier(BPoint \*pts, layerdata \*d, int8 \*pat) +-------------------------------------------------------- + +void StrokeEllipse(BRect r, layerdata \*d, int8 \*pattern) +---------------------------------------------------------- + +void FillEllipse(BRect r, layerdata \*d, int8 \*pattern) +-------------------------------------------------------- + +void StrokeLine(BPoint start, BPoint end, layerdata \*d, int8 \*pattern) +------------------------------------------------------------------------ + +void StrokeLineArray(BPoint \*pts, int32 numlines, rgb_color \*colors, layerdata \*d) +------------------------------------------------------------------------------------- + +void StrokePolygon(BPoint \*ptlist, int32 numpts, BRect rect, layerdata \*d, int8 \*pattern, bool is_closed=true) +----------------------------------------------------------------------------------------------------------------- + +void FillPolygon(BPoint \*ptlist, int32 numpts, BRect rect, layerdata \*d, int8 \*pattern) +------------------------------------------------------------------------------------------ + +void StrokeRect(BRect r, layerdata \*d, int8 \*pattern) +------------------------------------------------------- + +void FillRect(BRect r, layerdata \*d, int8 \*pattern) +----------------------------------------------------- + +void StrokeRoundRect(BRect r, float xrad, float yrad, layerdata \*d, int8 \*pattern) +------------------------------------------------------------------------------------ + +void FillRoundRect(BRect r, float xrad, float yrad, layerdata \*d, int8 \*pattern) +---------------------------------------------------------------------------------- + +void StrokeShape(SShape \*sh, layerdata \*d, int8 \*pattern) +------------------------------------------------------------ + +void FillShape(SShape \*sh, layerdata \*d, int8 \*pattern) +---------------------------------------------------------- + +void StrokeTriangle(BPoints \*pts, BRect r, layerdata \*d, int8 \*pattern) +-------------------------------------------------------------------------- + +void FillTriangle(BPoints \*pts, BRect r, layerdata \*d, int8 \*pattern) +------------------------------------------------------------------------ + +void ShowCursor(void) +--------------------- + +void HideCursor(void) +--------------------- + +void ObscureCursor(void) +------------------------ + +bool IsCursorHidden(void) +------------------------- + +void SetCursor(ServerCursor \*csr) +---------------------------------- + +float StringWidth(const char \*string, int32 length, LayerData \*d) +------------------------------------------------------------------- + +float StringHeight(const char \*string, int32 length, LayerData \*d) +-------------------------------------------------------------------- + + +These drawing functions are the meat and potatoes of the graphics +module. Defining any or all of them is completely optional. However, +the default versions of these functions will do nothing. Thus, +implementing them is likely a good idea, even if not required. + + + +Protected Functions +=================== + +uint8 GetDepth(void) +-------------------- + +uint16 GetHeight(void) +---------------------- + +uint16 GetWidth(void) +--------------------- + +screen_mode GetMode(void) +------------------------- + +void SetMode(screen_mode mode) +------------------------------ + + +These five functions are called internally in order to get information +about the current state of the buffer in the module. GetDepth should +return 8, 16, or 32, in any event because the server handles RGB color +spaces of these depths only. + + +bool DumpToFile(const char \*path) +---------------------------------- + +DumpToFile is completely optional, providing a hook which allows +screenshots to be taken. The default version does nothing but return +false. If a screenshot is successful, return true. + + +void Lock(void) +--------------- + +void Unlock(void) +----------------- + + +These two functions provide a locking scheme for the driver in order +to easily make it thread safe. Note that it is not publicly callable. + + +void SetDepthInternal(uint8 d) +------------------------------ + +void SetHeightInternal(uint16 h) +-------------------------------- + +void SetWidthInternal(uint16 w) +------------------------------- + +void SetModeInternal(int32 m) +----------------------------- + + +These four functions set the internal state variables for height, +width, etc. If the driver reimplements the public members SetDepth(), +etc, be sure to call the respective internal call so that calls to +GetDepth(), etc. return the proper values. + + +void SetCursorHidden(bool state) +-------------------------------- + +void SetCursorObscured(bool state) +---------------------------------- + +bool IsCursorObscured(void) +--------------------------- + + +These calls handle internal state tracking so that subclasses don't +have to. + diff --git a/docs/develop/servers/app_server/FontFamily.htm b/docs/develop/servers/app_server/FontFamily.htm deleted file mode 100644 index f353ea93a2..0000000000 --- a/docs/develop/servers/app_server/FontFamily.htm +++ /dev/null @@ -1,141 +0,0 @@ - - -FontFamily.htm - - - -
-

FontFamily class

-


-FontFamily objects are used to tie together all related font styles.

-


-


-

-

Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - -
-

FontFamily(const char *name)

-
-

~FontFamily(void)

-
-

const char *GetName(void)

-
-

void AddStyle(const char *path, FT_Face face)

-
-

void RemoveStyle(const char *style)

-
-

FontStyle *GetStyle(const char *stylename)

-
-

const char *GetStyle(int32 index)

-
-

int32 CountStyles(void)

-
-

bool HasStyle(const char *style)

-
-   -
-


-
-
-


-

-

FontFamily(const char *name)

-


-1) Create and set internal name to the one passed to the constructor

-

2) Create the styles list

-


-
-~FontFamily(void)

-


-1) delete the internal name

-

2) empty and delete the internal style list

-


-
-const char *GetName(void)

-


-Returns the internal family name

-


-
-void AddStyle(const char *path, FT_Face face)

-


-Adds the style to the family.

-


-1) Create the FontStyle object and add it to the style list.

-


-
-void RemoveStyle(const char *style)

-


-Removes the style from the FontFamily object.

-


-1) Call GetStyle on the given pointer

-

2) If non-NULL, delete the object

-

3) If the style list is now empty, ask the FontServer to remove it from the family list

-


-
-FontStyle *GetStyle(const char *style)

-


-Looks up a FontStyle object based on its style name. Returns NULL if not found.

-


-1) Iterate through the style list

-

a) compare style to each FontStyle object's GetName method and return the object if they are the same

-

2) If all items have been checked and nothing has been returned, return NULL

-


-
-const char *GetStyle(int32 index)

-


-Returns the name of the style at index

-


-1) Get the FontStyle item at index obtained via the style list's ItemAt call

-


-
-int32 CountStyles(void)

-


-Returns the number of items in the style list and, thus, the number of styles in the family

-


-
-bool HasStyle(const char *stylename)

-


-Returns true if the family has a style with the name stylename

-


-1) Call GetStyle on the style name and return false if NULL, true if not.

-


-

-
-
-
- - diff --git a/docs/develop/servers/app_server/FontFamily.rst b/docs/develop/servers/app_server/FontFamily.rst new file mode 100644 index 0000000000..7f0c277950 --- /dev/null +++ b/docs/develop/servers/app_server/FontFamily.rst @@ -0,0 +1,86 @@ +FontFamily class +################ + +FontFamily objects are used to tie together all related font styles. + +Member Functions +================ + +FontFamily(const char \*name) +----------------------------- + +1. Create and set internal name to the one passed to the constructor +2. Create the styles list + + +~FontFamily(void) +----------------- + +1. delete the internal name +2. empty and delete the internal style list + +const char \*GetName(void) +--------------------------- + +Returns the internal family name + + +void AddStyle(const char \*path, FT_Face face) +---------------------------------------------- + +Adds the style to the family. + + +1. Create the FontStyle object and add it to the style list. + + +void RemoveStyle(const char \*style) +------------------------------------ + +Removes the style from the FontFamily object. + + +1. Call GetStyle on the given pointer +2. If non-NULL, delete the object +3. If the style list is now empty, ask the FontServer to remove it from the family list + +FontStyle \*GetStyle(const char \*style) +---------------------------------------- + +Looks up a FontStyle object based on its style name. Returns NULL if +not found. + + +1. Iterate through the style list + + a. compare style to each FontStyle object's GetName method and return the object if they are the same + +2. If all items have been checked and nothing has been returned, return NULL + + +const char \*GetStyle(int32 index) +---------------------------------- + +Returns the name of the style at index + + +1. Get the FontStyle item at index obtained via the style list's +ItemAt call + + +int32 CountStyles(void) +----------------------- + +Returns the number of items in the style list and, thus, the number of +styles in the family + + +bool HasStyle(const char \*stylename) +------------------------------------- + +Returns true if the family has a style with the name stylename + + +1. Call GetStyle on the style name and return false if NULL, true if +not. + diff --git a/docs/develop/servers/app_server/FontServer.htm b/docs/develop/servers/app_server/FontServer.htm deleted file mode 100644 index 13e0fe5d34..0000000000 --- a/docs/develop/servers/app_server/FontServer.htm +++ /dev/null @@ -1,274 +0,0 @@ - - -FontServer.htm - - - -
-

FontServer class

-


-

-

The FontServer provides the base functionality for providing font support for the rest of the system and insulates the rest of the server from having to deal too much with FreeType.

-


-


-

-

Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

FontServer(void)

-
-

~FontServer(void)

-
-

void Lock(void)

-
-

void Unlock(void)

-
-

void SaveList(void)

-
-

status_t ScanDirectory(const char *path)

-
-

FontStyle *GetFont(font_family family, font_style face)

-
-

FontInstance *GetInstance(font_family family, font_style face, int16 size, int16 rotation, int16 shear)

-
-

int32 CountFamiles(void)

-
-

status_t IsInitialized(void)

-
-

int32 CountStyles(font_family family)

-
-

FontStyle *GetStyle(font_family family, font_style style)

-
-

void RemoveFamily(const char *family)

-
-

FontFamily *_FindFamily(const char *name)

-
-

ServerFont *GetSystemPlain(void)

-
-

ServerFont *GetSystemBold(void)

-
-

ServerFont *GetSystemFixed(void)

-
-

bool SetSystemPlain(const char *family, const char *style, float size)

-
-

void RemoveUnusedFamilies(void)

-
-

bool FontsNeedUpdated(void)

-
-


-
-


-

-

FontServer(void)

-


-1) Create access semaphore

-

2) Call FT_Init_FreeType()

-

3) If no error initializing the FreeType library, set init flag to true

-


-
-~FontServer(void)

-


-1) Call FT_Done_FreeType()

-


-
-void Lock(void)

-

void Unlock(void)

-


-These functions simply acquire and release the internal access semaphore.

-


-
-void SaveList(void)

-


-Saves the list of all scanned and valid font families and styles to disk

-


-1) create a BMessage for storing font family data (hereafter, the font message)

-

2) create a BMessage for storing a list of font family messages (hereafter, the list message)

-

3) create a boolean tuned flag and a boolean fixed flag

-

4) Iterate through all families

-

A) for each family, get its name and add its name to the font message as "name"

-

B) iterate through the families styles

-

a) get the style's name, and if valid, add it to the font message as "styles"

-

b) if IsTuned and IsScalable, set the tuned flag to true

-

c) if IsFixedWidth, set the fixed flag to true

-

C) if the tuned flag is set, add a boolean true to the font message as "tuned"

-

D) if the fixed flag is set, add a boolean true to the font message as "fixed"

-

E) add the font message to the list message as "family"

-

F) empty the font message

-

5) Create a BFile from the path definition SERVER_FONT_LIST for Read/Write, creating the file if nonexistent and erasing any existing one

-

6) Flatten the list message to the created BFile object

-

7) Set the needs_update flag to false

-


-
-status_t ScanDirectory(const char *path)

-


-ScanDirectory is where the brunt of the work of the FontServer is done - scans the directory of all fonts which can be loaded.

-


-1) Make a BDirectory object pointer at the path parameter. If the init code is not B_OK, return it.

-

2) Enter a while() loop, iterating through each entry in the given directory, executing as follows:

-

a) Ensure that the entry is not '.' or '..'

-

b) Call FT_New_Face on the entry's full path

-

c) If a valid FT_Face is returned, iterate through to see if there are any supported character mappings in the current entry.

-

d) If there are no supported character mappings, dump the supported mappings to debug output, call FT_Done_Face(), and continue to the next entry

-

e) See if the entry's family has been added to the family list. If it hasn't, create one and add it.

-

f) Check to see if the font's style has been added to its family. If so, call FT_Done_Face, and continue to the next entry

-

g) If the style has not been added, create a new SFont for that family and face, increment the font count, and continue to the next entry.

-

3) set the needs_update flag to true

-

4) Return B_OK

-


-Supported character mappings are Windows and Apple Unicode, Windows symbol, and Apple Roman character mappings, in order of preference from first to last.

-


-
-FontStyle *GetFont(font_family family, font_style face)

-


-Returns an FontStyle object for the specified family and style or NULL if not found.

-


-1) Call _FindFamily() for the given family

-

2) If non-NULL, call its FindStyle() method

-

3) Return the result

-


-
-FontInstance *GetInstance(font_family family, font_style face, int16 size, int16 rotation, int16 shear)

-


-Returns a usable instance of a specified font object with specified properties.

-


-1) Duplicates and performs the code found in GetFont

-

2) Assuming that the FontStyle object is non-NULL, it calls its GetInstance method and returns the result.

-


-
-int32 CountFamilies(void)

-


-Returns the number of valid font families available to the system.

-


-1) Return the number of items in the family list

-


-
-status_t IsInitialized(void)

-


-Returns the initialization status variable

-


-
-int32 CountStyles(font_family family)

-


-Returns the number of styles available for a given font family.

-


-1) Call _FindFamily() to get the appropriate font family

-

2) If non-NULL, call its return the result of its CountStyles method

-


-
-FontStyle *GetStyle(font_family family, font_style style)

-


-Gets the FontStyle object of the family, style, and flags.

-


-1) Call _FindFamily() to get the appropriate font family

-

2) If non-NULL, call the family's GetStyle method on the font_style parameter and return the result

-

3) If family is NULL, return NULL

-


-
-void RemoveFamily(const char *family)

-


-Removes a font family from the family list

-


-1) Look up font family in the family list via _FindFamily()

-

2) If it exists, delete it

-


-
-protected:

-


-FontFamily *_FindFamily(const char *name)

-


-Looks up a FontFamily object based on its family name. Returns NULL if not found.

-


-1) Call the family list's find() method.

-

2) Return the appropriate FontFamily object or NULL if not found.

-


-
-ServerFont *GetSystemPlain(void)

-

ServerFont *GetSystemBold(void)

-

ServerFont *GetSystemFixed(void)

-


-These return a copy of a pointer to the system-wide ServerFont objects which represent the appropriate system font settings. It is the responsibility of the caller to delete the object returned. NULL is returned if no setting has been set for a particular system font.

-


-bool SetSystemPlain(const char *family, const char *style, float size)

-

bool SetSystemBold(const char *family, const char *style, float size)

-

bool SetSystemFixed(const char *family, const char *style, float size)

-


-The system fonts settings may be set via these calls by specifying the family, style, and size. They return true if everything worked out ok and false if not. Settings are not changed if false is returned.

-


-1) Call _FindFamily on the family parameter. if NULL, return false

-

2) Call the family's GetStyle member. if NULL, return false

-

3) if the appropriate system font pointer is non-NULL, delete it

-

4) call the style's Instantiate member with the size parameter

-


-
-void RemoveUnusedFamilies(void)

-


-The purpose of this function is to allow for a complete rescan of the fonts in the appropriate directories.

-


-1) Iterate through the family list

-

A) Get a family

-

B) if it has no dependents, remove it from the list and delete it

-

2) Set the needs_update flag to true

-


-
-bool FontsNeedUpdated(void)

-


-Returns the value of the needs_update flag

-
-
-
- - diff --git a/docs/develop/servers/app_server/FontServer.rst b/docs/develop/servers/app_server/FontServer.rst new file mode 100644 index 0000000000..3a7d3276a9 --- /dev/null +++ b/docs/develop/servers/app_server/FontServer.rst @@ -0,0 +1,228 @@ +FontServer class +################ + +The FontServer provides the base functionality for providing font +support for the rest of the system and insulates the rest of the server +from having to deal too much with FreeType. + +Member Functions +================ + ++-----------------------------------+-----------------------------------+ +| FontServer(void) | ~FontServer(void) | ++-----------------------------------+-----------------------------------+ +| void Lock(void) | void Unlock(void) | ++-----------------------------------+-----------------------------------+ +| void SaveList(void) | status_t ScanDirectory(const char | +| | \*path) | ++-----------------------------------+-----------------------------------+ +| FontStyle \*GetFont(font_family | FontInstance | +| family, font_style face) | \*GetInstance(font_family family, | +| | font_style face, int16 size, | +| | int16 rotation, int16 shear) | ++-----------------------------------+-----------------------------------+ +| int32 CountFamiles(void) | status_t IsInitialized(void) | ++-----------------------------------+-----------------------------------+ +| int32 CountStyles(font_family | FontStyle \*GetStyle(font_family | +| family) | family, font_style style) | ++-----------------------------------+-----------------------------------+ +| void RemoveFamily(const char | FontFamily \*_FindFamily(const | +| \*family) | char \*name) | ++-----------------------------------+-----------------------------------+ +| ServerFont \*GetSystemPlain(void) | ServerFont \*GetSystemBold(void) | ++-----------------------------------+-----------------------------------+ +| ServerFont \*GetSystemFixed(void) | bool SetSystemPlain(const char | +| | \*family, const char \*style, | +| | float size) | ++-----------------------------------+-----------------------------------+ +| void RemoveUnusedFamilies(void) | bool FontsNeedUpdated(void) | ++-----------------------------------+-----------------------------------+ + +FontServer(void) +---------------- + +1. Create access semaphore +2. Call FT_Init_FreeType() +3. If no error initializing the FreeType library, set init flag to true + +~FontServer(void) +----------------- + +1. Call FT_Done_FreeType() + +void Lock(void), void Unlock(void) +---------------------------------- + +These functions simply acquire and release the internal access +semaphore. + +void SaveList(void) +------------------- + +Saves the list of all scanned and valid font families and styles to +disk + + +1. create a BMessage for storing font family data (hereafter, the font message) +2. create a BMessage for storing a list of font family messages (hereafter, the list message) +3. create a boolean tuned flag and a boolean fixed flag +4. Iterate through all families + + A. for each family, get its name and add its name to the font message as "name" + B. iterate through the families styles + + a. get the style's name, and if valid, add it to the font message as "styles" + b. if IsTuned and IsScalable, set the tuned flag to true + c. if IsFixedWidth, set the fixed flag to true + + C. if the tuned flag is set, add a boolean true to the font message as "tuned" + D. if the fixed flag is set, add a boolean true to the font message as "fixed" + E. add the font message to the list message as "family" + F. empty the font message + +5. Create a BFile from the path definition SERVER_FONT_LIST for Read/Write, creating the file if nonexistent and erasing any existing one +6. Flatten the list message to the created BFile object +7. Set the needs_update flag to false + + +status_t ScanDirectory(const char \*path) +----------------------------------------- + +ScanDirectory is where the brunt of the work of the FontServer is done: scan the directory of all fonts which can be loaded. + +1. Make a BDirectory object pointer at the path parameter. If the init code is not B_OK, return it. +2. Enter a while() loop, iterating through each entry in the given directory, executing as follows: + + a. Ensure that the entry is not '.' or '..' + b. Call FT_New_Face on the entry's full path + c. If a valid FT_Face is returned, iterate through to see if there are any supported character mappings in the current entry. + d. If there are no supported character mappings, dump the supported mappings to debug output, call FT_Done_Face(), and continue to the next entry + e. See if the entry's family has been added to the family list. If it hasn't, create one and add it. + f. Check to see if the font's style has been added to its family. If so, call FT_Done_Face, and continue to the next entry + g. If the style has not been added, create a new SFont for that family and face, increment the font count, and continue to the next entry. + +3. set the needs_update flag to true +4. Return B_OK + +Supported character mappings are Windows and Apple Unicode, Windows +symbol, and Apple Roman character mappings, in order of preference +from first to last. + +FontStyle \*GetFont(font_family family, font_style face) +-------------------------------------------------------- + +Returns an FontStyle object for the specified family and style or NULL +if not found. + +1. Call \_FindFamily() for the given family +2. If non-NULL, call its FindStyle() method +3. Return the result + +FontInstance \*GetInstance(font_family family, font_style face, int16 size, int16 rotation, int16 shear) +-------------------------------------------------------------------------------------------------------- + +Returns a usable instance of a specified font object with specified +properties. + + +1. Duplicates and performs the code found in GetFont +2. Assuming that the FontStyle object is non-NULL, it calls its GetInstance method and returns the result. + + +int32 CountFamilies(void) +------------------------- + +Returns the number of valid font families available to the system. + + +1. Return the number of items in the family list + + +status_t IsInitialized(void) +---------------------------- + +Returns the initialization status variable + + +int32 CountStyles(font_family family) +------------------------------------- + +Returns the number of styles available for a given font family. + + +1. Call \_FindFamily() to get the appropriate font family +2. If non-NULL, call its return the result of its CountStyles method + +FontStyle \*GetStyle(font_family family, font_style style) +---------------------------------------------------------- + +Gets the FontStyle object of the family, style, and flags. + +1. Call \_FindFamily() to get the appropriate font family +2. If non-NULL, call the family's GetStyle method on the font_style parameter and return the result +3. If family is NULL, return NULL + +void RemoveFamily(const char \*family) +-------------------------------------- + +Removes a font family from the family list + +1. Look up font family in the family list via \_FindFamily() +2. If it exists, delete it + +FontFamily \*_FindFamily(const char \*name) +------------------------------------------- + +Looks up a FontFamily object based on its family name. Returns NULL if not found. + +1. Call the family list's find() method. +2. Return the appropriate FontFamily object or NULL if not found. + +ServerFont \*GetSystemPlain(void), ServerFont \*GetSystemBold(void), ServerFont \*GetSystemFixed(void) +------------------------------------------------------------------------------------------------------ + +These return a copy of a pointer to the system-wide ServerFont objects +which represent the appropriate system font settings. It is the +responsibility of the caller to delete the object returned. NULL is +returned if no setting has been set for a particular system font. + + +bool SetSystemPlain(const char \*family, const char \*style, float size) +------------------------------------------------------------------------ + +bool SetSystemBold(const char \*family, const char \*style, float size) +----------------------------------------------------------------------- + +bool SetSystemFixed(const char \*family, const char \*style, float size) +------------------------------------------------------------------------ + + +The system fonts settings may be set via these calls by specifying the +family, style, and size. They return true if everything worked out ok +and false if not. Settings are not changed if false is returned. + +1. Call \_FindFamily on the family parameter. if NULL, return false +2. Call the family's GetStyle member. if NULL, return false +3. if the appropriate system font pointer is non-NULL, delete it +4. call the style's Instantiate member with the size parameter + + +void RemoveUnusedFamilies(void) +------------------------------- + +The purpose of this function is to allow for a complete rescan of the +fonts in the appropriate directories. + + +1. Iterate through the family list + + A. Get a family + B. if it has no dependents, remove it from the list and delete it + +2. Set the needs_update flag to true + + +bool FontsNeedUpdated(void) +--------------------------- + +Returns the value of the needs_update flag diff --git a/docs/develop/servers/app_server/FontStyle.htm b/docs/develop/servers/app_server/FontStyle.htm deleted file mode 100644 index 8d8a4ab69d..0000000000 --- a/docs/develop/servers/app_server/FontStyle.htm +++ /dev/null @@ -1,164 +0,0 @@ - - -FontStyle.htm - - - -
-

FontStyle class : public SharedObject

-


-

-

FontStyle objects represent a font's look, such as bold, italics, etc.

-


-
-


-

-

Type Definitions

-


-typedef struct CachedFaceRec_

-

{

-

BString file_path;

-

uint32 face_index;

-

} CachedFaceRec, *CachedFace;

-


-A record used in FreeType caching.

-


-
-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

FontStyle(const char *filepath, FT_Face face)

-
-

~FontStyle(void)

-
-

ServerFont *Instantiate(float size, float rotation=0.0, float shear=90.0)

-
-

bool IsFixedWidth(void)

-
-

bool IsScalable(void)

-
-

bool HasKerning(void)

-
-

bool HasTuned(void)

-
-

uint16 GlyphCount(void)

-
-

uint16 CharMapCount(void)

-
-

const char *Style(void)

-
-

FontFamily *Family(void)

-
-

FT_Face GetFace(void)

-
-

const char *GetPath(void)

-
-

int16 ConvertToUni code(uint16 c)

-
-


-
-
-


-

-

FontStyle(const char *filepath, FT_Face face)

-


-1) set name from face

-

2) create a CachedFaceRec object and generate the handle as being the memory address converted to an integer. Assign the path from the parameter.

-

3) set the path from the parameter

-

4) set family to NULL

-

5) create the instance list

-

6) check to see if face object has ready-made strikes and set IsTuned flags as appropriate

-

7) set fixed-width, kerning, and scalable flags as appropriate, based on face data

-

8) get and assign glyph and charmap count

-

9) set bounds to an invalid rectangle

-


-
-~FontStyle(void)

-


-1) delete all pointer objects

-

2) empty instance list, delete all attached instances, and delete the list

-


-
-ServerFont *Instantiate(float size, float rotation=0.0, float shear=90.0)

-


-Retrieves a specific instance of the font style, based on the size, rotation, and shear values

-


-1) create a new ServerFont object

-

2) add the new object to the instance list and return it

-


-
-bool IsFixedWidth(void)

-

bool IsScalable(void)

-

bool HasKerning(void)

-

bool HasTuned(void)

-

uint16 GlyphCount(void)

-

uint16 CharMapCount(void)

-

const char *GetPath(void)

-

FT_Face GetFace(void)

-


-These merely return the appropriate flags/values which are assigned values in the constructor.

-


-
-const char *Style(void)

-


-Returns the string value for the particular style.

-


-
-FontFamily *Family(void)

-


-Returns the pointer to the FontStyle object's family. Do NOT delete this pointer.

-


-
-int16 ConvertToUnicode(uint16 c)

-


-Converts a character code to a UTF-8 string

-


-1) Look up the face from the cache manager

-

2) Call FT_Get_Char_Index for the particular character code and return the value

-
-
-
- - diff --git a/docs/develop/servers/app_server/Layer.htm b/docs/develop/servers/app_server/Layer.htm deleted file mode 100644 index 97b3e5f426..0000000000 --- a/docs/develop/servers/app_server/Layer.htm +++ /dev/null @@ -1,389 +0,0 @@ - - -Layer.htm - - - -
-

Layer class

-


-

-

The Layer class is responsible for working with invalid regions and serves as the shadow class for BViews.

-


-


- -Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Layer(BRect frame, const char *name, int32 resize, int32 flags, ServerWindow *win)

-
-

~Layer(void)

-
-

void AddChild(Layer *child, Layer *before=NULL, bool rebuild=true)

-
-

RemoveChild(Layer *child, bool rebuild=true)

-
-

void RemoveSelf(bool rebuild=true)

-
-

void Invalidate(BRect r)

-
-

void Invalidate(BRegion *region)

-
-

BRect Frame(void)

-
-

BRect Bounds(void)

-
-

void MoveBy(BPoint pt)

-
-

void MoveBy(float x, float y)

-
-

void ResizeBy(BPoint pt)

-
-

void ResizeBy(float x, float y)

-
-

int32 CountChildren(void)

-
-

bool IsDirty(void)

-
-

BRect ConvertToTop(const BRect &r)

-
-

BRegion ConvertToTop(const BRegion &r)

-
-

BRect ConvertFromTop(const BRect &r)

-
-

BRegion ConvertFromTop(const BRegion &r)

-
-

BRect ConvertToParent(const BRect &r)

-
-

BRegion ConvertToParent(const BRegion &r)

-
-

BRect ConvertFromParent(const BRect &r)

-
-

BRegion ConvertFromParent(const BRegion &r)

-
-

void RebuildRegions(bool recursive=false)

-
-

void MakeTopChild(void)

-
-

void MakeBottomChild(void)

-
-

void RequestDraw(const BRect &r)

-
-

Layer *FindLayer(int32 token)

-
-

Layer *GetChildAt(BPoint pt, bool recursive=false)

-
-

PortLink *GetLink(void)

-
-


-
-Global Functions

-


-If there are any global functions associated with the class, they are listed here.

-


-
-


-

-

Layer(BRect frame, const char *name, int32 resize, int32 flags, ServerWindow *win)

-


-1) acquire a new layer token

-

2) validate (and fix, if necessary) parameters and assign to member objects

-

3) initalize relation pointers to NULL

-

4) set level to -1

-

5) set invalid region to NULL

-

6) set full and visible regions to bounds

-

7) set child count to 0

-

8) get ServerWindow's window port and create a PortLink pointed at it

-


-
-~Layer(void)

-


-1) if parent is non-NULL, call RemoveSelf()

-

2) if topchild is non-NULL, iterate through children and delete them.

-

3) delete invalid, full, and visible regions if non-NULL

-

4) delete the internal PortLink

-


-
-void AddChild(Layer *child, Layer *before=NULL, bool rebuild=true)

-


-Function which corresponds to BView::AddChild

-


-1) if child->parent is non-NULL, spew an error to stderr and return

-

2) set child->parent to this

-


- if before == NULL:

-

A) if topchild is non-NULL, set child->uppersibling to child

-

B) set child->lowersibling to topchild

-

C) if topchild is NULL, set bottomchild to child

-

D) set topchild to child

-


-if before != NULL:

-

A) if before->upper is non-NULL, set child->upper to before->upper

-

B) set before->upper to child

-

C) set child->lower to before

-

D) if child->upper is non-NULL, set child->upper->lower to child

-

E) increment child's level

-

3) increment the child count

-

4) if rebuild flag is true, call RebuildRegions

-


-
-RemoveChild(Layer *child, bool rebuild=true)

-


-Function which corresponds to BView::RemoveChild

-


-1) if child's parent != this, spew an error to stderr and return

-

2) set child's parent to NULL

-

3) set child's level to -1

-

4) if top child matches child, set top child to child's lower sibling

-

5) if bottom child matches child, set bottom child to child's upper sibilng

-

6) if child->uppersibling is non-NULL, set its lowersibling to the child's lowersibling

-

7) if child->lowersibling is non-NULL, set its uppersibling to the child's uppersibling

-

8) decrement child count

-

9) call RebuildRegions

-


-
-void RemoveSelf(bool rebuild=true)

-


-Function which corresponds to BView::RemoveSelf

-


-1) if parent is NULL, spew an error to stderr and return

-

2) call parent->RemoveChild(this)

-


-
-void Invalidate(BRect r)

-

void Invalidate(BRegion *region)

-


-Marks the area passed to the function as needing to be redrawn

-


-1) if parent is NULL, return

-

2) if the passed area intersects the layer's frame, add it to the invalid region, creating a new invalid object if necessary.

-

3) Iterate through all child layers, calling child->Invalidate() on the area converted from the parent

-


-
-BRect Frame(void)

-

BRect Bounds(void)

-


-Frame() returns the layer's frame in its parent coordinates. Bounds() returns the frame offset to (0,0).

-


-
-void MoveBy(BPoint pt)

-

void MoveBy(float x, float y)

-


-Moves the layer in its parent's coordinate space by the specified amount

-


-1) offset the frame by the specified amount

-

2) if parent is non-NULL, call parent->RebuildRegions()

-


-
-void ResizeBy(BPoint pt)

-

void ResizeBy(float x, float y)

-


-Resizes the layer by the specified amount and all children as appropriate.

-


-1) resize the frame by the specified amount

-

2) iterate through all children, checking the resize flags to see whether each should be resized and calling child->ResizeBy() by the appropriate amount if it is necessary.

-


-
-int32 CountChildren(void)

-


-Returns the number of children owned directly by the layer - grandchildren not included and some assembly required. Instructions are written in Yiddish.

-


-
-bool IsDirty(void)

-


-Returns true if the layer needs redrawn (if invalid region is non-NULL).

-


-
-BRect ConvertToTop(const BRect &r)

-

BRegion ConvertToTop(const BRegion &r)

-


-Converts the given data to the coordinates of the root layer in the layer tree.

-


-1) if parent is non-NULL, return the data.

-

2) if parent is NULL, call this: return (parent->ConvertToTop( data_offset_by_frame.left_top ) )

-


-
-BRect ConvertFromTop(const BRect &r)

-

BRegion ConvertFromTop(const BRegion &r)

-


-Converts the given data from the coordinates of the root layer in the layer tree.

-


-1) if parent is non-NULL, return the layer's frame

-

2) if parent is NULL, call this: return (parent->ConvertFromTop( data_offset_by_frame.left_and_top * -1 ) )

-


-
-BRect ConvertToParent(const BRect &r)

-

BRegion ConvertToParent(const BRegion &r)

-


-Converts the given data to the coordinates of the parent layer

-


-1) return the data offset by the layer's frame's top left point, i.e. frame.LeftTop()

-


-
-BRect ConvertFromParent(const BRect &r)

-

BRegion ConvertFromParent(const BRegion &r)

-


-Converts the given data from the coordinates of the parent layer

-


-1) operates exactly like ConvertToParent, except that the offset values are multiplied by -1

-


-
-void RebuildRegions(bool recursive=false)

-


-Rebuilds the visible and invalid layers based on the layer hierarchy. Used to update the regions after a call to remove or add a child layer is made or when a layer is hidden or shown.

-


-1) get the frame

-

2) set full and visible regions to frame

-

3) iterate through each child and exclude its full region from the visible region if the child is visible.

-

4) iterate through each lowersibling and exclude its full region from the visible region if the it is visible and it intersects the layer's frame.

-


-
-void MakeTopChild(void)

-


-Makes the layer the top child owned by its parent. Note that the top child is "behind" other children on the screen.

-


-1) if parent is NULL, spew an error to stderr and return

-

2) if parent's top child equals this, return without doing anything

-

3) if lowersibling and uppersibling are both NULL, return without doing anything

-

4) save pointer to parent layer to a temporary variable

-

5) call RemoveSelf and then the former parent's AddChild

-


-
-void MakeBottomChild(void)

-


-Makes the layer the bottom child owned by its parent. Note that the top child is "in front of" other children on the screen.

-


-1) if parent is NULL, spew an error to stderr and return

-

2) if parent's bottom child equals this, return without doing anything

-

3) if lowersibling and uppersibling are both NULL, return without doing anything

-

4) save pointer to parent layer to a temporary variable

-

5) call RemoveSelf() with rebuild set to false

-

6) call former parent's AddChild (rebuild is false), setting the before parameter to the former parent's bottomchild

-

7) save lowersibling to a temporary variable

-

8) call lowersibling->RemoveSelf() with no rebuild

-

9) call the parent's AddChild() with the before set to this and rebuild set to true

-


-
-void RequestDraw(const BRect &r)

-


-Requests that the layer be drawn on screen. The rectangle passed is in the layer's own coordinates.

-


-1) if invalid is NULL, return

-

2) set the PortLink opcode to B_DRAW

-

3) create a BMessage(B_DRAW) and attach all invalid rectangles to it

-

4) attach the view token to the message

-

4) flatten the message to a buffer, attach it to the PortLink, and Flush() it.

-

5) recurse through each child and call its RequestDraw() function if it intersects the child's frame

-


-
-Layer *FindLayer(int32 token)

-


-Finds a child layer given an identifying token

-


-1) iterate through children and check tokens. Return a match if found.

-

2) iterate through children, calling its FindLayer function, return any non-NULL results

-

3) return NULL - we got this far, so there is no match

-


-
-Layer *GetChildAt(BPoint pt, bool recursive=false)

-


-Gets the child at a given point. if recursive is true, all layers under the current one in the tree are searched. if the point is contained by the current layer's frame and no child is found, this function returns the current layer. if the point is outside the current layer's frame, it returns NULL

-


-1) if frame does not contain the point, return NULL -

-

if recursive is true:

-

A) start at the *bottom* child and iterate upward.

-

B) if the child has children, call the child's GetChildAt with the point converted to the child's coordinate space, returning any non-NULL results

-

C) if the child is hidden, continue to the next iteration

-

D) if the child's frame contains the point, return the child

-

E) if none of the children contain the point, return this

-


-if recursive is false:

-

A) start at the *bottom* child and iterate upward.

-

B) if the child is hidden, continue to the next iteration

-

C) if the child's frame contains the point, return the child

-

D) if none of the children contain the point, return this

-


-
-PortLink *GetLink(void)

-


-Returns the layer's internal PortLink object so a message can be sent to the Layer's window.

-
-
-
- - diff --git a/docs/develop/servers/app_server/Layer.rst b/docs/develop/servers/app_server/Layer.rst new file mode 100644 index 0000000000..287f2204ed --- /dev/null +++ b/docs/develop/servers/app_server/Layer.rst @@ -0,0 +1,283 @@ +Layer class +########### + +The Layer class is responsible for working with invalid regions and +serves as the shadow class for BViews. + +Member Functions +================ + +Layer(BRect frame, const char \*name, int32 resize, int32 flags, ServerWindow \*win) +------------------------------------------------------------------------------------ + + +1. acquire a new layer token +2. validate (and fix, if necessary) parameters and assign to member objects +3. initalize relation pointers to NULL +4. set level to -1 +5. set invalid region to NULL +6. set full and visible regions to bounds +7. set child count to 0 +8. get ServerWindow's window port and create a PortLink pointed at it + + +~Layer(void) +------------ + +1. if parent is non-NULL, call RemoveSelf() +2. if topchild is non-NULL, iterate through children and delete them. +3. delete invalid, full, and visible regions if non-NULL +4. delete the internal PortLink + + +void AddChild(Layer \*child, Layer \*before=NULL, bool rebuild=true) +-------------------------------------------------------------------- + +Function which corresponds to BView::AddChild + + +1) if child->parent is non-NULL, spew an error to stderr and return +2) set child->parent to this + + a) if before == NULL: + + A) if topchild is non-NULL, set child->uppersibling to child + B) set child->lowersibling to topchild + C) if topchild is NULL, set bottomchild to child + D) set topchild to child + + b) if before != NULL: + + A) if before->upper is non-NULL, set child->upper to before->upper + B) set before->upper to child + C) set child->lower to before + D) if child->upper is non-NULL, set child->upper->lower to child + E) increment child's level + +3) increment the child count +4) if rebuild flag is true, call RebuildRegions + + +RemoveChild(Layer \*child, bool rebuild=true) +--------------------------------------------- + +Function which corresponds to BView::RemoveChild + + +1. if child's parent != this, spew an error to stderr and return +2. set child's parent to NULL +3. set child's level to -1 +4. if top child matches child, set top child to child's lower sibling +5. if bottom child matches child, set bottom child to child's upper sibilng +6. if child->uppersibling is non-NULL, set its lowersibling to the child's lowersibling +7. if child->lowersibling is non-NULL, set its uppersibling to the child's uppersibling +8. decrement child count +9. call RebuildRegions + +void RemoveSelf(bool rebuild=true) +---------------------------------- + +Function which corresponds to BView::RemoveSelf + + +1. if parent is NULL, spew an error to stderr and return +2. call parent->RemoveChild(this) + +void Invalidate(BRect r) +------------------------ + +void Invalidate(BRegion \*region) +--------------------------------- + + +Marks the area passed to the function as needing to be redrawn + +1) if parent is NULL, return +2) if the passed area intersects the layer's frame, add it to the + invalid region, creating a new invalid object if necessary. +3) Iterate through all child layers, calling child->Invalidate() on the + area converted from the parent + +BRect Frame(void), BRect Bounds(void) +------------------------------------- + +Frame() returns the layer's frame in its parent coordinates. Bounds() +returns the frame offset to (0,0). + +void MoveBy(BPoint pt), void MoveBy(float x, float y) +----------------------------------------------------- + +Moves the layer in its parent's coordinate space by the specified +amount + +1. offset the frame by the specified amount +2. if parent is non-NULL, call parent->RebuildRegions() + +void ResizeBy(BPoint pt), void ResizeBy(float x, float y) +--------------------------------------------------------- + +Resizes the layer by the specified amount and all children as +appropriate. + +1) resize the frame by the specified amount +2) iterate through all children, checking the resize flags to see + whether each should be resized and calling child->ResizeBy() by the + appropriate amount if it is necessary. + +int32 CountChildren(void) +------------------------- + +Returns the number of children owned directly by the layer - +grandchildren not included and some assembly required. Instructions +are written in Yiddish. + + +bool IsDirty(void) +------------------ + +Returns true if the layer needs redrawn (if invalid region is +non-NULL). + + +BRect ConvertToTop(const BRect &r), BRegion ConvertToTop(const BRegion &r) +-------------------------------------------------------------------------- + + +Converts the given data to the coordinates of the root layer in the +layer tree. + + +1) if parent is non-NULL, return the data. +2) if parent is NULL, call this: return (parent->ConvertToTop( + data_offset_by_frame.left_top ) ) + +BRect ConvertFromTop(const BRect &r), BRegion ConvertFromTop(const BRegion &r) +------------------------------------------------------------------------------ + +Converts the given data from the coordinates of the root layer in the +layer tree. + +1. if parent is non-NULL, return the layer's frame +2. if parent is NULL, call this: return (parent->ConvertFromTop( + data_offset_by_frame.left_and_top \* -1 ) ) + +BRect ConvertToParent(const BRect &r), BRegion ConvertToParent(const BRegion &r) + +Converts the given data to the coordinates of the parent layer + +1. return the data offset by the layer's frame's top left point, i.e. + frame.LeftTop() + +BRect ConvertFromParent(const BRect &r), BRegion ConvertFromParent(const BRegion &r) +------------------------------------------------------------------------------------ + +Converts the given data from the coordinates of the parent layer + +1. operates exactly like ConvertToParent, except that the offset + values are multiplied by -1 + +void RebuildRegions(bool recursive=false) +----------------------------------------- + +Rebuilds the visible and invalid layers based on the layer hierarchy. +Used to update the regions after a call to remove or add a child layer +is made or when a layer is hidden or shown. + + +1. get the frame +2. set full and visible regions to frame +3. iterate through each child and exclude its full region from the + visible region if the child is visible. +4. iterate through each lowersibling and exclude its full region from + the visible region if the it is visible and it intersects the layer's + frame. + +void MakeTopChild(void) +----------------------- + +Makes the layer the top child owned by its parent. Note that the top +child is "behind" other children on the screen. + + +1. if parent is NULL, spew an error to stderr and return +2. if parent's top child equals this, return without doing anything +3. if lowersibling and uppersibling are both NULL, return without doing anything +4. save pointer to parent layer to a temporary variable +5. call RemoveSelf and then the former parent's AddChild + +void MakeBottomChild(void) +-------------------------- + +Makes the layer the bottom child owned by its parent. Note that the +top child is "in front of" other children on the screen. + +1. if parent is NULL, spew an error to stderr and return +2. if parent's bottom child equals this, return without doing anything +3. if lowersibling and uppersibling are both NULL, return without doing anything +4. save pointer to parent layer to a temporary variable +5. call RemoveSelf() with rebuild set to false +6. call former parent's AddChild (rebuild is false), setting the before + parameter to the former parent's bottomchild +7. save lowersibling to a temporary variable +8. call lowersibling->RemoveSelf() with no rebuild +9. call the parent's AddChild() with the before set to this and rebuild set to true + +void RequestDraw(const BRect &r) +-------------------------------- + +Requests that the layer be drawn on screen. The rectangle passed is in +the layer's own coordinates. + +1. if invalid is NULL, return +2. set the PortLink opcode to B_DRAW +3. create a BMessage(B_DRAW) and attach all invalid rectangles to it +4. attach the view token to the message +5. flatten the message to a buffer, attach it to the PortLink, and Flush() it. +6. recurse through each child and call its RequestDraw() function if it + intersects the child's frame + +Layer \*FindLayer(int32 token) +------------------------------ + +Finds a child layer given an identifying token + + +1. iterate through children and check tokens. Return a match if found. +2. iterate through children, calling its FindLayer function, return any non-NULL results +3. return NULL - we got this far, so there is no match + +Layer \*GetChildAt(BPoint pt, bool recursive=false) +--------------------------------------------------- + +Gets the child at a given point. if recursive is true, all layers +under the current one in the tree are searched. if the point is +contained by the current layer's frame and no child is found, this +function returns the current layer. if the point is outside the +current layer's frame, it returns NULL + + +1. if frame does not contain the point, return NULL + +if recursive is true: + +A. start at the \*bottom\* child and iterate upward. +B. if the child has children, call the child's GetChildAt with the point + converted to the child's coordinate space, returning any non-NULL + results +C. if the child is hidden, continue to the next iteration +D. if the child's frame contains the point, return the child +E. if none of the children contain the point, return this + +if recursive is false: + +A. start at the \*bottom\* child and iterate upward. +B. if the child is hidden, continue to the next iteration +C. if the child's frame contains the point, return the child +D. if none of the children contain the point, return this + +PortLink \*GetLink(void) +------------------------ + +Returns the layer's internal PortLink object so a message can be sent +to the Layer's window. + diff --git a/docs/develop/servers/app_server/PatternHandler.htm b/docs/develop/servers/app_server/PatternHandler.htm deleted file mode 100644 index ead8019a56..0000000000 --- a/docs/develop/servers/app_server/PatternHandler.htm +++ /dev/null @@ -1,118 +0,0 @@ - - -PatternHandler.htm - - - -
-

PatternHandler class

-


-

-

PatternHandler provides an easy way to integrate pattern support into classes which require it, such as the DisplayDriver class.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - -
-

PatternHandler(void)

-
-

~PatternHandler(void)

-
-

void SetTarget(int8 *pattern)

-
-

void SetColors(RGBColor c1, RGBColor c2)

-
-

RGBColor GetColor(BPoint pt)

-
-

RGBColor GetColor(float x, float y)

-
-

bool GetValue(float x, float y)

-
-

bool GetValue(BPoint pt)

-
-


-
-Enumerated Types

-


-pattern_enum

-

{

-

uint64 type64

-

uint8 type8 [8]

-

}

-


-


-

-

PatternHandler()

-


-1) Initialize internal RGBColor variables to black and white, respectively.

-

2) Set internal pattern to B_SOLID_HIGH (all 1's)

-


-
-~PatternHandler()

-


-Empty

-


-
-void SetTarget(int8 *pattern)

-


-Updates the pattern handler's pattern. It copies the pattern passed to it, so it does NOT take responsibility for freeing any memory.

-


-1) cast the passed pointer in such a way to copy it as a uint64 to the pattern_enum.type64 member

-


-void SetColors(RGBColor c1, RGBColor c2)

-


-Sets the internal high and low colors for the pattern handler. These will be the colors returned when GetColor() is called.

-


-1) Assign c1 to high color and c2 to low color

-


-
-RGBColor GetColor(BPoint pt) -RGBColor GetColor (float x, float y)

-


-bool GetValue(BPoint pt) -bool GetValue (float x, float y)

-


-
GetColor returns the color in the pattern at the specified location. GetValue returns true for the high color and false for the low color.

-


-1) xpos = x % 8, ypos = y % 8 -2) value = pointer [ ypos ] & ( 1 << (7 - xpos) )

-

3) GetValue: return (value==0)?false:true

-

GetColor: return (value==0)?lowcolor:highcolor

-
-
-
- - diff --git a/docs/develop/servers/app_server/PatternHandler.rst b/docs/develop/servers/app_server/PatternHandler.rst new file mode 100644 index 0000000000..652fa25ae3 --- /dev/null +++ b/docs/develop/servers/app_server/PatternHandler.rst @@ -0,0 +1,65 @@ +PatternHandler class +#################### + +PatternHandler provides an easy way to integrate pattern support into +classes which require it, such as the DisplayDriver class. + + +Enumerated Types +================ + +pattern_enum +------------ + +- uint64 type64 +- uint8 type8 [8] + +Member Functions +================ + +PatternHandler() +---------------- + + +1. Initialize internal RGBColor variables to black and white, respectively. +2. Set internal pattern to B_SOLID_HIGH (all 1's) + +~PatternHandler() +----------------- + +Empty + + +void SetTarget(int8 \*pattern) +------------------------------ + +Updates the pattern handler's pattern. It copies the pattern passed to +it, so it does NOT take responsibility for freeing any memory. + + +1. cast the passed pointer in such a way to copy it as a uint64 to the + pattern_enum.type64 member + +void SetColors(RGBColor c1, RGBColor c2) +---------------------------------------- + +Sets the internal high and low colors for the pattern handler. These +will be the colors returned when GetColor() is called. + + +1. Assign c1 to high color and c2 to low color + + +RGBColor GetColor(BPoint pt) RGBColor GetColor (float x, float y) +----------------------------------------------------------------- + +bool GetValue(BPoint pt) bool GetValue (float x, float y) +--------------------------------------------------------- + +GetColor returns the color in the pattern at the specified location. +GetValue returns true for the high color and false for the low color. + +1. xpos = x % 8, ypos = y % 8 2) value = pointer [ ypos ] & ( 1 << (7 - xpos) ) +2. GetValue: return (value==0)?false:true +3. GetColor: return (value==0)?lowcolor:highcolor + diff --git a/docs/develop/servers/app_server/RGBColor.htm b/docs/develop/servers/app_server/RGBColor.htm deleted file mode 100644 index a2bc3ef06f..0000000000 --- a/docs/develop/servers/app_server/RGBColor.htm +++ /dev/null @@ -1,189 +0,0 @@ - - -RGBColor.htm - - - -
-

RGBColor class

-


-

-

RGBColor objects provide a simplified interface to colors for the app_server, especially the DisplayDriver class

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

RGBColor(uint8 r, uint8 g, uint8 b, uint8 a=255)

-
-

RGBColor(rgb_color col)

-
-

RGBColor(uint16 color16)

-
-

RGBColor(uint8 color8)

-
-

RGBColor(const RGBColor &color)

-
-

RGBColor(void)

-
-

void PrintToStream(void)

-
-

uint8 GetColor8(void)

-
-

uint16 GetColor16(void)

-
-

rgb_color GetColor32(void)

-
-

void SetColor(uint8 r, uint8 g, uint8 b, uint8 a=255)

-
-

void SetColor(uint16 color16)

-
-

void SetColor(uint8 color 8)

-
-

void SetColor(rgb_color color)

-
-

void SetColor(const RGBColor &col)

-
-

Operators: =,==,!=

-
-

RGBColor MakeBlendColor( RGBColor c, float position)

-
-   -
-


-
-


-

-

RGBColor(uint8 r, uint8 g, uint8 b, uint8 a=255)

-

RGBColor(rgb_color col)

-

RGBColor(uint16 color16)

-

RGBColor(uint8 color8)

-

RGBColor(const RGBColor &color)

-

RGBColor(void)

-


-1) In all cases, extract the color data by calling SetColor. Void version sets to (0,0,0,0)

-


-
-void PrintToStream(void)

-


-Prints the color values of the color32 member via printf()

-


-uint8 GetColor8(void)

-

uint16 GetColor16(void)

-

rgb_color GetColor32(void)

-


-These are for obtaining space-specific versions of the color assigned to the object.

-


-1) In all cases, return the internal color storage members

-


-
-void SetColor(const RGBColor &color)

-


-Copy all internal members to the current object.

-


-
-
void SetColor(uint8 r, uint8 g, uint8 b, uint8 a=255)

-

void SetColor(rgb_color col)

-


-
1) Assign parameters to internal rgb_color

-

2) call SetRGBAColor15()

-

3) call SystemPalette::FindClosestColor()

-


-

-
void SetColor(uint16 color16)

-


-1) Assign parameter to internal uint16

-

2) call SetRGBAColor32()

-

3) call SystemPalette::FindClosestColor()

-


-
-
void SetColor(uint8 color8)

-


-
1) Assign parameter to internal uint8

-

2) Get the 32-bit value from the palette and assign it to the internal rgb_color

-

3) call SetRGBAColor16()

-


-
-
RGBColor & operator=(const RGBColor &from)

-


-Copy all data members over and return the value of this (return *this;)

-


-
bool operator==(const RGBColor &from)

-


-
Compare rgb_colors and if all members are equal, return true. Otherwise, return false.

-


-
bool operator!=(const RGBColor &from)

-


-Compare rgb_colors and if all are equal, return false. Otherwise, return true.

-


-RGBColor MakeBlendColor(RGBColor c, float position)

-


-Returns a color which is (position * 100) of the way from the current color to the one passed to it. This would be an easy way to generate color gradients, for example, but with more control.

-


-1) Clip position to the range 0<=position<=1

-

2) For each color component,

-

a) calculate the delta (delta=int16(c.component-thiscolor.component))

-

b) calculate the modifier (mod=thiscolor.component+(delta * position))

-

c) clip modifier to the range 0 <= modifier <= 255

-

d) assign modifier to the component (thiscolor.component=int8(mod))

-

3) return a new RGBColor constructed around the new color

-


-

-
-
-
- - diff --git a/docs/develop/servers/app_server/RGBColor.rst b/docs/develop/servers/app_server/RGBColor.rst new file mode 100644 index 0000000000..f074d28c08 --- /dev/null +++ b/docs/develop/servers/app_server/RGBColor.rst @@ -0,0 +1,117 @@ +RGBColor class +############## + +RGBColor objects provide a simplified interface to colors for the +app_server, especially the DisplayDriver class + +Member Functions +================ + +RGBColor(uint8 r, uint8 g, uint8 b, uint8 a=255) +------------------------------------------------ + +RGBColor(rgb_color col) +----------------------- + +RGBColor(uint16 color16) +------------------------ + +RGBColor(uint8 color8) +---------------------- + +RGBColor(const RGBColor &color) +------------------------------- + +RGBColor(void) +-------------- + +In all cases, extract the color data by calling SetColor. Void version sets to (0,0,0,0) + +void PrintToStream(void) +------------------------ + +Prints the color values of the color32 member via printf() + +uint8 GetColor8(void) +--------------------- + +uint16 GetColor16(void) +----------------------- + +rgb_color GetColor32(void) +-------------------------- + + +These are for obtaining space-specific versions of the color assigned +to the object. + + +1) In all cases, return the internal color storage members + + +void SetColor(const RGBColor &color) +------------------------------------ + +Copy all internal members to the current object. + +void SetColor(uint8 r, uint8 g, uint8 b, uint8 a=255) +----------------------------------------------------- + +void SetColor(rgb_color col) +---------------------------- + +1. Assign parameters to internal rgb_color +2. call SetRGBAColor15() +3. call SystemPalette::FindClosestColor() + +void SetColor(uint16 color16) +----------------------------- + +1. Assign parameter to internal uint16 +2. call SetRGBAColor32() +3. call SystemPalette::FindClosestColor() + +void SetColor(uint8 color8) +--------------------------- + +1. Assign parameter to internal uint8 +2. Get the 32-bit value from the palette and assign it to the internal rgb_color +3. call SetRGBAColor16() + +RGBColor & operator=(const RGBColor &from) +------------------------------------------ + +Copy all data members over and return the value of this (return \*this;) + +bool operator==(const RGBColor &from) +------------------------------------- + +Compare rgb_colors and if all members are equal, return true. Otherwise, +return false. + +bool operator!=(const RGBColor &from) +------------------------------------- + + +Compare rgb_colors and if all are equal, return false. Otherwise, +return true. + + +RGBColor MakeBlendColor(RGBColor c, float position) +--------------------------------------------------- + +Returns a color which is (position \* 100) of the way from the current +color to the one passed to it. This would be an easy way to generate +color gradients, for example, but with more control. + + +1) Clip position to the range 0<=position<=1 +2) For each color component, + + a) calculate the delta (delta=int16(c.component-thiscolor.component)) + b) calculate the modifier (mod=thiscolor.component+(delta \* position)) + c) clip modifier to the range 0 <= modifier <= 255 + d) assign modifier to the component (thiscolor.component=int8(mod)) + +3) return a new RGBColor constructed around the new color + diff --git a/docs/develop/servers/app_server/ServerApp.htm b/docs/develop/servers/app_server/ServerApp.htm deleted file mode 100644 index 4099495d7d..0000000000 --- a/docs/develop/servers/app_server/ServerApp.htm +++ /dev/null @@ -1,330 +0,0 @@ - - -ServerApp.htm - - - -
-

ServerApp class

-


-

-

ServerApps are the server-side counterpart to BApplications. They monitor for messages for the BApplication, create BWindows and BBitmaps, and provide a channel for the app_server to send messages to a user application without having a window.

-


-
-


-

-

Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - -
-

ServerApp(port_id sendport, port_id rcvport, const char *signature, thread_id thread_bapp)

-
-

~ServerApp(void)

-
-

bool Run(void)

-
-

static int32 MonitorApp(void *data)

-
-

void Lock(void)

-
-

void Unlock(void)

-
-

bool IsLocked(void)

-
-

void WindowBroadcast(int32 code)

-
-

bool IsActive(void)

-
-

bool PingTarget(void)

-
-

void DispatchMessage(int32 code, int8 *buffer)

-
-   -
-


-
-Global Functions

-


-
-


-

-

ServerApp(port_id sendport, port_id rcvport, const char *sig, thread_id thread_bapp)

-


-1) Create the window list as empty

-

2) Save sendport, rcvport, sig, and thread_bapp to the respective ServerApp members

-

3) Set quit_app flag to false

-

4) Create the window list lock

-


-
-~ServerApp(void)

-


-1) Empty and delete window list and accompanying windows

-

2) Wait for the monitoring thread to exit

-

3) Call CursorManager::RemoveAppCursors(this)

-

4) Delete the window list lock

-

5) If monitoring thread still active, kill it (in case app is deleted without a quit message)

-


-
-bool Run(void)

-


-Run() simply makes a ServerApp start monitoring for messages from its BApplication, telling it to quit if there is a problem.

-


-1) Spawn the monitoring thread (which utilizes MonitorApp()) -2) If any error, tell the BApplication to quit, spit an error to stderr, and return false

-

3) Resume the monitoring thread

-

4) Return true

-


-
-static int32 MonitorApp(void *data)

-


-Thread function for monitoring for messages from the ServerApp's BApplication.

-


-1) Call port_buffer_size - which will block if the port is empty

-

2) Allocate a buffer on the heap if the port buffer size is greater than 0

-

3) Read the port

-

4) Pass specified messages to DispatchMessage() for processing, spitting out an error message to stderr if the message's code is unrecognized

-

5) Return from DispatchMessage() and free the message buffer if one was allocated

-

6) If the message code matches the B_QUIT_REQUESTED definition and the quit_app flag is true, fall out of the infinite message-monitoring loop. Otherwise continue to next iteration

-

7) Send a DELETE_APP message to the server's main message to force deleting of the ServerApp instance and exit

-


-
-
-bool IsActive(void)

-


-Used for determining whether the application is the active one. Simply returns the isactive flag.

-


-
-void PingTarget(void)

-


-PingTarget() is called only from the Picasso thread of the app_server in order to determine whether its respective BApplication still exists. BApplications have been known to crash from time to time without the common courtesy of notifying the server of its intentions. ;D

-


-1) Call get_thread_info() with the app's thread_id

-

2) if it returns anything but B_OK, return false. Otherwise, return true.

-


-
-void DispatchMessage(int32 code, int8 *buffer)

-


-DispatchMessage implements all the code necessary to respond to a given message sent to the ServerApp on its receiving message port. This allows for clearer and more manageable code.

-


-CREATE_WINDOW:

-


-Sent by a new BWindow object via synchronous PortLink messaging. Set up the corresponding ServerWindow and reply to the BWindow with the new port to which it will send future communications with the App Server.

-


-Attached Data:

-


-

-

- - - - - - - - - - - - - - - - - - - - - - - - - -
-

port_id reply_port

-
-

port to which the server is to reply in response to the current message

-
-

BRect wframe

-
-

frame of the requesting BWindow

-
-

uint32 wflags

-
-

flag data of the requesting BWindow

-
-

port_id win_port

-
-

receiver port of the requesting BWindow

-
-

uint32 workspaces

-
-

workspaces on which the BWindow is to appear

-
-

const char *title

-
-

title of the requesting BWindow

-
-


-

-


-1) Get all attached data

-

2) Acquire the window list lock

-

3) Allocate a ServerWindow object and add it to the list

-

4) Release window list lock

-

5) Send the message SET_SERVER_PORT (with the ServerWindow's receiver port attached to the reply port

-


-
-DELETE_APP:

-


-Sent by a ServerWindow when told to quit. It is identified by the unique ID assigned to its thread.

-


-Attached Data:

-


-

-

- - - - - -
-

thread_id win_thread

-
-

Thread id of the ServerWindow sending this message

-
-


-

-


-1) Get window's thread_id

-

2) Acquire window list lock

-

3) Iterate through the window list, searching for the ServerWindow object with the sent thread_id

-

4) Remove the object from the list and delete it

-

5) Release window list lock

-


-
-SET_CURSOR_DATA:

-


-Received from the ServerApp's BApplication when SetCursor(const void *) is called.

-


-

-

Attached Data:

-


-

-

- - - - - -
-

int8 cursor[68]

-
-

Cursor data in the format as defined in the BeBook

-
-


-

-


-1) Create a ServerCursor from the attached cursor data

-

2) Add the new ServerCursor to the CursorManager and then call CursorManager::SetCursor

-

-

-

SET_CURSOR_BCURSOR:

-


-Received from the ServerApp's BApplication when SetCursor(BCursor *, bool) is called.

-


-

-

Attached Data:

-


-

-

- - - - - -
-

int32 token

-
-

Token identifier of cursor in the BCursor class

-
-


-

-


-1) Get the attached token and call CursorManager::SetCursor(token)

-


-
-B_QUIT_REQUESTED:

-


-Received from the BApplication when quits, so set the quit flag and ask the server to delete the object

-


-Attached Data: None

-


-1) Set quit_app flag to true

-


-
-UPDATE_DECORATOR:

-


-Received from the poller thread when the window decorator for the system has changed.

-


-Attached Data: None

-


-1) Call WindowBroadcast(UPDATE_DECORATOR)

-


-
-void WindowBroadcast(int32 code)

-


-Similar to AppServer::Broadcast(), this sends a message to all ServerWindows which belong to the ServerApp.

-


-1) Acquire window list lock

-

2) Create a PortLink instance and set its message code to the passed parameter.

-

3) Iterate through the window list, targeting the PortLink instance to each ServerWindow's message port and calling Flush().

-

4) Release window list lock

-


-
-void Lock(void)

-

void Unlock(void)

-

bool IsLocked(void)

-


-These functions are used to regulate access to the ServerApp's data members. Lock() acquires the internal semaphore, Unlock() releases it, and IsLocked returns true only if the semaphore's value is positive.

-
-
-
- - diff --git a/docs/develop/servers/app_server/ServerApp.rst b/docs/develop/servers/app_server/ServerApp.rst new file mode 100644 index 0000000000..4a5efce1c1 --- /dev/null +++ b/docs/develop/servers/app_server/ServerApp.rst @@ -0,0 +1,226 @@ +ServerApp class +############### + +ServerApps are the server-side counterpart to BApplications. They +monitor for messages for the BApplication, create BWindows and BBitmaps, +and provide a channel for the app_server to send messages to a user +application without having a window. + +Member Functions +================ + +- ServerApp(port_id sendport, port_id rcvport, const char\*signature, thread_id thread_bapp) +- ~ServerApp(void) +- bool Run(void) +- static int32 MonitorApp(void \*data) +- void Lock(void) +- void Unlock(void) +- bool IsLocked(void) +- void WindowBroadcast(int32 code) +- bool IsActive(void) +- bool PingTarget(void) +- void DispatchMessage(int32 code, int8 \*buffer) + +ServerApp(port_id sendport, port_id rcvport, const char \*sig, thread_id thread_bapp) +------------------------------------------------------------------------------------- + +1. Create the window list as empty +2. Save sendport, rcvport, sig, and thread_bapp to the respective + ServerApp members +3. Set quit_app flag to false +4. Create the window list lock + +~ServerApp(void) +---------------- + +1. Empty and delete window list and accompanying windows +2. Wait for the monitoring thread to exit +3. Call CursorManager::RemoveAppCursors(this) +4. Delete the window list lock +5. If monitoring thread still active, kill it (in case app is deleted + without a quit message) + +bool Run(void) +-------------- + +Run() simply makes a ServerApp start monitoring for messages from its +BApplication, telling it to quit if there is a problem. + +1. Spawn the monitoring thread (which utilizes MonitorApp()) 2) If any + error, tell the BApplication to quit, spit an error to stderr, and + return false +2. Resume the monitoring thread +3. Return true + +static int32 MonitorApp(void \*data) +------------------------------------ + +Thread function for monitoring for messages from the ServerApp's +BApplication. + +1. Call port_buffer_size - which will block if the port is empty +2. Allocate a buffer on the heap if the port buffer size is greater than 0 +3. Read the port +4. Pass specified messages to DispatchMessage() for processing, spitting + out an error message to stderr if the message's code is unrecognized +5. Return from DispatchMessage() and free the message buffer if one was + allocated +6. If the message code matches the B_QUIT_REQUESTED definition and the + quit_app flag is true, fall out of the infinite message-monitoring loop. + Otherwise continue to next iteration +7. Send a DELETE_APP message to the server's main message to force + deleting of the ServerApp instance and exit + +bool IsActive(void) +------------------- + +Used for determining whether the application is the active one. Simply +returns the isactive flag. + +void PingTarget(void) +--------------------- + +PingTarget() is called only from the Picasso thread of the app_server +in order to determine whether its respective BApplication still +exists. BApplications have been known to crash from time to time +without the common courtesy of notifying the server of its intentions. +;D + +1. Call get_thread_info() with the app's thread_id +2. if it returns anything but B_OK, return false. Otherwise, return + true. + +void DispatchMessage(int32 code, int8 \*buffer) +----------------------------------------------- + +DispatchMessage implements all the code necessary to respond to a +given message sent to the ServerApp on its receiving message port. +This allows for clearer and more manageable code. + +CREATE_WINDOW +............. + +Sent by a new BWindow object via synchronous PortLink messaging. Set +up the corresponding ServerWindow and reply to the BWindow with the +new port to which it will send future communications with the App +Server. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| port_id reply_port | port to which the server is to | +| | reply in response to the current | +| | message | ++-----------------------------------+-----------------------------------+ +| BRect wframe | frame of the requesting BWindow | ++-----------------------------------+-----------------------------------+ +| uint32 wflags | flag data of the requesting | +| | BWindow | ++-----------------------------------+-----------------------------------+ +| port_id win_port | receiver port of the requesting | +| | BWindow | ++-----------------------------------+-----------------------------------+ +| uint32 workspaces | workspaces on which the BWindow | +| | is to appear | ++-----------------------------------+-----------------------------------+ +| const char \*title | title of the requesting BWindow | ++-----------------------------------+-----------------------------------+ + +1. Get all attached data +2. Acquire the window list lock +3. Allocate a ServerWindow object and add it to the list +4. Release window list lock +5. Send the message SET_SERVER_PORT (with the ServerWindow's receiver + port attached to the reply port + +DELETE_APP +.......... + +Sent by a ServerWindow when told to quit. It is identified by the +unique ID assigned to its thread. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| thread_id win_thread | Thread id of the ServerWindow | +| | sending this message | ++-----------------------------------+-----------------------------------+ + +1. Get window's thread_id +2. Acquire window list lock +3. Iterate through the window list, searching for the ServerWindow + object with the sent thread_id +4. Remove the object from the list and delete it +5. Release window list lock + +SET_CURSOR_DATA +............... + +Received from the ServerApp's BApplication when SetCursor(const void\*) is called. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int8 cursor[68] | Cursor data in the format as | +| | defined in the BeBook | ++-----------------------------------+-----------------------------------+ + +1. Create a ServerCursor from the attached cursor data +2. Add the new ServerCursor to the CursorManager and then call + CursorManager::SetCursor + +SET_CURSOR_BCURSOR +.................. + +Received from the ServerApp's BApplication when SetCursor(BCursor \*, +bool) is called. + +Attached Data: + ++-----------------------------------+-----------------------------------+ +| int32 token | Token identifier of cursor in the | +| | BCursor class | ++-----------------------------------+-----------------------------------+ + +1) Get the attached token and call CursorManager::SetCursor(token) + +B_QUIT_REQUESTED +................ + +Received from the BApplication when quits, so set the quit flag and +ask the server to delete the object + +Attached Data: None + + +1) Set quit_app flag to true + +UPDATE_DECORATOR +................ + +Received from the poller thread when the window decorator for the +system has changed. + +Attached Data: None + +1) Call WindowBroadcast(UPDATE_DECORATOR) + +void WindowBroadcast(int32 code) +-------------------------------- + +Similar to AppServer::Broadcast(), this sends a message to all +ServerWindows which belong to the ServerApp. + +1) Acquire window list lock +2) Create a PortLink instance and set its message code to the passed + parameter. +3) Iterate through the window list, targeting the PortLink instance to + each ServerWindow's message port and calling Flush(). +4) Release window list lock + +void Lock(void), void Unlock(void), bool IsLocked(void) +------------------------------------------------------- + +These functions are used to regulate access to the ServerApp's data +members. Lock() acquires the internal semaphore, Unlock() releases it, +and IsLocked returns true only if the semaphore's value is positive. diff --git a/docs/develop/servers/app_server/ServerBitmap.htm b/docs/develop/servers/app_server/ServerBitmap.htm deleted file mode 100644 index d8c810d492..0000000000 --- a/docs/develop/servers/app_server/ServerBitmap.htm +++ /dev/null @@ -1,119 +0,0 @@ - - -ServerBitmap.htm - - - -
-

ServerBitmap class

-


-

-

ServerBitmaps are the server side counterpart to BBitmap. Note that they are not allocated like other objects - the BitmapManager handles all allocation and deletion tasks.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - -
-

ServerBitmap(BRect r, color_space cspace, int32 flags, int32 bytesperrow=-1, screen_id screen=B_MAIN_SCREEN_ID)

-
-

void _HandleSpace(color_space cs, int32 bytesperline=-1)

-
-

~ServerBitmap(void)

-
-

int32 BytesPerRow(void)

-
-

uint8 *Bits(void)

-
-

area_id Area(void)

-
-

uint32 BitsLength(void)

-
-

BRect Bounds(void)

-
-


-
-Global Functions

-


-If there are any global functions associated with the class, they are listed here.

-


-
-


-

-

ServerBitmap(BRect r, color_space cspace, int32 flags, int32 bytesperrow=-1, screen_id screen=B_MAIN_SCREEN_ID)

-


-1) Call _HandleSpace()

-

2) Call _HandleFlags()

-

3) Initialize remaining data members to parameters or safe values

-


-

-~ServerBitmap(void)

-


-Empty

-


-
-
uint8 *Bits(void)

-


-Returns the bitmap's buffer member

-


-
-area_id Area(void)

-


-Returns the bitmap's buffer member.

-


-
-uint32 BitsLength(void)

-


-Returns bytes_per_row * height

-


-
-BRect Bounds(void)

-


-returns BRect(width-1,height-1)

-


-
-int32 BytesPerRow(void)

-


-returns the bitmap's bytes_per_row member

-


-
-void _HandleSpace(color_space cs, int32 bytesperline=-1)

-


-Large function which essentially consists of a switch() of the available color spaces and assigns the bits per pixel and bytes per line values based on the color space. If bytesperline is -1, the default is used, otherwise it uses the specified value.

-
-
-
- - diff --git a/docs/develop/servers/app_server/ServerBitmap.rst b/docs/develop/servers/app_server/ServerBitmap.rst new file mode 100644 index 0000000000..3402ca2c8f --- /dev/null +++ b/docs/develop/servers/app_server/ServerBitmap.rst @@ -0,0 +1,55 @@ +ServerBitmap class +################## + +ServerBitmaps are the server side counterpart to BBitmap. Note that they +are not allocated like other objects - the BitmapManager handles all +allocation and deletion tasks. + +Member Functions +================ + +ServerBitmap(BRect r, color_space cspace, int32 flags, int32 bytesperrow=-1, screen_id screen=B_MAIN_SCREEN_ID) +--------------------------------------------------------------------------------------------------------------- + +1. Call \_HandleSpace() +2. Call \_HandleFlags() +3. Initialize remaining data members to parameters or safe values + +~ServerBitmap(void) +------------------- + +Empty + +uint8 \*Bits(void) +------------------ + +Returns the bitmap's buffer member + +area_id Area(void) +------------------ + +Returns the bitmap's buffer member. + +uint32 BitsLength(void) +----------------------- + +Returns bytes_per_row \* height + +BRect Bounds(void) +------------------ + +returns BRect(width-1,height-1) + +int32 BytesPerRow(void) +----------------------- + +returns the bitmap's bytes_per_row member + +void _HandleSpace(color_space cs, int32 bytesperline=-1) +--------------------------------------------------------- + +Large function which essentially consists of a switch() of the available +color spaces and assigns the bits per pixel and bytes per line values +based on the color space. If bytesperline is -1, the default is used, +otherwise it uses the specified value. + diff --git a/docs/develop/servers/app_server/SharedObject.htm b/docs/develop/servers/app_server/SharedObject.htm deleted file mode 100644 index 4e5783571a..0000000000 --- a/docs/develop/servers/app_server/SharedObject.htm +++ /dev/null @@ -1,86 +0,0 @@ - - -SharedObject.htm - - - -
-

SharedObjectf class

-


-The FontStyle class represents the particular style in a font family, such as Bold, Roman, etc. and provides information on an individual font, such as whether it has a fixed width, whether it is scalable etc. It also houses all instances of the individual style.

-


-


-

-

Member Functions

-


-

- - - - - - - - - - - - - -
-

SharedObject(void)

-
-

virtual SharedObject(void)

-
-

virtual void AddDependent(void)

-
-

virtual void RemoveDependent(void)

-
-

virtual bool HasDependents(void)

-
-   -
-


-
-


-

-

SharedObject(void)

-


-1) Sets dependent count to 0

-


-
-virtual ~SharedObject(void)

-


-1) Does nothing

-


-
-virtual void AddDependent(void)

-


-1) Increments dependent count

-


-
-virtual void RemoveDependent(void)

-


-1) Decrements dependent count if greater than 0

-


-
-virtual bool HasDependents(void)

-


-1) if dependent count > 0, return true. Otherwise, return false.

-
-
-
- - diff --git a/docs/develop/servers/app_server/SharedObject.rst b/docs/develop/servers/app_server/SharedObject.rst new file mode 100644 index 0000000000..4ae7bdf96f --- /dev/null +++ b/docs/develop/servers/app_server/SharedObject.rst @@ -0,0 +1,26 @@ +SharedObject class +################### + +Member Functions +---------------- + +SharedObject(void) + +1) Sets dependent count to 0 + +virtual ~SharedObject(void) + +1) Does nothing + +virtual void AddDependent(void) + +1) Increments dependent count + +virtual void RemoveDependent(void) + +1) Decrements dependent count if greater than 0 + +virtual bool HasDependents(void) + +1) if dependent count > 0, return true. Otherwise, return false. + diff --git a/docs/develop/servers/app_server/SystemPalette.htm b/docs/develop/servers/app_server/SystemPalette.htm deleted file mode 100644 index 2211b5df0a..0000000000 --- a/docs/develop/servers/app_server/SystemPalette.htm +++ /dev/null @@ -1,249 +0,0 @@ - - -SystemPalette.htm - - - -
-

SystemPalette class

-


-

-

This object does all the handling for system attribute colors and system palette management.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - -
-

SystemPalette(void)

-
-

~SystemPalette(void)

-
-

void SetPalette(uint8 index, RGBColor col)

-
-

void SetPalette(uint8 index, rgb_color col)

-
-

RGBColor GetPalette(uint8 index)

-
-

void SetGUIColor(color_which which, RGBColor col)

-
-

RGBColor GetGUIColor(color_which which)

-
-

color_set GetGUIColors(void)

-
-

void SetGUIColors(color_set cset)

-
-

void _GenerateSystemPalette(rgb_color *palette)

-
-

void _SetDefaultGUIColors(void)

-
-   -
-


-
-_ Denotes a protected function

-


-Structures

-


-color_set {

-

rgb_color panel_background

-

rgb_color panel_text

-

rgb_color document_background

-

rgb_color document_text

-

rgb_color control_background

-

rgb_color control_text

-

rgb_color control_border

-

rgb_color control_highlight

-

rgb_color tooltip_background

-

rgb_color tooltip_text

-

rgb_color menu_background

-

rgb_color menu_selected_background

-

rgb_color menu_text

-

rgb_color menu_selected_text

-

rgb_color menu_separator

-

rgb_color menu_triggers

-

}

-


-


-

-

SystemPalette(void)

-


-1) Allocate the rgb_color[256] palette on the heap and call _GenerateSystemPalette()

-

2) Initialize attribute variables to the defaults

-


-
-~SystemPalette(void)

-


-1) Free the palette array

-


-
-void SetPalette(uint8 index, RGBColor col)

-

void SetPalette(uint8 index, rgb_color col)

-


-Sets the said index to the passed color value.

-


-
-RGBColor GetPalette(uint8 index)

-


-Returns the color at said index in the palette.

-


-
-void SetGUIColor(color_which which, RGBColor col)

-

RGBColor GetGUIColor(color_which which)

-

color_set GetGUIColors(void)

-

void SetGUIColors(color_set cset)

-


-These tweak or return the system attribute colors, one at a time or all at once.

-


-
-protected: void _GenerateSystemPalette(rgb_color *palette)

-


-Sets the passed palette to the BeOS R5 system colors, which follows.

-

Grays:

-

0,0,0 -> 248,248,248 by increments of 8

-

Blues:

-

0,0,255

-

0,0,229

-

0,0,204

-

0,0,179

-

0,0,154

-

0,0,129

-

0,0,105

-

0,0,80

-

0,0,55

-

0,0,30

-

Reds: as per blues, but red values are 1 less

-

Greens: as per blues, but green values are 1 less

-

0,152,51

-

255,255,255

-


-The following sets use [255, 203, 152, 102, 51, 0] for the blue values, keeping the other colors the same:

-


-203,255, [value]

-

152,255, [value]

-

102,255, [value]

-

51,255, [value]

-

255,152, [value]

-


-0,102,255

-

0,102,203

-


-203,203, [value]

-

152,255, [value]

-

102,255, [value]

-

51,255, [value]

-

255,102, [value]

-


-0,102,152

-

0,102,102

-


-203,152, [value]

-

152,152, [value]

-

102,152, [value]

-

51,152, [value]

-


-230,134,0

-


-255,51, [value excepting 255]

-


-0,102,51

-

0,102,0

-


-203,102, [value]

-

152,102, [value]

-

102,102, [value]

-

51,102, [value]

-

255,0, [value excepting 0]

-


-255,175,19

-

0,51,255

-

0,51,203

-


-203,51, [value]

-

152,51, [value]

-

102,51, [value]

-

51,51, [value]

-


-255,203,102 -> 255,203,255, stepping in the [value] increments

-


-0,51, [value, starting at 152]

-

203,0, [value, excepting 0]

-


-255,227,70

-


-152,0, [value]

-

102,0, [value]

-

51,0, [value]

-


-255,203,51

-

255,203,0

-


-255,255, [values in reverse]

-


-
-protected: void _SetDefaultGUIColors(void)

-


-Sets the internal color_set to the defaults, which is the following:

-


-panel_background: 216,216, 216

-

panel_text: 0,0,0

-

document_background: 255,255,255

-

document_text: 0,0,0

-

control_background: 216,216,216

-

control_text: 0,0,0

-

control_border: 0,0,0

-

control_highlight: 0,0,255

-

tooltip_background:

-

tooltip_text: 0,0,0

-

menu_background: 216,216,216

-

menu_selected_background: 160,160,160

-

menu_text: 0,0,0

-

menu_selected_text: 0,0,0

-

menu_separator_high: 241,241,241

-

menu_separator_low: 186,186,186

-

menu_triggers: 0,0,0

-
-
-
- - diff --git a/docs/develop/servers/app_server/SystemPalette.rst b/docs/develop/servers/app_server/SystemPalette.rst new file mode 100644 index 0000000000..83149a6528 --- /dev/null +++ b/docs/develop/servers/app_server/SystemPalette.rst @@ -0,0 +1,231 @@ +SystemPalette class +################### + +This object does all the handling for system attribute colors and system +palette management. + +Member Functions +================ + +_ Denotes a protected function + +SystemPalette(void) +------------------- + +1. Allocate the rgb_color[256] palette on the heap and call _GenerateSystemPalette() +2. Initialize attribute variables to the defaults + +~SystemPalette(void) +-------------------- + +1) Free the palette array + +void SetPalette(uint8 index, RGBColor col), void SetPalette(uint8 index, rgb_color col) +--------------------------------------------------------------------------------------- + +Sets the said index to the passed color value. + +RGBColor GetPalette(uint8 index) +-------------------------------- + +Returns the color at said index in the palette. + +void SetGUIColor(color_which which, RGBColor col) +------------------------------------------------- + +RGBColor GetGUIColor(color_which which) +--------------------------------------- + +color_set GetGUIColors(void) +---------------------------- + +void SetGUIColors(color_set cset) +--------------------------------- + +These tweak or return the system attribute colors, one at a time or all at once. + +protected: void \_GenerateSystemPalette(rgb_color \*palette) +------------------------------------------------------------ + +Sets the passed palette to the BeOS R5 system colors, which follows. + +Grays: +...... + +0,0,0 -> 248,248,248 by increments of 8 + +Blues: +...... + +0,0,255 + +0,0,229 + +0,0,204 + +0,0,179 + +0,0,154 + +0,0,129 + +0,0,105 + +0,0,80 + +0,0,55 + +0,0,30 + +Reds: +..... + +as per blues, but red values are 1 less + +Greens: +....... + +as per blues, but green values are 1 less + +0,152,51 + +255,255,255 + +The following sets use [255, 203, 152, 102, 51, 0] for the blue values, +keeping the other colors the same: + +203,255, [value] + +152,255, [value] + +102,255, [value] + +51,255, [value] + +255,152, [value] + +0,102,255 + +0,102,203 + +203,203, [value] + +152,255, [value] + +102,255, [value] + +51,255, [value] + +255,102, [value] + +0,102,152 + +0,102,102 + +203,152, [value] + +152,152, [value] + +102,152, [value] + +51,152, [value] + +230,134,0 + +255,51, [value excepting 255] + +0,102,51 + +0,102,0 + +203,102, [value] + +152,102, [value] + +102,102, [value] + +51,102, [value] + +255,0, [value excepting 0] + +255,175,19 + +0,51,255 + +0,51,203 + +203,51, [value] + +152,51, [value] + +102,51, [value] + +51,51, [value] + +255,203,102 -> 255,203,255, stepping in the [value] increments + +0,51, [value, starting at 152] + +203,0, [value, excepting 0] + +255,227,70 + +152,0, [value] + +102,0, [value] + +51,0, [value] + +255,203,51 + +255,203,0 + +255,255, [values in reverse] + +protected: void _SetDefaultGUIColors(void) +------------------------------------------- + +Sets the internal color_set to the defaults, which is the following: + +- panel_background: 216,216, 216 +- panel_text: 0,0,0 +- document_background: 255,255,255 +- document_text: 0,0,0 +- control_background: 216,216,216 +- control_text: 0,0,0 +- control_border: 0,0,0 +- control_highlight: 0,0,255 +- tooltip_background: +- tooltip_text: 0,0,0 +- menu_background: 216,216,216 +- menu_selected_background: 160,160,160 +- menu_text: 0,0,0 +- menu_selected_text: 0,0,0 +- menu_separator_high: 241,241,241 +- menu_separator_low: 186,186,186 +- menu_triggers: 0,0,0 + +Structures +========== + +.. code-block:: cpp + + color_set { + rgb_color panel_background + rgb_color panel_text + rgb_color document_background + rgb_color document_text + rgb_color control_background + rgb_color control_text + rgb_color control_border + rgb_color control_highlight + rgb_color tooltip_background + rgb_color tooltip_text + rgb_color menu_background + rgb_color menu_selected_background + rgb_color menu_text + rgb_color menu_selected_text + rgb_color menu_separator + rgb_color menu_triggers + } + diff --git a/docs/develop/servers/app_server/TokenHandler.htm b/docs/develop/servers/app_server/TokenHandler.htm deleted file mode 100644 index ae7954b572..0000000000 --- a/docs/develop/servers/app_server/TokenHandler.htm +++ /dev/null @@ -1,135 +0,0 @@ - - -TokenHandler.htm - - - -
-

TokenHandler class

-


-This is a simple way to provide tokens for various reasons.

-


-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - -
-

TokenHandler(void)

-
-

~TokenHandler(void)

-
-

int32 GetToken(void)

-
-

void Reset(void)

-
-

void ExcludeValue(int32 value)

-
-

void ResetExcludes(void)

-
-

bool IsExclude(int32 value)

-
-   -
-   - -   -
-


-
-


-

-

TokenHandler(void)

-


-1) Initialize the index to -1

-

2) create the access semaphore

-

3) create the exclude list with no items

-


-
-~TokenHandler(void)

-


-1) delete the access lock

-

2) call ResetExcludes and delete the exclude list

-


-
-int32 GetToken(void)

-


-Returns a unique token which is not equal to any excluded values

-


-1) create a local variable to return the new token

-

2) acquire the access semaphore

-

3) Increment the internal index

-

4) while IsExclude(index) is true, increment the index

-

5) assign it to the local variable

-

6) release the access semaphore

-

7) return the local variable

-


-
-void Reset(void)

-


-1) acquire the access semaphore

-

2) set the internal index to -1

-

3) release the access semaphore

-


-
-void ExcludeValue(int32 value)

-


-1) acquire the access semaphore

-

2) if IsExclude(value) is false, add it to the exclude list

-

3) release the access semaphore

-


-
-void ResetExcludes(void)

-


-1) acquire the access semaphore

-

2) Iterate through the exclude list, removing and deleting each item

-

3) release the access semaphore

-


-
-bool IsExclude(int32 value)

-


-1) create a boolean match flag and set it to false

-

2) acquire the access semaphore

-

3) iterate through the exclude list and see if the value matches any in the list

-

4) If there is a match, set the match flag to true and exit the loop

-

5) release the access semaphore

-

6) return the match flag

-
-
-
- - diff --git a/docs/develop/servers/app_server/TokenHandler.rst b/docs/develop/servers/app_server/TokenHandler.rst new file mode 100644 index 0000000000..f2ae9b2481 --- /dev/null +++ b/docs/develop/servers/app_server/TokenHandler.rst @@ -0,0 +1,66 @@ +TokenHandler class +################## + +This is a simple way to provide tokens for various reasons. + +Member Functions +================ + +TokenHandler(void) +------------------ + +1. Initialize the index to -1 +2. create the access semaphore +3. create the exclude list with no items + +~TokenHandler(void) +------------------- + +1. delete the access lock +2. call ResetExcludes and delete the exclude list + +int32 GetToken(void) +-------------------- + +Returns a unique token which is not equal to any excluded values + +1. create a local variable to return the new token +2. acquire the access semaphore +3. Increment the internal index +4. while IsExclude(index) is true, increment the index +5. assign it to the local variable +6. release the access semaphore +7. return the local variable + +void Reset(void) +---------------- + +1. acquire the access semaphore +2. set the internal index to -1 +3. release the access semaphore + +void ExcludeValue(int32 value) +------------------------------ + +1. acquire the access semaphore +2. if IsExclude(value) is false, add it to the exclude list +3. release the access semaphore + +void ResetExcludes(void) +------------------------ + +1. acquire the access semaphore +2. Iterate through the exclude list, removing and deleting each item +3. release the access semaphore + +bool IsExclude(int32 value) +--------------------------- + +1. create a boolean match flag and set it to false +2. acquire the access semaphore +3. iterate through the exclude list and see if the value matches any in + the list +4. If there is a match, set the match flag to true and exit the loop +5. release the access semaphore +6. return the match flag + diff --git a/docs/develop/servers/app_server/WinBorder.htm b/docs/develop/servers/app_server/WinBorder.htm deleted file mode 100644 index b3d23c0c6b..0000000000 --- a/docs/develop/servers/app_server/WinBorder.htm +++ /dev/null @@ -1,423 +0,0 @@ - - -WinBorder.htm - - - -
-

WinBorder class : public Layer

-


-

-

WinBorder objects provide window management functionality and ensure that the border for each window is drawn.

-


-
-


-

-


-Member Functions

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

WinBorder(BRect r, const char *name, int32 resize, int32 flags, ServerWindow *win)

-
-

~WinBorder(void)

-
-

void RequestDraw(void)

-
-

void MoveBy(BPoint pt)

-
-

void MoveBy(float x, float y)

-
-

void ResizeBy(BPoint pt)

-
-

void ResizeBy(float x, float y)

-
-

void MouseDown(int8 *buffer)

-
-

void MouseUp(int8 *buffer)

-
-

void MouseMoved(int8 *buffer)

-
-

void UpdateDecorator(void)

-
-

void UpdateColors(void)

-
-

void UpdateFont(void)

-
-

void UpdateScreen(void)

-
-

void RebuildRegions(bool recursive=true)

-
-

void Activate(bool state)

-
-


-
-Global Functions

-


-bool is_moving_window(void)

-

void set_is_moving_window(bool state)

-

bool is_resizing_window(void)

-

void set_is_resizing_window(bool state)

-

void set_active_winborder(WinBorder *win)

-

WinBorder * get_active_winborder(void)

-


-Namespaces

-


-winborder_private {

-

bool is_moving_a_window

-

bool is_resizing_a_window

-

WinBorder *active_winborder

-

}

-


-


-

-

WinBorder(BRect r, const char *name, int32 resize, int32 flags, ServerWindow *win)

-


-1) Pass parameters to Layer constructor

-

2) Instantiate a decorator

-

3) Initialize visible and full regions via Decorator::GetFootprint()

-


-
-~WinBorder(void)

-


-1) Delete decorator instance

-


-
-void RequestDraw(void)

-


-Reimplements Layer::RequestDraw() because it has no corresponding BView

-


-1) if IsDirty()==false, return

-

2) Iterate through each BRect in the invalid region and call Decorator::Draw(BRect) for each invalid rectangle

-

3) Perform recursive child calls as in Layer::RequestDraw()

-


-
-void MoveBy(BPoint pt)

-

void MoveBy(float x, float y)

-


-Moves the WinBorder's position on screen - reimplements Layer::MoveBy()

-


-1) Call the decorator's MoveBy()

-

2) Call Layer::MoveBy()

-


-
-void ResizeBy(BPoint pt)

-

void ResizeBy(float x, float y)

-


-Resizes the WinBorder - reimplements Layer::MoveBy()

-


-1) Call the decorator's ResizeBy()

-

2) Call Layer::ResizeBy()

-


-
-void MouseDown(int8 *buffer)

-


-Figures out what to do with B_MOUSE_DOWN messages sent to the window's border.

-


-1) Extract data from the buffer

-

2) Call the decorator's Clicked() function

-

3) Feed return value to a switch() function (table below)

-

4) Call the ServerWindow's Activate() function

-


-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

CLICK_MOVETOBACK

-
-

call MoveToBack()

-
-

CLICK_MOVETOFRONT

-
-

call MoveToFront()

-
-

CLICK_CLOSE

-
-

1) call SetCloseButton(true)

-

2) call decorator->DrawClose

-
-

CLICK_ZOOM

-
-

1) call SetZoomButton(true)

-

2) call decorator->DrawZoom

-
-

CLICK_MINIMIZE

-
-

1) call SetMinimizeButton(true)

-

2) call decorator->DrawMinimize

-
-

CLICK_DRAG

-
-

1) call MoveToFront()

-

2) call set_is_win_moving(true)

-

3) Save the mouse position

-
-

CLICK_RESIZE

-
-

1) call MoveToFront()

-

2) call set_is_win_resizing(true)

-
-

CLICK_NONE

-
-

do nothing

-
-

default:

-
-

Spew an error to stderr and return

-
-


-
-
-void MouseUp(int8 *buffer)

-


-Figures out what to do with B_MOUSE_UP messages sent to the window's border.

-


-1) Extract data from the buffer

-

2) Call the decorator's Clicked() function

-

3) Feed return value to a switch() function (table below)

-

4) if is_resizing_window, call set_is_resizing_window(false)

-

5) if is_moving_window, call set_is_moving_window(false)

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

CLICK_MOVETOBACK

-
-

call MoveToBack()

-
-

CLICK_MOVETOFRONT

-
-

call MoveToFront()

-
-

CLICK_CLOSE

-
-

1) call SetCloseButton(false)

-

2) call decorator->DrawClose

-

3) send B_QUIT_REQUESTED to the target BWindow

-
-

CLICK_ZOOM

-
-

1) call SetZoomButton(false)

-

2) call decorator->DrawZoom

-

3) send B_ZOOM to the target BWindow

-
-

CLICK_MINIMIZE

-
-

1) call SetMinimizeButton(false)

-

2) call decorator->DrawMinimize

-

3) send B_MINIMIZE to the target BWindow

-
-

CLICK_DRAG

-
-

call set_is_win_moving(false)

-
-

CLICK_RESIZE

-
-

call set_is_win_resizing(false)

-
-

CLICK_NONE

-
-

do nothing

-
-

default:

-
-

Spew an error to stderr

-
-


-
-
-void MouseMoved(int8 *buffer)

-


-Figures out what to do with B_MOUSE_MOVED messages sent to the window's border.

-


-1) Extract data from the buffer

-

2) Call the decorator's Clicked() function

-

3) If not CLICK_CLOSE and decorator->GetClose is true, call SetClose(false) and DrawClose()

-

4) If not CLICK_ZOOM and decorator->GetZoom is true, call SetZoom(false) and DrawZoom()

-

5) If not CLICK_MINIMIZE and decorator->GetMinimize is true, call SetMinimize(false) and DrawMinimize()

-

6) if CLICK_RESIZE or its variants, call CursorManager::SetCursor() with the appropriate system cursor.

-

7) if is_moving_window() is true, calculate the amount the mouse has moved and call decorator->MoveBy() followed by Layer::MoveBy()

-

8) if is_resizing_window() is true, calculate the amount the mouse has moved and call decorator->ResizeBy() followed by Layer::ResizeBy()

-


-
-void UpdateDecorator(void)

-


-Hook function called by the WinBorder's ServerWindow when the decorator used is changed.

-


-1) Delete the current decorator

-

2) Call instantiate_decorator

-

3) Get the new decorator's footprint region and assign it to the full and visible regions

-

4) Call RebuildRegions and then RequestDraw

-


-
-void UpdateColors(void)

-


-Hook function called by the WinBorder's ServerWindow when system colors change

-


-1) Call the decorator's SetColors(), passing the SystemPalette's GetGUIColors() value

-


-
-void UpdateFont(void)

-


-Hook function called by the WinBorder's ServerWindow when system fonts change

-


-TODO: implementation details

-


-
-void UpdateScreen(void)

-


-Hook function called by the WinBorder's ServerWindow when screen attributes change

-


-1) Call the decorator's UpdateScreen and then RequestDraw

-


-
-void RebuildRegions(bool recursive=true)

-


-Reimplementation of Layer::RebuildRegions which changes it such that lower siblings are clipped to the footprint instead of the frame.

-


-
-void Activate(bool state)

-


-This function is never directly called except from within set_active_winborder. It exists to force redraw and set the internal state information to the proper values for when a window receives or loses focus.

-


-1) call the decorator's SetFocus(state)

-

2) set the internal is_active flag to state

-

3) iterate through each rectangle in the visible region and call the decorator's Draw on it.

-


-
-bool is_moving_window(void)

-

void set_is_moving_window(bool state)

-


-These two functions set and return the variable winborder_private::is_moving_a_window.

-


-
-bool is_resizing_window(void)

-

void set_is_resizing_window(bool state)

-


-These two functions set and return the variable winborder_private::is_resizing_a_window.

-


-
-void set_active_winborder(WinBorder *win)

-

WinBorder * get_active_winborder(void)

-


-These two functions set and return the variable winborder_private::active_winborder

-
-
-
- - diff --git a/docs/develop/servers/app_server/WinBorder.rst b/docs/develop/servers/app_server/WinBorder.rst new file mode 100644 index 0000000000..da426fbe33 --- /dev/null +++ b/docs/develop/servers/app_server/WinBorder.rst @@ -0,0 +1,236 @@ +WinBorder class : public Layer +############################## + +WinBorder objects provide window management functionality and ensure +that the border for each window is drawn. + +Member Functions +================ + +WinBorder(BRect r, const char \*name, int32 resize, int32 flags, ServerWindow \*win) +------------------------------------------------------------------------------------ + +1. Pass parameters to Layer constructor +2. Instantiate a decorator +3. Initialize visible and full regions via Decorator::GetFootprint() + +~WinBorder(void) +---------------- + +1. Delete decorator instance + +void RequestDraw(void) +---------------------- + +Reimplements Layer::RequestDraw() because it has no corresponding BView + +1. if IsDirty()==false, return +2. Iterate through each BRect in the invalid region and call Decorator::Draw(BRect) for each invalid rectangle +3. Perform recursive child calls as in Layer::RequestDraw() + +void MoveBy(BPoint pt), void MoveBy(float x, float y) +----------------------------------------------------- + +Moves the WinBorder's position on screen - reimplements Layer::MoveBy() + +1. Call the decorator's MoveBy() +2. Call Layer::MoveBy() + +void ResizeBy(BPoint pt), void ResizeBy(float x, float y) +--------------------------------------------------------- + +Resizes the WinBorder - reimplements Layer::MoveBy() + +1. Call the decorator's ResizeBy() +2. Call Layer::ResizeBy() + +void MouseDown(int8 \*buffer) +----------------------------- + +Figures out what to do with B_MOUSE_DOWN messages sent to the window's border. + +1. Extract data from the buffer +2. Call the decorator's Clicked() function +3. Feed return value to a switch() function (table below) +4. Call the ServerWindow's Activate() function + ++-----------------------------------+-----------------------------------+ +| CLICK_MOVETOBACK | call MoveToBack() | ++-----------------------------------+-----------------------------------+ +| CLICK_MOVETOFRONT | call MoveToFront() | ++-----------------------------------+-----------------------------------+ +| CLICK_CLOSE | 1) call SetCloseButton(true) | +| | | +| | 2) call decorator->DrawClose | ++-----------------------------------+-----------------------------------+ +| CLICK_ZOOM | 1) call SetZoomButton(true) | +| | | +| | 2) call decorator->DrawZoom | ++-----------------------------------+-----------------------------------+ +| CLICK_MINIMIZE | 1) call SetMinimizeButton(true) | +| | | +| | 2) call decorator->DrawMinimize | ++-----------------------------------+-----------------------------------+ +| CLICK_DRAG | 1) call MoveToFront() | +| | | +| | 2) call set_is_win_moving(true) | +| | | +| | 3) Save the mouse position | ++-----------------------------------+-----------------------------------+ +| CLICK_RESIZE | 1) call MoveToFront() | +| | | +| | 2) call set_is_win_resizing(true) | ++-----------------------------------+-----------------------------------+ +| CLICK_NONE | do nothing | ++-----------------------------------+-----------------------------------+ +| default: | Spew an error to stderr and | +| | return | ++-----------------------------------+-----------------------------------+ + +void MouseUp(int8 \*buffer) +--------------------------- + +Figures out what to do with B_MOUSE_UP messages sent to the window's border. + +1. Extract data from the buffer +2. Call the decorator's Clicked() function +3. Feed return value to a switch() function (table below) +4. if is_resizing_window, call set_is_resizing_window(false) +5. if is_moving_window, call set_is_moving_window(false) + ++-----------------------------------+-----------------------------------+ +| CLICK_MOVETOBACK | call MoveToBack() | ++-----------------------------------+-----------------------------------+ +| CLICK_MOVETOFRONT | call MoveToFront() | ++-----------------------------------+-----------------------------------+ +| CLICK_CLOSE | 1) call SetCloseButton(false) | +| | | +| | 2) call decorator->DrawClose | +| | | +| | 3) send B_QUIT_REQUESTED to the | +| | target BWindow | ++-----------------------------------+-----------------------------------+ +| CLICK_ZOOM | 1) call SetZoomButton(false) | +| | | +| | 2) call decorator->DrawZoom | +| | | +| | 3) send B_ZOOM to the target | +| | BWindow | ++-----------------------------------+-----------------------------------+ +| CLICK_MINIMIZE | 1) call SetMinimizeButton(false) | +| | | +| | 2) call decorator->DrawMinimize | +| | | +| | 3) send B_MINIMIZE to the target | +| | BWindow | ++-----------------------------------+-----------------------------------+ +| CLICK_DRAG | call set_is_win_moving(false) | ++-----------------------------------+-----------------------------------+ +| CLICK_RESIZE | call set_is_win_resizing(false) | ++-----------------------------------+-----------------------------------+ +| CLICK_NONE | do nothing | ++-----------------------------------+-----------------------------------+ +| default: | Spew an error to stderr | ++-----------------------------------+-----------------------------------+ + +void MouseMoved(int8 \*buffer) +------------------------------ + +Figures out what to do with B_MOUSE_MOVED messages sent to the window's border. + +1. Extract data from the buffer +2. Call the decorator's Clicked() function +3. If not CLICK_CLOSE and decorator->GetClose is true, call SetClose(false) and DrawClose() +4. If not CLICK_ZOOM and decorator->GetZoom is true, call SetZoom(false) and DrawZoom() +5. If not CLICK_MINIMIZE and decorator->GetMinimize is true, call SetMinimize(false) and DrawMinimize() +6. if CLICK_RESIZE or its variants, call CursorManager::SetCursor() with the appropriate system cursor. +7. if is_moving_window() is true, calculate the amount the mouse has moved and call decorator->MoveBy() followed by Layer::MoveBy() +8. if is_resizing_window() is true, calculate the amount the mouse has moved and call decorator->ResizeBy() followed by Layer::ResizeBy() + +void UpdateDecorator(void) +-------------------------- + +Hook function called by the WinBorder's ServerWindow when the decorator used is changed. + +1. Delete the current decorator +2. Call instantiate_decorator +3. Get the new decorator's footprint region and assign it to the full and visible regions +4. Call RebuildRegions and then RequestDraw + +void UpdateColors(void) +----------------------- + +Hook function called by the WinBorder's ServerWindow when system colors change + +1. Call the decorator's SetColors(), passing the SystemPalette's GetGUIColors() value + +void UpdateFont(void) +--------------------- + +Hook function called by the WinBorder's ServerWindow when system fonts change + +| TODO: implementation details + +void UpdateScreen(void) +----------------------- + +Hook function called by the WinBorder's ServerWindow when screen +attributes change + +1. Call the decorator's UpdateScreen and then RequestDraw + +void RebuildRegions(bool recursive=true) +---------------------------------------- + +Reimplementation of Layer::RebuildRegions which changes it such that +lower siblings are clipped to the footprint instead of the frame. + +void Activate(bool state) +------------------------- + +This function is never directly called except from within +set_active_winborder. It exists to force redraw and set the internal +state information to the proper values for when a window receives or +loses focus. + +1. call the decorator's SetFocus(state) +2. set the internal is_active flag to state +3. iterate through each rectangle in the visible region and call the decorator's Draw on it. + +Global Functions +================ + + +bool is_moving_window(void), void set_is_moving_window(bool state) +------------------------------------------------------------------ + + +These two functions set and return the variable +winborder_private::is_moving_a_window. + + +bool is_resizing_window(void), void set_is_resizing_window(bool state) +---------------------------------------------------------------------- + + +These two functions set and return the variable +winborder_private::is_resizing_a_window. + + +void set_active_winborder(WinBorder \*win), WinBorder \* get_active_winborder(void) +----------------------------------------------------------------------------------- + + +These two functions set and return the variable winborder_private::active_winborder + +Namespaces +========== + +.. code-block:: cpp + + winborder_private { + bool is_moving_a_window + bool is_resizing_a_window + WinBorder *active_winborder + } + diff --git a/docs/develop/servers/app_server/asis.htm b/docs/develop/servers/app_server/asis.htm deleted file mode 100644 index 821091912f..0000000000 --- a/docs/develop/servers/app_server/asis.htm +++ /dev/null @@ -1,271 +0,0 @@ - - -App Server Interface Spec.htm - - - -
-

App Server Interface Specification v0.3

-


-
Purpose:

-

The app_server provides services to the OpenBeOS by managing processes, filtering and dispatching input from the Input Server to the appropriate applications, and managing all graphics-related tasks.

-


-Tasks:

-

The tasks performed by the app_server are grouped in relation to its purpose.

-


-
Receives and redirects (dispatches) messages from the input server

-


-Responds to messages from apps

-

Receives and consolidates requests from BView, BWindow, BBitmap, and others to draw stuff (draw bitmap, etc)

-

Utilizes ports to communicate with child processes

-

Handles drag & drop messaging

-

Manages the system clipboard

-


-Loads and Kills processes

-

Detects absence of Input Server and restarts when not running

-

Aids in system shutdown

-


-Dynamically loads accelerant portion of graphics driver

-

Creates a connection with BBitmaps requiring a child view

-

Draws the blue desktop screen

-

Provides workspace support

-

Provides functionality to the BeAPI for drawing primitives, such as rectangles, ellipses, and beziers

-

Provides a means for BViews to draw on BBitmaps

-

Manages window behavior with respect to redraw (move to front, minimize, etc)

-

Returns a frame buffer to direct-access classes

-

Caches fonts for screen and printer use

-

Draws text and provides other font API support for the BeAPI classes

-


-
Table of Contents

-


-
Graphics:

-

I. Desktop Initialization

-

II. Window management

-

A. ServerApp

-

B. ServerWindow

-

C. Layer

-

D. WindowBorder

-

E. Decorator

-

III. Screen updates

-

IV. Cursor management

-

V. Display Drivers

-

Process Management:

-

I. BApplication execution

-

II. Non-BApplication execution

-

III. Killing/Exiting applications

-

IV. System Shutdown

-

Input Processing:

-

I. Input Server messages

-

II. Mouse

-

III. Keyboard

-

Messaging:

-

I. Inter-Application messaging

-

II. Drag-and-drop

-

III. Methods

-


-
-
-
-
Graphics:

-

I. Desktop Initialization

-

II. Window management

-

III. Screen updates

-

IV. Cursor management

-


-
I. Desktop Initialization

-


-The graphics hardware is abstracted from the rest of the app_server. When started, the server creates the desktop, which is little more than a collection of workspaces. The desktop actually creates a DisplayDriver and then calls the driver's method Inititialize() before calling a few high-level routines for setup. Below is the process by which the HWDriver class, which is used to access the primary graphics card in the system, followed by the steps taken to set up the desktop.

-


-
Load Accelerant

-

The app_server looks in three paths when scanning for an accelerant:

-

/fd/beos/system/add-ons/app_server

-

/boot/home/config/add-ons/app_server

-

/boot/beos/system/add-ons/app_server

-


- When the app_server searches a path, it simply prints to the debug stream on the serial port a message akin "Attempting to load accelerant so-and-so" when loading the accelerant. Following this, it is loads the accelerant via load_add_on(), obtains the hook function control_graphics_card is via get_image_symbol, and control_graphics_card(OPEN_GRAPHICS_CARD) is called. If this returns an error, the image is unloaded after a control_graphics_card(CLOSE_GRAPHICS_CARD) is called and the server spits out a message like "So-and-so is not an acceptable driver" to the serial port. Assuming that the OPEN call succeeds, the app_server serial prints "Using so-and-so as accelerant." Hook functions are then acquired through control_graphics_card(B_GET_GRAPHICS_CARD_HOOKS). At this point, it is a good idea to have a palette generated for 8-bit mode (just in case we're going to use it), so the server generates the system palette. The palette on the graphics card is then set through many calls to control_graphics_card(B_SET_INDEXED_COLOR).

-


-Set up workspaces

-

Workspace preferences are read in from disk. If they exist, they are used; otherwise the default of 3 workspace, each with the settings 640x480x256@59.9Hz, is used. Each workspace is initialized to the proper information (preferences or default). Additionally, all settings are checked and possibly "clipped" by information gained through the driver class. With the desktop having been given the proper settings, the default workspace, 0, is activated.

-


-
Display

-

Provided that everything has gone well so far, the screen is filled to the user-set workspace color or RGB(51,102,160) Also, the global clipboard is created, which is nothing more than a BClipboard object. The Input Server will notify the app_server of its existence, at which point the cursor will be set to B_HAND_CURSOR and shown on the screen.

-


-II. Window management

-


-Window management is a complicated issue, requiring the cooperation of a number of different types of elements. Each BApplication, BWindow, and BView has a counterpart in the app_server which has a role to play. These objects are Decorators, ServerApps, ServerWindows, Layers, and WindowBorders.

-


-
A. ServerApps

-


-ServerApp objects are created when a BApplication notifies the app_server of its presence. In acknowledging the BApplication's existence, the server creates a ServerApp which will handle future server-app communications and notifies the BApplication of the port to which it must send future messages.

-


-ServerApps are each an independent thread which has a function similar to that of a BLooper, but with additional tasks. When a BWindow is created, it spawns a ServerWindow object to handle the new window. The same applies to when a window is destroyed. Cursor commands and all other BApplication functions which require server interaction are also handled. B_QUIT_REQUESTED messages are received and passed along to the main thread in order for the ServerApp object to be destroyed. The server's Picasso thread also utilizes ServerApp::PingTarget in order to determine whether the counterpart BApplication is still alive and running.

-


-
B. ServerWindows

-


-ServerWindow objects' purpose is to take care of the needs of BWindows. This includes all calls which require a trip to the server, such as BView graphics calls and sending messages to invoke hook functions within a window.

-


-
C. Layers

-


-Layers are shadowed BViews and are used to handle much BView functionality and also determine invalid screen regions. Hierarchal functions, such as AddChild, are mirrored. Invalid regions are tracked and generate Draw requests which are sent to the application for a specific BView to update its part of the screen.

-


-
D. WindowBorders

-


-WindowBorders are a special kind of Layer with no BView counterpart, designed to handle window management issues, such as click tests, resize and move events, and ensuring that its decorator updates the screen appropriately.

-


-
F. Decorators

-


-Decorators are addons which are intended to do one thing: draw the window frame. The Decorator API and development information is described in the Decorator Development Reference. They are essentially the means by which WindowBorders draw to the screen.

-


-
G. How It All Works

-


-
The app_server is one large, complex beast because of all the tasks it performs. It also utilizes the various objects to accomplish them. Input messages are received from the Input Server and all messages not specific to the server (such as Ctrl-Alt-Shift-Backspace) are passed to the active application, if any. Mouse clicks are passed to the ServerWindow class for hit testing. These hit tests can result in window tabs and buttons being clicked, or mouse click messages being passed to a specific view in a window.

-


-These input messages which are passed to a running application will sometimes cause things to happen inside it, such as button presses, window closings/openings, etc. which will cause messages to be sent to the server. These messages are sent either from a BWindow to a ServerWindow or a BApplication to a ServerApp. When such messages are sent, then the corresponding app_server object performs an appropriate action.

-


-
III. Screen Updates

-


-Screen updates are done entirely through the BView class or some subclass thereof, hereafter referred to as a view. A view's drawing commands will cause its window to store draw command messages in a message packet. At some point Flush() will be called and the command packet will be sent to the window's ServerWindow object inside the server.

-


-The ServerWindow will receive the packet, check to ensure that its size is correct, and begin retrieving each command from the packet and dispatching it, taking the appropriate actions. Actual drawing commands, such as StrokeRect, will involve the ServerWindow object calling the appropriate command in the graphics module for the Layer corresponding to the view which sent the command.

-


-
IV. Cursor Management

-


-The app_server handles all messiness to do with the cursor. The cursor commands which are members of the BApplication class will send a message to its ServerApp, which will then call the DisplayDriver's appropriate function. The DisplayDriver used will actually handle the drawing of the cursor and whether or not to do so at any given time.

-


-OpenBeOS R1 will also include the advent of an extension of the API: SetCursor(BBitmap *), which will accept a BBitmap of color space RGB(A)32, RGBA16, CMAP8, GRAY8, or GRAY1. Thus, color cursors and cursors which are not 16x16 are now supported.

-


-V. Display Drivers

-


-Unlike the BeOS R5 app_server, OpenBeOS' server will have a special feature: a modular graphics driver access class. The class is not actually the graphics driver, but, rather, a generalized interface which is implemented to interact with various destinations for graphics output. This allows the server to draw to a BWindow/BView combination, a BDirectWindow, or the actual frame buffer of a particular graphics card. All that the rest of the server needs to do is call whichever graphics function that is needed.

-


-
Process Management:

-

I. BApplication execution

-

II. Non-BApplication execution

-

III. Killing/Exiting applications

-

IV. System Shutdown

-


-
I. BApplication execution

-


-
Applications will come in two types: those which communicate with the app_server and take advantage of its services, and those which do not. To access the app_server, an application must be derived from BApplication.

-


-When a BApplication (referred to hereafter as a BApp) is executed, the app constructor creates its BLooper message port with the name AppLooperPort. This port's id, by means of BLooper, registers its port_id with the app_server so that the two can communicate with each other most easily.

-


-When the app_server receives notification that an app has been created, the server creates an AppMonitor (with accompanying thread) in its own team to handle messages sent to it and sends a reply with the port_id of the AppMonitor, to which all future messages are sent. These AppMonitor objects are stored in a global BList created for the storage of such things.

-


-
II. non-BApplication execution

-


-
Other applications do not communicate with the app_server. These applications have no access to app services and do not generally pass BMessages. This includes, but is not limited to, UNIX apps. The app_server ignores such applications except when asked to kill them.

-


-While, technically, these are not limited to being non-GUI applications, in practice these applications are command-line-only, for the application would be required to (1) render the app_server unable to access video hardware and (2) reinvent existing graphics code to load and use accelerants and draw onto the video buffer. This is extremely bad style and programming practice, not to mention more work than it is worth except in one case: the OpenBeOS app_server can coexist with the BeOS R5 app_server with some degree of peace because it can utilize extra video cards which the BeOS app_server does not use.

-


-
III. Killing/Exiting Applications

-


-
While the input server handles the Team Monitor window, the app_server actually takes care of shutting down teams, peacefully or not. Exiting an app is done simply by sending a B_QUIT_REQUESTED message to particular app. Killing an app is done via kill_team, but all the messy details are handled by the kernel itself through this call. When the user requests a team die via the Team Monitor, the Input Server sends a message to the app_server to kill the team, attaching the team_id. The app_server responds by happily nuking the respective team and notifies the registrar of its forcible removal from the roster.

-


-IV. System Shutdown

-


-
Although the server maintains an internal list of running GUI applications, when a request to shut down the system is received by the app_server, it will pass the request on to the registrar, which will, in turn, increment its way through the app roster and request each app quit. When each quit request is sent, a timer is started and after timeout, the registrar will ask the server to kill the particular team and continue iterating through the application list.

-


-
Input Processing:

-

I. Input Server messages

-

II. Mouse

-

III. Keyboard

-


-I. Input Server messages

-


-
The Input Server collects information about keyboard and mouse events and forwards them to the app_server via messages. They are sent to port specifically for such messages, and the port is monitored by a thread whose task is to monitor, process, and dispatch them to the appropriate recipients. The Input Server is a regular BApplication, and unlike other applications, it requests a port to which it can send input messages.

-


-
II. Mouse

-


-
Mouse events consist of button changes, mouse movements, and the mouse wheel. The message will consist of the time of the event and attachments appropriate for each message listed below:

-


-B_MOUSE_DOWN

-

when

-

location of the cursor

-

button number

-

modifiers

-

clicks

-

B_MOUSE_UP

-

time

-

buttons' status // not implemented for R5 but included for future expansion

-

location of the cursor

-

modifiers

-

B_MOUSE_MOVED

-

time

-

location of the cursor

-

buttons' status

-

B_MOUSE_WHEEL_CHANGED

-

time

-

location of the cursor

-

transit - in or out

-

x delta

-

y delta

-


-
III. Keyboard

-


-Keyboard events consist of notification when a key is pressed or released. Any keypress or release will evoke a message, regardless of whether or not the key is mapped. The message will consist of the appropriate code and attachments listed below:

-


-B_KEY_DOWN

-

time

-

key code

-

repeat count

-

modifiers

-

states

-

UTF-8 code

-

string generated

-

modifier-independent ASCII code

-

B_KEY_UP

-

time

-

key code

-

modifiers

-

states

-

UTF-8 code

-

string generated

-

modifier-independent ASCII code

-

B_UNMAPPED_KEY_DOWN

-

time

-

key code

-

modifiers

-

states

-

B_UNMAPPED_KEY_UP

-

time

-

key code

-

modifiers

-

states

-

B_MODIFIERS_CHANGED // sent when a modifier key changes

-

time

-

modifier states

-

previous modifier states

-

states

-


-Nearly all keypresses received by the app_server are passed onto the appropriate application. Control-Tab, when held, is sent to the Deskbar for app switching. Command+F?? is intercepted and a workspace is switched. Left Control + Alt + Delete is not even intercepted by the app_server. The Input Server receives it and shows the Team Monitor window.

-


-
Messaging:

-

I. Inter-Application messaging

-

II. Drag-and-drop

-

III. Methods

-


-
I. Inter-Application Messaging

-


-
The details of messaging are depicted under Process Management::BApplication.

-


-
II. Drag-and-drop

-


-III. Methods

-


-
Messaging with the app_server is not done using BMessages because of the overhead required to send them costs time and speed. Instead, ports are utilized indirectly by means of the PortLink class, which simply makes attaching data to a port message easier, but requires very little overhead.

-
-
-
- - diff --git a/docs/develop/servers/app_server/asis.rst b/docs/develop/servers/app_server/asis.rst new file mode 100644 index 0000000000..97baa6a2b4 --- /dev/null +++ b/docs/develop/servers/app_server/asis.rst @@ -0,0 +1,425 @@ +App Server Interface Specification v0.3 +####################################### + +Purpose: +======== + +The app_server provides services to the OpenBeOS by managing processes, +filtering and dispatching input from the Input Server to the appropriate +applications, and managing all graphics-related tasks. + +Tasks: +====== + +The tasks performed by the app_server are grouped in relation to its +purpose. + +- Receives and redirects (dispatches) messages from the input server +- Responds to messages from apps +- Receives and consolidates requests from BView, BWindow, BBitmap, and others to draw stuff (draw bitmap, etc) +- Utilizes ports to communicate with child processes +- Handles drag & drop messaging +- Manages the system clipboard +- Loads and Kills processes +- Detects absence of Input Server and restarts when not running +- Aids in system shutdown +- Dynamically loads accelerant portion of graphics driver +- Creates a connection with BBitmaps requiring a child view +- Draws the blue desktop screen +- Provides workspace support +- Provides functionality to the BeAPI for drawing primitives, such as rectangles, ellipses, and beziers +- Provides a means for BViews to draw on BBitmaps +- Manages window behavior with respect to redraw (move to front, minimize, etc) +- Returns a frame buffer to direct-access classes +- Caches fonts for screen and printer use +- Draws text and provides other font API support for the BeAPI classes + +Graphics: +========= + +Desktop Initialization +----------------------- + +The graphics hardware is abstracted from the rest of the app_server. +When started, the server creates the desktop, which is little more than +a collection of workspaces. The desktop actually creates a DisplayDriver +and then calls the driver's method Inititialize() before calling a few +high-level routines for setup. Below is the process by which the +HWDriver class, which is used to access the primary graphics card in the +system, followed by the steps taken to set up the desktop. + +Load Accelerant +............... + +The app_server looks in three paths when scanning for an accelerant: + +- /fd/beos/system/add-ons/app_server +- /boot/home/config/add-ons/app_server +- /boot/beos/system/add-ons/app_server + +When the app_server searches a path, it simply prints to the debug +stream on the serial port a message akin "Attempting to load accelerant +so-and-so" when loading the accelerant. Following this, it is loads the +accelerant via load_add_on(), obtains the hook function +control_graphics_card is via get_image_symbol, and +control_graphics_card(OPEN_GRAPHICS_CARD) is called. If this returns an +error, the image is unloaded after a +control_graphics_card(CLOSE_GRAPHICS_CARD) is called and the server +spits out a message like "So-and-so is not an acceptable driver" to the +serial port. Assuming that the OPEN call succeeds, the app_server serial +prints "Using so-and-so as accelerant." Hook functions are then acquired +through control_graphics_card(B_GET_GRAPHICS_CARD_HOOKS). At this point, +it is a good idea to have a palette generated for 8-bit mode (just in +case we're going to use it), so the server generates the system palette. +The palette on the graphics card is then set through many calls to +control_graphics_card(B_SET_INDEXED_COLOR). + +Set up workspaces +................. + +Workspace preferences are read in from disk. If they exist, they are +used; otherwise the default of 3 workspace, each with the settings +640x480x256@59.9Hz, is used. Each workspace is initialized to the proper +information (preferences or default). Additionally, all settings are +checked and possibly "clipped" by information gained through the driver +class. With the desktop having been given the proper settings, the +default workspace, 0, is activated. + +Display +....... + +Provided that everything has gone well so far, the screen is filled to +the user-set workspace color or RGB(51,102,160) Also, the global +clipboard is created, which is nothing more than a BClipboard object. +The Input Server will notify the app_server of its existence, at which +point the cursor will be set to B_HAND_CURSOR and shown on the screen. + +Window management +----------------- + +Window management is a complicated issue, requiring the cooperation of a +number of different types of elements. Each BApplication, BWindow, and +BView has a counterpart in the app_server which has a role to play. +These objects are Decorators, ServerApps, ServerWindows, Layers, and +WindowBorders. + +ServerApps +.......... + +ServerApp objects are created when a BApplication notifies the +app_server of its presence. In acknowledging the BApplication's +existence, the server creates a ServerApp which will handle future +server-app communications and notifies the BApplication of the port to +which it must send future messages. + +ServerApps are each an independent thread which has a function similar +to that of a BLooper, but with additional tasks. When a BWindow is +created, it spawns a ServerWindow object to handle the new window. The +same applies to when a window is destroyed. Cursor commands and all +other BApplication functions which require server interaction are also +handled. B_QUIT_REQUESTED messages are received and passed along to the +main thread in order for the ServerApp object to be destroyed. The +server's Picasso thread also utilizes ServerApp::PingTarget in order to +determine whether the counterpart BApplication is still alive and +running. + +ServerWindows +............. + +ServerWindow objects' purpose is to take care of the needs of BWindows. +This includes all calls which require a trip to the server, such as +BView graphics calls and sending messages to invoke hook functions +within a window. + +Layers +...... + +Layers are shadowed BViews and are used to handle much BView +functionality and also determine invalid screen regions. Hierarchal +functions, such as AddChild, are mirrored. Invalid regions are tracked +and generate Draw requests which are sent to the application for a +specific BView to update its part of the screen. + +WindowBorders +............. + +WindowBorders are a special kind of Layer with no BView counterpart, +designed to handle window management issues, such as click tests, resize +and move events, and ensuring that its decorator updates the screen +appropriately. + +Decorators +.......... + +Decorators are addons which are intended to do one thing: draw the +window frame. The Decorator API and development information is described +in the Decorator Development Reference. They are essentially the means +by which WindowBorders draw to the screen. + +How It All Works +................ + +The app_server is one large, complex beast because of all the tasks it +performs. It also utilizes the various objects to accomplish them. Input +messages are received from the Input Server and all messages not +specific to the server (such as Ctrl-Alt-Shift-Backspace) are passed to +the active application, if any. Mouse clicks are passed to the +ServerWindow class for hit testing. These hit tests can result in window +tabs and buttons being clicked, or mouse click messages being passed to +a specific view in a window. + +These input messages which are passed to a running application will +sometimes cause things to happen inside it, such as button presses, +window closings/openings, etc. which will cause messages to be sent to +the server. These messages are sent either from a BWindow to a +ServerWindow or a BApplication to a ServerApp. When such messages are +sent, then the corresponding app_server object performs an appropriate +action. + +Screen Updates +-------------- + +Screen updates are done entirely through the BView class or some +subclass thereof, hereafter referred to as a view. A view's drawing +commands will cause its window to store draw command messages in a +message packet. At some point Flush() will be called and the command +packet will be sent to the window's ServerWindow object inside the +server. + +The ServerWindow will receive the packet, check to ensure that its size +is correct, and begin retrieving each command from the packet and +dispatching it, taking the appropriate actions. Actual drawing commands, +such as StrokeRect, will involve the ServerWindow object calling the +appropriate command in the graphics module for the Layer corresponding +to the view which sent the command. + +Cursor Management +----------------- + +The app_server handles all messiness to do with the cursor. The cursor +commands which are members of the BApplication class will send a message +to its ServerApp, which will then call the DisplayDriver's appropriate +function. The DisplayDriver used will actually handle the drawing of the +cursor and whether or not to do so at any given time. + +OpenBeOS R1 will also include the advent of an extension of the API: +SetCursor(BBitmap \*), which will accept a BBitmap of color space +RGB(A)32, RGBA16, CMAP8, GRAY8, or GRAY1. Thus, color cursors and +cursors which are not 16x16 are now supported. + +Display Drivers +--------------- + +Unlike the BeOS R5 app_server, OpenBeOS' server will have a special +feature: a modular graphics driver access class. The class is not +actually the graphics driver, but, rather, a generalized interface which +is implemented to interact with various destinations for graphics +output. This allows the server to draw to a BWindow/BView combination, a +BDirectWindow, or the actual frame buffer of a particular graphics card. +All that the rest of the server needs to do is call whichever graphics +function that is needed. + +Process Management +================== + +BApplication execution +----------------------- + +Applications will come in two types: those which communicate with the +app_server and take advantage of its services, and those which do not. +To access the app_server, an application must be derived from +BApplication. + +When a BApplication (referred to hereafter as a BApp) is executed, the +app constructor creates its BLooper message port with the name +AppLooperPort. This port's id, by means of BLooper, registers its +port_id with the app_server so that the two can communicate with each +other most easily. + +When the app_server receives notification that an app has been created, +the server creates an AppMonitor (with accompanying thread) in its own +team to handle messages sent to it and sends a reply with the port_id of +the AppMonitor, to which all future messages are sent. These AppMonitor +objects are stored in a global BList created for the storage of such +things. + +non-BApplication execution +-------------------------- + +Other applications do not communicate with the app_server. These +applications have no access to app services and do not generally pass +BMessages. This includes, but is not limited to, UNIX apps. The +app_server ignores such applications except when asked to kill them. + +While, technically, these are not limited to being non-GUI applications, +in practice these applications are command-line-only, for the +application would be required to (1) render the app_server unable to +access video hardware and (2) reinvent existing graphics code to load +and use accelerants and draw onto the video buffer. This is extremely +bad style and programming practice, not to mention more work than it is +worth except in one case: the OpenBeOS app_server can coexist with the +BeOS R5 app_server with some degree of peace because it can utilize +extra video cards which the BeOS app_server does not use. + +Killing/Exiting Applications +---------------------------- + +While the input server handles the Team Monitor window, the app_server +actually takes care of shutting down teams, peacefully or not. Exiting +an app is done simply by sending a B_QUIT_REQUESTED message to +particular app. Killing an app is done via kill_team, but all the messy +details are handled by the kernel itself through this call. When the +user requests a team die via the Team Monitor, the Input Server sends a +message to the app_server to kill the team, attaching the team_id. The +app_server responds by happily nuking the respective team and notifies +the registrar of its forcible removal from the roster. + +System Shutdown +--------------- + +Although the server maintains an internal list of running GUI +applications, when a request to shut down the system is received by the +app_server, it will pass the request on to the registrar, which will, in +turn, increment its way through the app roster and request each app +quit. When each quit request is sent, a timer is started and after +timeout, the registrar will ask the server to kill the particular team +and continue iterating through the application list. + +Input Processing +================ + +Input Server messages +--------------------- + +The Input Server collects information about keyboard and mouse events +and forwards them to the app_server via messages. They are sent to port +specifically for such messages, and the port is monitored by a thread +whose task is to monitor, process, and dispatch them to the appropriate +recipients. The Input Server is a regular BApplication, and unlike other +applications, it requests a port to which it can send input messages. + +Mouse +----- + +Mouse events consist of button changes, mouse movements, and the mouse +wheel. The message will consist of the time of the event and attachments +appropriate for each message listed below: + +B_MOUSE_DOWN +............ + +- when +- location of the cursor +- button number +- modifiers +- clicks + +B_MOUSE_UP +.......... + +- time +- buttons' status // not implemented for R5 but included for future expansion +- location of the cursor +- modifiers + +B_MOUSE_MOVED +............. + +- time +- location of the cursor +- buttons' status + +B_MOUSE_WHEEL_CHANGED +..................... + +- time +- location of the cursor +- transit - in or out +- x delta +- y delta + +Keyboard +-------- + +Keyboard events consist of notification when a key is pressed or +released. Any keypress or release will evoke a message, regardless of +whether or not the key is mapped. The message will consist of the +appropriate code and attachments listed below: + +B_KEY_DOWN +.......... + +- time +- key code +- repeat count +- modifiers +- states +- UTF-8 code +- string generated +- modifier-independent ASCII code + +B_KEY_UP +........ + +- time +- key code +- modifiers +- states +- UTF-8 code +- string generated +- modifier-independent ASCII code + +B_UNMAPPED_KEY_DOWN +................... + +- time +- key code +- modifiers +- states + +B_UNMAPPED_KEY_UP +................. + +- time +- key code +- modifiers +- states + +B_MODIFIERS_CHANGED +................... + +sent when a modifier key changes + +- time +- modifier states +- previous modifier states +- states + +Nearly all keypresses received by the app_server are passed onto the +appropriate application. Control-Tab, when held, is sent to the Deskbar +for app switching. Command+F?? is intercepted and a workspace is +switched. Left Control + Alt + Delete is not even intercepted by the +app_server. The Input Server receives it and shows the Team Monitor +window. + +Messaging +========= + +Inter-Application Messaging +--------------------------- + +The details of messaging are depicted under Process +Management::BApplication. + +Drag-and-drop +------------- + +Methods +------- + +Messaging with the app_server is not done using BMessages because of the +overhead required to send them costs time and speed. Instead, ports are +utilized indirectly by means of the PortLink class, which simply makes +attaching data to a port message easier, but requires very little +overhead. + diff --git a/docs/develop/servers/app_server/bget.txt b/docs/develop/servers/app_server/bget.txt deleted file mode 100644 index e8835b5b82..0000000000 --- a/docs/develop/servers/app_server/bget.txt +++ /dev/null @@ -1,339 +0,0 @@ - - BGET -- Memory Allocator - ========================== - - by John Walker - kelvin@fourmilab.ch - http://www.fourmilab.ch/ - -BGET is a comprehensive memory allocation package which is easily -configured to the needs of an application. BGET is efficient in both -the time needed to allocate and release buffers and in the memory -overhead required for buffer pool management. It automatically -consolidates contiguous space to minimise fragmentation. BGET is -configured by compile-time definitions, Major options include: - - * A built-in test program to exercise BGET and - demonstrate how the various functions are used. - - * Allocation by either the "first fit" or "best fit" - method. - - * Wiping buffers at release time to catch code which - references previously released storage. - - * Built-in routines to dump individual buffers or the - entire buffer pool. - - * Retrieval of allocation and pool size statistics. - - * Quantisation of buffer sizes to a power of two to - satisfy hardware alignment constraints. - - * Automatic pool compaction, growth, and shrinkage by - means of call-backs to user defined functions. - -Applications of BGET can range from storage management in ROM-based -embedded programs to providing the framework upon which a multitasking -system incorporating garbage collection is constructed. BGET -incorporates extensive internal consistency checking using the - mechanism; all these checks can be turned off by compiling -with NDEBUG defined, yielding a version of BGET with minimal size and -maximum speed. - -The basic algorithm underlying BGET has withstood the test of time; more -than 25 years have passed since the first implementation of this code. -And yet, it is substantially more efficient than the native allocation -schemes of many operating systems: the Macintosh and Microsoft Windows -to name two, on which programs have obtained substantial speed-ups by -layering BGET as an application level memory manager atop the underlying -system's. - -BGET has been implemented on the largest mainframes and the lowest of -microprocessors. It has served as the core for multitasking operating -systems, multi-thread applications, embedded software in data network -switching processors, and a host of C programs. And while it has -accreted flexibility and additional options over the years, it remains -fast, memory efficient, portable, and easy to integrate into your -program. - - -BGET IMPLEMENTATION ASSUMPTIONS -=============================== - -BGET is written in as portable a dialect of C as possible. The only -fundamental assumption about the underlying hardware architecture is -that memory is allocated is a linear array which can be addressed as a -vector of C "char" objects. On segmented address space architectures, -this generally means that BGET should be used to allocate storage within -a single segment (although some compilers simulate linear address spaces -on segmented architectures). On segmented architectures, then, BGET -buffer pools may not be larger than a segment, but since BGET allows any -number of separate buffer pools, there is no limit on the total storage -which can be managed, only on the largest individual object which can be -allocated. Machines with a linear address architecture, such as the -VAX, 680x0, Sparc, MIPS, or the Intel 80386 and above in native mode, -may use BGET without restriction. - - -GETTING STARTED WITH BGET -========================= - -Although BGET can be configured in a multitude of fashions, there are -three basic ways of working with BGET. The functions mentioned below -are documented in the following section. Please excuse the forward -references which are made in the interest of providing a roadmap to -guide you to the BGET functions you're likely to need. - -Embedded Applications ---------------------- - -Embedded applications typically have a fixed area of memory dedicated to -buffer allocation (often in a separate RAM address space distinct from -the ROM that contains the executable code). To use BGET in such an -environment, simply call bpool() with the start address and length of -the buffer pool area in RAM, then allocate buffers with bget() and -release them with brel(). Embedded applications with very limited RAM -but abundant CPU speed may benefit by configuring BGET for BestFit -allocation (which is usually not worth it in other environments). - -Malloc() Emulation ------------------- - -If the C library malloc() function is too slow, not present in your -development environment (for example, an a native Windows or Macintosh -program), or otherwise unsuitable, you can replace it with BGET. -Initially define a buffer pool of an appropriate size with -bpool()--usually obtained by making a call to the operating system's -low-level memory allocator. Then allocate buffers with bget(), bgetz(), -and bgetr() (the last two permit the allocation of buffers initialised -to zero and [inefficient] re-allocation of existing buffers for -compatibility with C library functions). Release buffers by calling -brel(). If a buffer allocation request fails, obtain more storage from -the underlying operating system, add it to the buffer pool by another -call to bpool(), and continue execution. - -Automatic Storage Management ----------------------------- - -You can use BGET as your application's native memory manager and -implement automatic storage pool expansion, contraction, and optionally -application-specific memory compaction by compiling BGET with the BECtl -variable defined, then calling bectl() and supplying functions for -storage compaction, acquisition, and release, as well as a standard pool -expansion increment. All of these functions are optional (although it -doesn't make much sense to provide a release function without an -acquisition function, does it?). Once the call-back functions have been -defined with bectl(), you simply use bget() and brel() to allocate and -release storage as before. You can supply an initial buffer pool with -bpool() or rely on automatic allocation to acquire the entire pool. -When a call on bget() cannot be satisfied, BGET first checks if a -compaction function has been supplied. If so, it is called (with the -space required to satisfy the allocation request and a sequence number -to allow the compaction routine to be called successively without -looping). If the compaction function is able to free any storage (it -needn't know whether the storage it freed was adequate) it should return -a nonzero value, whereupon BGET will retry the allocation request and, -if it fails again, call the compaction function again with the -next-higher sequence number. - -If the compaction function returns zero, indicating failure to free -space, or no compaction function is defined, BGET next tests whether a -non-NULL allocation function was supplied to bectl(). If so, that -function is called with an argument indicating how many bytes of -additional space are required. This will be the standard pool expansion -increment supplied in the call to bectl() unless the original bget() -call requested a buffer larger than this; buffers larger than the -standard pool block can be managed "off the books" by BGET in this mode. -If the allocation function succeeds in obtaining the storage, it returns -a pointer to the new block and BGET expands the buffer pool; if it -fails, the allocation request fails and returns NULL to the caller. If -a non-NULL release function is supplied, expansion blocks which become -totally empty are released to the global free pool by passing their -addresses to the release function. - -Equipped with appropriate allocation, release, and compaction functions, -BGET can be used as part of very sophisticated memory management -strategies, including garbage collection. (Note, however, that BGET is -*not* a garbage collector by itself, and that developing such a system -requires much additional logic and careful design of the application's -memory allocation strategy.) - - -BGET FUNCTION DESCRIPTIONS -========================== - -Functions implemented by BGET (some are enabled by certain of the -optional settings below): - - void bpool(void *buffer, bufsize len); - -Create a buffer pool of bytes, using the storage starting at -. You can call bpool() subsequently to contribute additional -storage to the overall buffer pool. - - void *bget(bufsize size); - -Allocate a buffer of bytes. The address of the buffer is -returned, or NULL if insufficient memory was available to allocate the -buffer. - - void *bgetz(bufsize size); - -Allocate a buffer of bytes and clear it to all zeroes. The -address of the buffer is returned, or NULL if insufficient memory was -available to allocate the buffer. - - void *bgetr(void *buffer, bufsize newsize); - -Reallocate a buffer previously allocated by bget(), changing its size to - and preserving all existing data. NULL is returned if -insufficient memory is available to reallocate the buffer, in which case -the original buffer remains intact. - - void brel(void *buf); - -Return the buffer , previously allocated by bget(), to the free -space pool. - - void bectl(int (*compact)(bufsize sizereq, int sequence), - void *(*acquire)(bufsize size), - void (*release)(void *buf), - bufsize pool_incr); - -Expansion control: specify functions through which the package may -compact storage (or take other appropriate action) when an allocation -request fails, and optionally automatically acquire storage for -expansion blocks when necessary, and release such blocks when they -become empty. If is non-NULL, whenever a buffer allocation -request fails, the function will be called with arguments -specifying the number of bytes (total buffer size, including header -overhead) required to satisfy the allocation request, and a sequence -number indicating the number of consecutive calls on -attempting to satisfy this allocation request. The sequence number is 1 -for the first call on for a given allocation request, and -increments on subsequent calls, permitting the function to -take increasingly dire measures in an attempt to free up storage. If -the function returns a nonzero value, the allocation attempt -is re-tried. If returns 0 (as it must if it isn't able to -release any space or add storage to the buffer pool), the allocation -request fails, which can trigger automatic pool expansion if the - argument is non-NULL. At the time the function is -called, the state of the buffer allocator is identical to that at the -moment the allocation request was made; consequently, the -function may call brel(), bpool(), bstats(), and/or directly manipulate -the buffer pool in any manner which would be valid were the application -in control. This does not, however, relieve the function of -the need to ensure that whatever actions it takes do not change things -underneath the application that made the allocation request. For -example, a function that released a buffer in the process of -being reallocated with bgetr() would lead to disaster. Implementing a -safe and effective mechanism requires careful design of an -application's memory architecture, and cannot generally be easily -retrofitted into existing code. - -If is non-NULL, that function will be called whenever an -allocation request fails. If the function succeeds in -allocating the requested space and returns a pointer to the new area, -allocation will proceed using the expanded buffer pool. If -cannot obtain the requested space, it should return NULL and the entire -allocation process will fail. specifies the normal -expansion block size. Providing an function will cause -subsequent bget() requests for buffers too large to be managed in the -linked-block scheme (in other words, larger than minus the -buffer overhead) to be satisfied directly by calls to the -function. Automatic release of empty pool blocks will occur only if all -pool blocks in the system are the size given by . - - void bstats(bufsize *curalloc, bufsize *totfree, - bufsize *maxfree, long *nget, long *nrel); - -The amount of space currently allocated is stored into the variable -pointed to by . The total free space (sum of all free blocks -in the pool) is stored into the variable pointed to by , and -the size of the largest single block in the free space pool is stored -into the variable pointed to by . The variables pointed to by - and are filled, respectively, with the number of -successful (non-NULL return) bget() calls and the number of brel() -calls. - - void bstatse(bufsize *pool_incr, long *npool, - long *npget, long *nprel, - long *ndget, long *ndrel); - -Extended statistics: The expansion block size will be stored into the -variable pointed to by , or the negative thereof if automatic -expansion block releases are disabled. The number of currently active -pool blocks will be stored into the variable pointed to by . The -variables pointed to by and will be filled with, -respectively, the number of expansion block acquisitions and releases -which have occurred. The variables pointed to by and -will be filled with the number of bget() and brel() calls, respectively, -managed through blocks directly allocated by the acquisition and release -functions. - - void bufdump(void *buf); - -The buffer pointed to by is dumped on standard output. - - void bpoold(void *pool, int dumpalloc, int dumpfree); - -All buffers in the buffer pool , previously initialised by a call -on bpool(), are listed in ascending memory address order. If - is nonzero, the contents of allocated buffers are dumped; if - is nonzero, the contents of free blocks are dumped. - - int bpoolv(void *pool); - -The named buffer pool, previously initialised by a call on bpool(), is -validated for bad pointers, overwritten data, etc. If compiled with -NDEBUG not defined, any error generates an assertion failure. Otherwise 1 -is returned if the pool is valid, 0 if an error is found. - -BGET CONFIGURATION -================== - -#define TestProg 20000 /* Generate built-in test program - if defined. The value specifies - how many buffer allocation attempts - the test program should make. */ - -#define SizeQuant 4 /* Buffer allocation size quantum: - all buffers allocated are a - multiple of this size. This - MUST be a power of two. */ - -#define BufDump 1 /* Define this symbol to enable the - bpoold() function which dumps the - buffers in a buffer pool. */ - -#define BufValid 1 /* Define this symbol to enable the - bpoolv() function for validating - a buffer pool. */ - -#define DumpData 1 /* Define this symbol to enable the - bufdump() function which allows - dumping the contents of an allocated - or free buffer. */ - -#define BufStats 1 /* Define this symbol to enable the - bstats() function which calculates - the total free space in the buffer - pool, the largest available - buffer, and the total space - currently allocated. */ - -#define FreeWipe 1 /* Wipe free buffers to a guaranteed - pattern of garbage to trip up - miscreants who attempt to use - pointers into released buffers. */ - -#define BestFit 1 /* Use a best fit algorithm when - searching for space for an - allocation request. This uses - memory more efficiently, but - allocation will be much slower. */ - -#define BECtl 1 /* Define this symbol to enable the - bectl() function for automatic - pool space control. */ diff --git a/docs/develop/servers/app_server/toc.htm b/docs/develop/servers/app_server/toc.htm deleted file mode 100644 index 15038379cc..0000000000 --- a/docs/develop/servers/app_server/toc.htm +++ /dev/null @@ -1,52 +0,0 @@ - - - -

OpenBeOS R1 Application Server Specification

- -

Table of Contents

- -

Class Descriptions

- -
Application Management
- - - -
Graphics Management
-

-

- -
Font Infrastructure
-

-

- -

Other Documents

- - - - \ No newline at end of file diff --git a/docs/develop/servers/app_server/toc.rst b/docs/develop/servers/app_server/toc.rst new file mode 100644 index 0000000000..0b837d542d --- /dev/null +++ b/docs/develop/servers/app_server/toc.rst @@ -0,0 +1,49 @@ +Application Server +============================================ + +Class Descriptions +~~~~~~~~~~~~~~~~~~ + +Application Management + +.. toctree:: + + /servers/app_server/AppServer + /servers/app_server/ServerApp + /servers/app_server/SharedObject + /servers/app_server/TokenHandler + /servers/app_server/DebugTools + +Graphics Management + +.. toctree:: + + /servers/app_server/BitmapManager + /servers/app_server/ColorUtils + /servers/app_server/CursorManager + /servers/app_server/Decorator + /servers/app_server/Desktop + /servers/app_server/DesktopClasses + /servers/app_server/DisplayDriver + /servers/app_server/Layer + /servers/app_server/PatternHandler + /servers/app_server/RGBColor + /servers/app_server/ServerBitmap + /servers/app_server/SystemPalette + /servers/app_server/WinBorder + +Font Infrastructure + +.. toctree:: + + /servers/app_server/FontServer + /servers/app_server/FontFamily + +Other Documents +~~~~~~~~~~~~~~~ + +.. toctree:: + + /servers/app_server/asis + +- `Multiple Monitor Support Spec `__ diff --git a/docs/develop/servers/input/input_server threads b/docs/develop/servers/input/input_server threads deleted file mode 100644 index 0f93d29338..0000000000 --- a/docs/develop/servers/input/input_server threads +++ /dev/null @@ -1,12 +0,0 @@ -Input_server threads - -input_server(10-Normal Priority) -_input_server_event_loop_(103-Custom Priority) -ScreenSaver Looper(10-Normal Priority) -DevicesLooper(10-Normal Priority) -w>Team Monitor(120-Real Time Priority) -PS/2 Mouse(104-Custom Priority) -AT Keyboard(104-Custom Priority) - -Legend: -w> This signifies that the thread is spawned from a parent process. (most likely from the input_server) \ No newline at end of file diff --git a/docs/develop/servers/input/intro to input_server b/docs/develop/servers/input/intro to input_server deleted file mode 100644 index c2fbce5a43..0000000000 --- a/docs/develop/servers/input/intro to input_server +++ /dev/null @@ -1,149 +0,0 @@ -
-
This is G o o g l e's cache of http://bedriven.be-in.org/articles/input_server/II_035-an%20introduction%20to%20the%20input%20server.html.
-G o o g l e's cache is the snapshot that we took of the page as we crawled the web.
-The page may have changed since that time. Click here for the current page without highlighting.


Google is not affiliated with the authors of this page nor responsible for its content.
-
These search terms have been highlighted: hiroshi lockheimer 
-These terms only appear in links pointing to this page: input_server -
-
- -Be Newsletter, Volume II, Issue 35 - - -
Be Newsletter, Volume II, Issue 35; September 2, 1998

- - -BE ENGINEERING INSIGHTS:

An Introduction to the Input Server -
By Hiroshi Lockheimer hiroshi@be.com -

One of the many upcoming changes in the BeOS is in the world -of input devices and events. The Input Server, slated to -debut in R4, is a server that deals with all things "input." -Specifically, it serves three functions: manages input -devices such as keyboards and mice; hosts a stream of events -that those devices generate; and dispatches those events -that make it through the stream. - - -

-Managing Input Devices - - -

The Input Server is a pretty dumb piece of software. (Cue to -Alex: roll your eyes and say, "What do you expect Hiroshi, -you wrote it.") On its own, the server doesn't know how a -keyboard or a mouse works; it relies on BInputServerDevice -add-ons to tell it. - - -

BInputServerDevice is a base class from which all input -device add-ons must derive. It provides the basic framework -of virtual hook functions and non-virtual member functions -that the Input Server uses to communicate with an add-on, -and that the add-on can use to talk back to the server. To -give a sneak peak of the API, some of the virtuals include -InitCheck(), Start(), Stop(), and Control(). The common -sequence of the life of an input device is this: - -

    - -
  1. The Input Server loads an add-on and constructs its - BInputServerDevice-derived object. - - -

  2. The Input Server calls InitCheck() on the object. The - object determines whether it is capable of doing its job - -- that is, generating input events. - - -

  3. This task may involve the object sniffing around for - hardware it can drive, or looking for a kernel device - driver in /dev. If the object is happy, it registers with - the Input Server any input device(s) it finds, and - returns B_NO_ERROR. An error return causes the Input - Server to promptly destruct the object and unload the - add-on. - - -

  4. At some point in time, someone will tell the input - devices registered with the Input Server to Start(). The - system automatically starts keyboards and mice at boot - time. Any other type of device (an "undefined" input - device that the system doesn't have any special knowledge - about) can be started by an application using new API in - the Interface Kit. - - -

  5. A registered device, whether it has been started or - not, may be Control()-ed at any time. Think of Control() - as the ioctl() equivalent in input device parlance. - Examples of system-defined control messages include - keymap changes and mouse speed changes. -
- -

-Generating Input Events - - -

Once a BInputServerDevice-derived object's input device is -up and running, its primary task is to generate input -events. These events are expressed as BMessages. For -example, a keyboard input device will most likely generate -B_KEY_DOWN and B_KEY_UP messages. Similarly, a mouse input -device will probably generate B_MOUSE_UP, B_MOUSE_DOWN, and -B_MOUSE_MOVED events. - - -

There is nothing that prevents an input device from putting -arbitrary data in any of the BMessages it generates. So, for -example, a tablet may generate the aforementioned mouse -events with extra data such as pressure and proximity. Any -information packed into the BMessages is delivered -unmolested by the input server. - - -

When an event is ready to be shipped off, an input device -enqueues it into the Input Server's event stream. Some -BHandler (most likely a BView) down the line eventually -receives the event by way of the usual hook functions such -as KeyDown(), MouseDown(), and MouseMoved(). - - -

-The Input Event Stream - - -

The Input Server's event stream is open for inspection and -alteration by anyone in the system. This is achieved through -another set of add-ons called BInputServerFilter. Like -BInputServerDevice, BInputServerFilter is a base class for input filter add-ons to the Input Server. - - -

An input filter add-on is privy to all the events that pass -through the Input Server's event stream. A filter may -inspect, alter, generate, or completely drop input events. -It's similar in some ways to the Interface Kit's -BMessageFilter, but much more low-level. A -BInputServerFilter sees all events that exist in the system; -BMessageFilters are associated with a specific BLooper and -thus see only the events targeted to its BLooper. Also, -filters in the Input Server can generate additional events -in place of, or in addition to, the original input event -that it was invoked with. - - -

-Conclusion - - -

With the introduction of loadable input device objects, the -Input Server enables the BeOS to be used with a wide variety -of input devices (and more than one of them at once too). -And with the advent of input filters, the Input Server opens -the door to a new class of tricks, hacks, and (gulp) pranks -for the creative developer. It's going to be fun. - - -

- - - diff --git a/docs/develop/servers/input/objdump-inputserver b/docs/develop/servers/input/objdump-inputserver deleted file mode 100644 index 06ffc764ab..0000000000 --- a/docs/develop/servers/input/objdump-inputserver +++ /dev/null @@ -1,104 +0,0 @@ -00000000 l df *ABS* 00000000 InputServer.cpp -00000000 l df *ABS* 00000000 InputServerDevice.cpp -00000000 l df *ABS* 00000000 InputServerFilter.cpp -00000000 l df *ABS* 00000000 InputServerMethod.cpp -000245c0 g O .bss 0000000c InputServer type_info node -000164cc g F .text 0000002f BInputServerDevice::StartMonitoringDevice(char const *) -000245ec g O .bss 0000000c BInputServerMethod type_info node -0001fce0 w O .data 00000058 BInputServerDevice virtual table -00016584 g F .text 00000009 BInputServerDevice::Stop(char const *, void *) -00016550 g F .text 00000026 BInputServerDevice::RegisterDevices(input_device_ref **) -00012e64 g F .text 00000207 InputServer::QuitRequested(void) -00024580 g O .bss 00000020 InputServer::fMouseState -00016720 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod2(void) -000151bc g F .text 0000010f InputServer::HandleGetSetMouseAcceleration(BMessage *, BMessage *) -0001620c g F .text 000000df InputServer::EnqueueMethodMessage(BMessage *) -00014f9c g F .text 0000010f InputServer::HandleGetSetMouseType(BMessage *, BMessage *) -00016008 g F .text 0000001d InputServer::EventLoopRunning(void) -00015b1c g F .text 0000003e InputServer::UnlockMethodQueue(void) -0001612c g F .text 000000cf InputServer::StartStopDevices(char const *, input_device_type, bool) -000157f8 g F .text 00000323 InputServer::EventLoop(void *) -00018834 g F .text 00000157 MethodReplicant::SendToInputServer(BMessage *) -0001b000 g O .rodata 00000022 kInputServerSignature -00015690 g F .text 00000165 InputServer::HandleSetMethod(BMessage *) -00016578 g F .text 00000009 BInputServerDevice::Control(char const *, void *, unsigned long, BMessage *) -00024620 g O .bss 00000008 BInputServerFilter type_info node -000166b0 g F .text 0000002f BInputServerFilter::~BInputServerFilter(void) -00014c3c g F .text 0000010f InputServer::HandleGetSetKeyRepeatDelay(BMessage *, BMessage *) -00013ce0 g F .text 000001ea InputServer::MethodizeEvents(BList *, bool) -0001cd35 g O .data 00000001 InputServer::sEventLoopRunning -00015bec g F .text 00000053 InputServer::HandleGetKeyInfo(BMessage *, BMessage *) -00015b5c g F .text 00000048 InputServer::LockMethodQueue(void) -00016834 g F .text 0000002d BInputServerMethod::~BInputServerMethod(void) -00016494 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice1(void) -0001631c g F .text 00000026 InputServer::ReadyToRun(void) -0001fd40 w O .data 00000040 BInputServerFilter virtual table -00015d8c g F .text 00000077 InputServer::SetNextMethod(bool) -0001306c g F .text 000002f2 InputServer::InitKeyboardMouseStates(void) -00013360 g F .text 000000ff InputServer::InitMethods(void) -00019ddc w F .text 00000045 InputServer::~InputServer(void) -0001662c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter1(void) -0001649c g F .text 0000002f BInputServerDevice::StopMonitoringDevice(char const *) -0001fb60 w O .data 00000180 InputServer virtual table -00015ba4 g F .text 00000045 InputServer::HandleGetModifiers(BMessage *, BMessage *) -000148e0 g F .text 000001ef InputServer::HandleSetModifierKey(BMessage *, BMessage *) -000165a8 g F .text 00000009 BInputServerDevice::InitCheck(void) -00013794 g F .text 00000549 InputServer::SanitizeEvents(BList *) -00016710 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod4(void) -000166e0 g F .text 00000023 BInputServerFilter::BInputServerFilter(void) -000167ac g F .text 00000027 BInputServerMethod::SetIcon(unsigned char const *) -00014800 g F .text 000000dd InputServer::HandleSetKeyboardLocks(BMessage *, BMessage *) -00019d98 w F .text 00000041 InputServer type_info function -000165b4 g F .text 0000002f BInputServerDevice::~BInputServerDevice(void) -00016528 g F .text 00000026 BInputServerDevice::UnregisterDevices(input_device_ref **) -000165e4 g F .text 0000002d BInputServerDevice::BInputServerDevice(void) -00014e5c g F .text 0000013f InputServer::HandleGetSetMouseMap(BMessage *, BMessage *) -000135e8 g F .text 000001ab InputServer::DoMouseAcceleration(long *, long *) -00015ec4 g F .text 0000004e InputServer::SetMousePos(long *, long *, long, long) -00015c88 g F .text 00000103 InputServer::SetActiveMethod(_BMethodAddOn_ *) -00019ed8 w F .text 00000041 BInputServerMethod type_info function -0001277c g F .text 000006e5 InputServer::MessageReceived(BMessage *) -000162ec g F .text 0000002e InputServer::EnqueueDeviceMessage(BMessage *) -000167d4 g F .text 00000027 BInputServerMethod::SetName(char const *) -00016624 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter2(void) -00016028 g F .text 0000001d InputServer::SafeMode(void) -00016590 g F .text 00000009 BInputServerDevice::Start(char const *, void *) -00016484 g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice3(void) -00016614 g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter4(void) -00016728 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod1(void) -0001648c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice2(void) -0001cd34 g O .data 00000001 InputServer::sSafeMode -00016698 g F .text 0000000c BInputServerFilter::Filter(BMessage *, BList *) -000144d0 g F .text 0000032e InputServer::DispatchEvents(BList *) -000140dc g F .text 000003f4 InputServer::CacheEvents(BList *) -000124f0 g F .text 0000028b InputServer::InputServer(void) -0001647c g F .text 00000007 BInputServerDevice::_ReservedInputServerDevice4(void) -00016828 g F .text 00000009 BInputServerMethod::MethodActivated(bool) -00016344 g F .text 00000079 InputServer::ArgvReceived(long, char **) -000150ac g F .text 0000010f InputServer::HandleGetSetMouseSpeed(BMessage *, BMessage *) -00013460 g F .text 00000186 InputServer::GetNextEvents(BList *) -000153dc g F .text 00000155 InputServer::HandleSetMousePosition(BMessage *, BMessage *) -0001661c g F .text 00000007 BInputServerFilter::_ReservedInputServerFilter3(void) -00019e68 w F .text 00000035 BInputServerDevice type_info function -00016864 g F .text 00000097 BInputServerMethod::BInputServerMethod(char const *, unsigned char const *) -000164fc g F .text 00000029 BInputServerDevice::EnqueueMessage(BMessage *) -00015fc8 g F .text 0000003f InputServer::InitFilters(void) -000166a4 g F .text 00000009 BInputServerFilter::InitCheck(void) -000167fc g F .text 00000029 BInputServerMethod::EnqueueMessage(BMessage *) -00013ecc g F .text 0000020d InputServer::FilterEvents(BList *) -000161fc g F .text 00000010 InputServer::MethodReplicant(void) const -00015c40 g F .text 00000046 InputServer::HandleGetKeyboardID(BMessage *, BMessage *) -000152cc g F .text 0000010f InputServer::HandleGetSetClickSpeed(BMessage *, BMessage *) -0001659c g F .text 00000009 BInputServerDevice::SystemShuttingDown(void) -0001fd80 w O .data 00000068 BInputServerMethod virtual table -00024728 g O .bss 00000008 BInputServerDevice type_info node -00016730 g F .text 0000007c BInputServerMethod::SetMenu(BMenu const *, BMessenger) -00016048 g F .text 000000e3 InputServer::ControlDevices(char const *, input_device_type, unsigned long, BMessage *) -00015534 g F .text 0000015b InputServer::HandleFocusUnfocusIMAwareView(BMessage *, BMessage *) -00019ea0 w F .text 00000035 BInputServerFilter type_info function -00016718 g F .text 00000007 BInputServerMethod::_ReservedInputServerMethod3(void) -00015f14 g F .text 000000b4 InputServer::SetMousePos(long *, long *, BPoint) -00014d4c g F .text 0000010f InputServer::HandleGetSetKeyRepeatRate(BMessage *, BMessage *) -00014ad0 g F .text 0000016c InputServer::HandleGetSetKeyMap(BMessage *, BMessage *) -00015e04 g F .text 000000bf InputServer::SetMousePos(long *, long *, float, float) -00016634 g F .text 00000061 BInputServerFilter::GetScreenRegion(BRegion *) const diff --git a/docs/develop/servers/registrar/Protocols b/docs/develop/servers/registrar/Protocols deleted file mode 100644 index 4360e6b9b8..0000000000 --- a/docs/develop/servers/registrar/Protocols +++ /dev/null @@ -1,1028 +0,0 @@ -Protocols -========= - -Standard Replies ----------------- - -standard success reply message - -reply: B_REG_SUCCESS - [ ] - -fields: -- : Request-specific fields. - ------------------------------------------------------------------------ - -standard error reply message - -reply: B_REG_ERROR - "error": B_INT32_TYPE - [ "error_description": B_STRING_TYPE ] - [ ] - -fields: -- "error": The error code (a status_t). -- "error_description": Optional human readable description. -- : Request-specific fields. - ------------------------------------------------------------------------ - -standard general result reply message - -reply: B_REG_RESULT - "result": B_INT32_TYPE - [ "result_description": B_STRING_TYPE ] - [ ] - -fields: -- "result": The result value (a status_t). -- "result_description": Optional human readable description. -- : Request-specific fields. - ------------------------------------------------------------------------ - - -General Requests ----------------- - -getting the messengers for MIME, clipboard and disk device management -respectively - -target: registrar app looper (preferred handler) -message: B_REG_GET_MIME_MESSENGER/B_REG_GET_CLIPBOARD_MESSENGER - /B_REG_GET_DISK_DEVICE_MESSENGER -reply: standard success - "messenger": B_MESSENGER_TYPE -on error: - B_NO_REPLY (fatal) - - standard error (fatal) - -reply fields: -- "messenger": The requested messenger. - ------------------------------------------------------------------------ - -shut down - -target: registrar app looper (preferred handler) -message: B_REG_SHUT_DOWN - "reboot": B_BOOL_TYPE - "confirm": B_BOOL_TYPE - "synchronously": B_BOOL_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error (fatal) - -message fields: -- "reboot": If true, the system reboots instead of turning the power off. -- "confirm": If true, the user will be asked to confirm to shut down the system. -- "synchronously": If true, the request sender gets a reply only, if the - shutdown process fails. Otherwise the reply will be sent - right before asking the user for confirmation (if desired). - ------------------------------------------------------------------------ - - -Roster Requests ---------------- - -app registration (BRoster::AddApplication()) - -target: roster -message: B_REG_ADD_APP - "signature": B_MIME_STRING_TYPE - "ref": B_REF_TYPE - "flags": B_UINT32_TYPE - "team": B_INT32_TYPE - "thread": B_INT32_TYPE - "port": B_INT32_TYPE - "full_registration": B_BOOL_TYPE -reply: standard success - [ "token": B_INT32_TYPE ] - [ "other_team": B_INT32_TYPE ] -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "signature": The application signature. -- "ref": An entry_ref to the application executable. -- "flags": The application flags. -- "team": The application team (team_id). -- "port": The app looper port (port_id). -- "full_registration": Whether full or pre-registration is requested. - -reply fields: -- "token": If pre-registration was requested (uint32). Unique token to be - passed to BRoster::SetThreadAndTeam(). -- "other_team": For single/exclusive launch applications that are launched - the second time. The team ID of the already running instance (team_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_ENTRY_NOT_FOUND: The entry_ref doesn't refer to a file. - - B_ALREADY_RUNNING: For single/exclusive launch applications - that are launched the second time. - - B_REG_ALREADY_REGISTERED: The team is already registered. - - ... - ------------------------------------------------------------------------ - -app registration (BRoster::CompleteRegistration()) - -target: roster -message: B_REG_COMPLETE_REGISTRATION - "team": B_INT32_TYPE - "thread": B_INT32_TYPE - "port": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The application team (team_id). -- "thread": The application looper thread (thread_id). -- "port": The app looper port (port_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_REG_APP_NOT_PRE_REGISTERED: The team is unknown to the roster or the - application is already fully registered. - - ... - ------------------------------------------------------------------------ - -app registration check (BRoster::IsAppRegistered()) - -target: roster -message: B_REG_IS_APP_REGISTERED - "ref": B_REF_TYPE - ( "team": B_INT32_TYPE - | "token": B_INT32_TYPE ) -reply: standard success - "registered": B_BOOL_TYPE - "pre-registered": B_BOOL_TYPE - [ "app_info": flattened app_info ] -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "ref": An entry_ref to the application executable. -- "team": The application team (team_id). -- "token": The application's preregistration token. - -reply fields: -- "registered": true, if the app is (pre-)registered, false otherwise. -- "pre-registered": true, if the app is pre-registered, false otherwise. -- "app_info": Flattened app info, if the app is known (i.e. (pre-)registered). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_ENTRY_NOT_FOUND: The entry_ref doesn't refer to a file. - - ... - ------------------------------------------------------------------------ - -pre-registrated app unregistration (BRoster::RemovePreRegApp()) - -target: roster -message: B_REG_REMOVE_PRE_REGISTERED_APP - "token": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "token": The token BRoster::AddApplication() returned (uint32). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_REG_APP_NOT_PRE_REGISTERED: The token does not identify a pre-registered - application. - - ... - ------------------------------------------------------------------------ - -app unregistration (BRoster::RemoveApp()) - -target: roster -message: B_REG_REMOVE_APP - "team": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The application team (team_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_REG_APP_NOT_REGISTERED: The team is unknown to the roster. - - ... - ------------------------------------------------------------------------ - -app pre-registration, set thread/team (BRoster::SetThreadAndTeam()) - -target: roster -message: B_REG_SET_THREAD_AND_TEAM - "token": B_INT32_TYPE - "team": B_INT32_TYPE - "thread": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "token": The token BRoster::AddApplication() returned (uint32). -- "team": The application team (team_id). -- "thread": The application looper thread (thread_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_REG_APP_NOT_PRE_REGISTERED: The token does not identify a pre-registered - application. - - ... - ------------------------------------------------------------------------ - -app registration, change app signature (BRoster::SetSignature()) - -target: roster -message: B_REG_SET_SIGNATURE - "team": B_INT32_TYPE - "signature": B_STRING_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The application team (team_id). -- "signature": The application's new signature. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_REG_APP_NOT_REGISTERED: The team does not identify a registered - application. - - ... - ------------------------------------------------------------------------ - -get an app info (BRoster::Get{Running,Active,}AppInfo()) - -target: roster -message: B_REG_GET_APP_INFO - [ "team": B_INT32_TYPE - | "ref": B_REF_TYPE - | "signature": B_STRING_TYPE ] -reply: standard success - "app_info": B_REG_APP_INFO_TYPE -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The application team (team_id). -- "ref": An entry_ref to the application executable. -- "signature": The application signature. -- If both are omitted the active application is referred to. - -reply fields: -- "app_info": The requested app_info (flat_app_info). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_BAD_TEAM_ID: The supplied team ID does not identify a registered - application. - - B_ERROR: - - An entry_ref or a signature has been supplied and no such application - is currently running. - - No team ID has been supplied and currently there is no active - application. - - ... - ------------------------------------------------------------------------ - -get an app list (BRoster::GetAppList()) - -target: roster -message: B_REG_GET_APP_LIST - [ "signature": B_STRING_TYPE ] -reply: standard success - "teams": B_INT32_TYPE[] -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "signature": The application signature. - -reply fields: -- "teams": The requested list of team IDs (team_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -activate an app (BRoster::ActivateApp()) - -target: roster -message: B_REG_ACTIVATE_APP - "team": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The application team (team_id). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_BAD_TEAM_ID: The supplied team ID does not identify a registered - application. - - ... - ------------------------------------------------------------------------ - -broadcast a message (BRoster::Broadcast()) - -target: roster -message: B_REG_BROADCAST - "team": B_INT32_TYPE - "message": B_MESSAGE_TYPE - "reply_target": B_MESSENGER_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": The requesting team (team_id). -- "message": The message to be broadcast. -- "reply_target": The reply target for the message. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -start roster watching (BRoster::StartWatching()) - -target: roster -message: B_REG_START_WATCHING - "target": B_MESSENGER_TYPE - "events": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "target": The target the event messages shall be sent to. -- "events": Specifies the events the caller is interested in (uint32). - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -stop roster watching (BRoster::StopWatching()) - -target: roster -message: B_REG_STOP_WATCHING - "target": B_MESSENGER_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "target": The target that shall not longer receive any event messages. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - - -MIME Database Requests ----------------------- - -install a mime type (BMimeType::Install()) - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_INSTALL - "type": B_STRING_TYPE -reply: standard general result - -message fields: -- "type": The mime type - -reply fields: -- "result": - - B_OK: success - - B_FILE_EXISTS: the type is already installed - - ... - ------------------------------------------------------------------------ - -remove a mime type (BMimeType::Delete()) - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_DELETE - "type": B_STRING_TYPE -reply: standard general result - -message fields: -- "type": The mime type - -reply fields: -- "result": - - B_OK: success - - B_ENTRY_NOT_FOUND: the type was not found - - (other error code): failure - ------------------------------------------------------------------------ - -set a specific attribute of a mime type (BMimeType::Set*()), -installing if necessary - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_SET_PARAM - "type": B_STRING_TYPE - "which": B_INT32_TYPE - [ additional fields depending upon the "which" field (see below) ] - -reply: standard general result - -message fields: -- "type": The mime type -- "which": Which attribute to set. May be one of the following: - - "which" additional message fields field comments - ------------------------- ---------------------------- -------------------------- - B_REG_MIME_ICON: "icon data": B_RAW_TYPE, B_CMAP8 bitmap data only - "icon size": B_INT32_TYPE B_{MINI,LARGE}_ICON or -1 for flat vector icon data - B_REG_MIME_PREFERRED_APP: "signature": B_STRING_TYPE, - "app verb": B_INT32_TYPE - B_REG_MIME_ATTR_INFO: "attr info": B_MESSAGE_TYPE - B_REG_MIME_FILE_EXTENSIONS: "extensions": B_MESSAGE_TYPE - B_REG_MIME_DESCRIPTION: "long": B_BOOL_TYPE, - "description": B_STRING_TYPE - B_REG_MIME_SNIFFER_RULE: "sniffer rule": B_STRING_TYPE - B_REG_MIME_APP_HINT: "app hint": B_REF_TYPE - B_REG_MIME_ICON_FOR_TYPE "file type": B_STRING_TYPE, - "icon data": B_RAW_TYPE, - "icon size": B_INT32_TYPE - B_REG_MIME_SUPPORTED_TYPES: "types": B_MESSAGE_TYPE - -reply fields: -- "result": - - B_OK: success - - (error code): failure - ------------------------------------------------------------------------ - -delete a specific attribute of a mime type (BMimeType::Delete*()), - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_DELETE_PARAM - "type": B_STRING_TYPE - "which": B_INT32_TYPE - [ additional fields depending upon the "which" field (see below) ] - -reply: standard general result - -message fields: -- "type": The mime type -- "which": Which attribute to delete. May be one of the following: - - "which" additional message fields field comments - ------------------------- ---------------------------- -------------------------- - B_REG_MIME_ICON: "icon size": B_INT32_TYPE B_{MINI,LARGE}_ICON or -1 for vector icon data - B_REG_MIME_PREFERRED_APP: "app verb": B_INT32_TYPE - B_REG_MIME_ATTR_INFO: - B_REG_MIME_FILE_EXTENSIONS: - B_REG_MIME_DESCRIPTION: "long": B_BOOL_TYPE, - B_REG_MIME_SNIFFER_RULE: - B_REG_MIME_APP_HINT: - B_REG_MIME_ICON_FOR_TYPE "file type": B_STRING_TYPE, - "icon size": B_INT32_TYPE - B_REG_MIME_SUPPORTED_TYPES: - -reply fields: -- "result": - - B_OK: success - - B_ENTRY_NOT_FOUND: no such attribute exists, or the type is not installed - - (other error code): failure - ------------------------------------------------------------------------ - -subscribe a BMessenger to the MIME monitor service (BMimeType::StartWatching()) - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_START_WATCHING - "target": B_MESSENGER_TYPE -reply: standard general result - -message fields: -- "target": The BMessenger subscribing to the monitor service - -reply fields: -- "result": - - B_OK: success - - (error code): failure - ------------------------------------------------------------------------ - -unsubscribe a BMessenger from the MIME monitor service (BMimeType::StopWatching()) - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_STOP_WATCHING - "target": B_MESSENGER_TYPE -reply: standard general result - -message fields: -- "target": The BMessenger unsubscribing from the monitor service - -reply fields: -- "result": - - B_OK: success - - B_ENTRY_NOT_FOUND: the given BMessenger was not subscribed to the service - - (other error code): failure - ------------------------------------------------------------------------ - -perform an update_mime_info() call - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_UPDATE_MIME_INFO - "entry": B_REF_TYPE - "recursive": B_BOOLEAN_TYPE - "synchronous": B_BOOLEAN_TYPE - "force": B_INT32_TYPE -reply: standard general result - -message fields: -- "entry": The base entry to update. -- "recursive": If true and "entry" is a directory, update all entries - below "entry" in the hierarchy. -- "synchronous": If true, the call will block until the operation is - completed. If false, the call will return immediately and the operation - will run asynchronously in another thread. -- "force": Specifies how to handle entries for which a BEOS:TYPE attribute - already exists. Valid values are - B_UPDATE_MIME_INFO_{NO_FORCE, FORCE_KEEP_TYPE, FORCE_UPDATE_ALL}. - -reply fields: -- "result": - - B_OK: The asynchronous update_mime_info() call has been successfully - started (and may still be running). - - (error code): failure - ------------------------------------------------------------------------ - -perform a create_app_meta_mime() call - -target: mime manager (BRoster::fMimeMess) -message: B_REG_MIME_CREATE_APP_META_MIME - "entry": B_REF_TYPE - "recursive": B_BOOLEAN_TYPE - "synchronous": B_BOOLEAN_TYPE - "force": B_INT32_TYPE -reply: standard general result - -message fields: -- "entry": The base entry to update. -- "recursive": If true and "entry" is a directory, update all entries - below "entry" in the hierarchy. -- "synchronous": If true, the call will block until the operation is - completed. If false, the call will return immediately and the operation - will run asynchronously in another thread. -- "force": If != 0, also update entries for which meta app information - already exists. - -reply fields: -- "result": - - B_OK: The asynchronous update_mime_info() call has been successfully - started (and may still be running). - - (error code): failure - ------------------------------------------------------------------------ - -notify the thread manager to perform a clean up run - -target: thread manager/mime manager (MIMEManager::fThreadManager/BRoster::fMimeMess) -message: B_REG_MIME_UPDATE_THREAD_FINISHED -reply: none (message should be sent asynchronously) - ------------------------------------------------------------------------ - - -Message Runner Requests ------------------------ - -message runner registration (BMessageRunner::InitData()) - -target: roster -message: B_REG_REGISTER_MESSAGE_RUNNER - "team": B_INT32_TYPE - "target": B_MESSENGER_TYPE - "message": B_MESSAGE_TYPE - "interval": B_INT64_TYPE - "count": B_INT32_TYPE - "reply_target": B_MESSENGER_TYPE -reply: standard success - "token": B_INT32_TYPE -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "team": ID of the team owning the BMessageRunner (team_id). -- "target": The message target. -- "message": The message to be sent to the target. -- "interval": Period of time before the first message is sent and between - messages (if more than one shall be sent) in microseconds. -- "count": Specifies how many times the message shall be sent. - A value less than 0 for an unlimited number of repetitions. -- "reply_target": Target replies to the delivered message(s) shall be sent to. - -reply fields: -- "token": Unique token identifying the message runner. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -message runner unregistration (BMessageRunner::~BMessageRunner()) - -target: roster -message: B_REG_UNREGISTER_MESSAGE_RUNNER - "token": B_INT32_TYPE -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "token": Unique token identifying the message runner. Returned by the - B_REG_REGISTER_MESSAGE_RUNNER request. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -set message runner parameters (BMessageRunner::SetParams()) - -target: roster -message: B_REG_SET_MESSAGE_RUNNER_PARAMS - "token": B_INT32_TYPE - [ "interval": B_INT64_TYPE ] - [ "count": B_INT32_TYPE ] -reply: standard success -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "token": Unique token identifying the message runner. Returned by the - B_REG_REGISTER_MESSAGE_RUNNER request. -- "interval": Period of time before the first message is sent and between - messages (if more than one shall be sent) in microseconds. -- "count": Specifies how many times the message shall be sent. - A value less than 0 for an unlimited number of repetitions. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -get message runner info (BMessageRunner::InitData()) - -target: roster -message: B_REG_GET_MESSAGE_RUNNER_INFO - "token": B_INT32_TYPE -reply: standard success - "interval": B_INT64_TYPE - "count": B_INT32_TYPE -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "token": Unique token identifying the message runner. Returned by the - B_REG_REGISTER_MESSAGE_RUNNER request. - -reply fields: -- "interval": Period of time before the first message is sent and between - messages (if more than one shall be sent) in microseconds. -- "count": Specifies how many times the message still has to be sent. - A value less than 0 for an unlimited number of repetitions. - -error reply fields: -- "error": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - - -Clipboard Handler Requests --------------------------- - -add new clipboard to system (BClipboard::BClipboard()) - -target: clipboard handler -message: B_REG_ADD_CLIPBOARD - "name": B_STRING_TYPE -reply: standard general result - -message fields: -- "name": Name used to identify the particular clipboard to add - -reply fields: -- "result": - - B_OK: B - - B_BAD_VALUE: name field was not specified in message - ------------------------------------------------------------------------ - -get clipboard write count (BClipboard::GetSystemCount()) - -target: clipboard handler -message: B_REG_GET_CLIPBOARD_COUNT - "name": B_STRING_TYPE -reply: standard general result - "count": B_INT32_TYPE - -message fields: -- "name": Name used to identify the particular clipboard - -reply fields: -- "result": - - B_OK: success - - B_BAD_VALUE: no name / no valid name specified in message -- "count": - - number of times this clipboard has been written to - ------------------------------------------------------------------------ - -start watching clipboard (BClipboard::StartWatching()) - -target: clipboard handler -message: B_REG_CLIPBOARD_START_WATCHING - "name": B_STRING_TYPE - "target": B_MESSENGER_TYPE -reply: standard general result - -message fields: -- "name": Name used to identify the particular clipboard -- "target": Messenger pointing to the target to notify - -reply fields: -- "result": - - B_OK: success - - B_BAD_VALUE: no name / no valid name specified in message - no target specified - ------------------------------------------------------------------------ - -stop watching clipboard (BClipboard::StopWatching()) - -target: clipboard handler -message: B_REG_CLIPBOARD_STOP_WATCHING - "name": B_STRING_TYPE - "target": B_MESSENGER_TYPE -reply: standard general result - -message fields: -- "name": Name used to identify the particular clipboard -- "target": Messenger pointing to the target to remove from the notify list - -reply fields: -- "result": - - B_OK: success - - B_BAD_VALUE: no name / no valid name specified in message - no target specified - ------------------------------------------------------------------------ - -download clipboard data (BClipboard::DownloadFromSystem()) - -target: clipboard handler -message: B_REG_DOWNLOAD_CLIPBOARD - "name": B_STRING_TYPE -reply: standard general result - "data": B_MESSAGE_TYPE - "data source": B_MESSENGER_TYPE - "count": B_INT32_TYPE - -message fields: -- "name": Name used to identify the particular clipboard - -reply fields: -- "result": - - B_OK: success - - B_BAD_VALUE: no name / no valid name specified in message - no target specified -- "data": - - message with Data fields containing the contents of the clipboard -- "data source": - - messenger to the be_app_messenger of the application which last wrote data -- "count": - - number of times this clipboard has been written to - ------------------------------------------------------------------------ - -upload clipboard data (BClipboard::UploadToSystem()) - -target: clipboard handler -message: B_REG_UPLOAD_CLIPBOARD - "name": B_STRING_TYPE - "data": B_MESSAGE_TYPE - "data source": B_MESSENGER_TYPE -reply: standard general result - "count": B_INT32_TYPE - -message fields: -- "name": Name used to identify the particular clipboard -- "data": - - message with Data fields containing the contents of the clipboard -- "data source": - - messenger to the be_app_messenger of the application which last wrote data - -reply fields: -- "result": - - B_OK: success - - B_BAD_VALUE: no name / no valid name specified in message - no target specified -- "count": - - number of times this clipboard has been written to - ------------------------------------------------------------------------ - - -Disk Device Requests --------------------- - -get next disk device - -target: disk device manager -message: B_REG_NEXT_DISK_DEVICE - "cookie": B_INT32_TYPE -reply: standard general result - "device": B_MESSAGE_TYPE - "cookie": B_INT32_TYPE - -message fields: -- "cookie": An iteration cookie. Initially 0. - -reply fields: -- "device": Archived BDiskDevice info. -- "cookie": Next value for the iteration cookie. -- "result": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_ENTRY_NOT_FOUND: Iteration finished. - - ... - ------------------------------------------------------------------------ - -get disk device - -target: disk device manager -message: B_REG_GET_DISK_DEVICE - "device_id": B_INT32_TYPE - | "session_id": B_INT32_TYPE - | "partition_id": B_INT32_TYPE -reply: standard general result - "device": B_MESSAGE_TYPE - -message fields: -- "device_id": ID of the device to be retrieved. -- "session_id": ID of session whose device shall be retrieved. -- "partition_id": ID of partition whose device shall be retrieved. - -reply fields: -- "device": Archived BDiskDevice info. -- "result": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_ENTRY_NOT_FOUND: A device/session/partition with that ID could not - be found. - - ... - ------------------------------------------------------------------------ - -update disk device - -target: disk device manager -message: B_REG_UPDATE_DISK_DEVICE - "device_id": B_INT32_TYPE - | "session_id": B_INT32_TYPE - | "partition_id": B_INT32_TYPE - "change_counter": B_INT32_TYPE - "update_policy": B_INT32_TYPE -reply: standard general result - "up_to_date": B_BOOLEAN_TYPE - [ "device": B_MESSAGE_TYPE ] - -message fields: -- "device_id": ID of the device to be retrieved. -- "session_id": ID of session whose device shall be retrieved. -- "partition_id": ID of partition whose device shall be retrieved. -- "change_counter": Change counter of the object (or device in case of - B_REG_DEVICE_UPDATE_DEVICE_CHANGED update policy) in - question. -- "update_policy": (uint32) - B_REG_DEVICE_UPDATE_CHECK: Check only, if the object is up to date. - B_REG_DEVICE_UPDATE_CHANGED: Update only, if the object has changed. - B_REG_DEVICE_UPDATE_DEVICE_CHANGED: Update, if the device has changed, even - if the partition/session has not. - The latter two have the same semantics, if the object is a device. - -reply fields: -- "up_to_date": true, if the object (and for - B_REG_DEVICE_UPDATE_DEVICE_CHANGED also the device) is already up to date, - false otherwise. -- "device": Archived BDiskDevice info. -- "result": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - B_ENTRY_NOT_FOUND: A device/session/partition with that ID could not - be found. - - ... - ------------------------------------------------------------------------ - -start disk device watching - -target: disk device manager -message: B_REG_DEVICE_START_WATCHING - "target": B_MESSENGER_TYPE - "events": B_INT32_TYPE -reply: standard general result -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "target": The target the event messages shall be sent to. -- "events": Specifies the events the caller is interested in (uint32). -- "result": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ - -stop disk device watching - -target: disk device manager -message: B_REG_DEVICE_STOP_WATCHING - "target": B_MESSENGER_TYPE -reply: standard general result -on error: - B_NO_REPLY (fatal) - - standard error - -message fields: -- "target": The target that shall not longer receive any event messages. -- "result": - - B_BAD_VALUE: A request message field is missing or contains an - invalid value. - - ... - ------------------------------------------------------------------------ diff --git a/docs/develop/servers/registrar/Protocols.rst b/docs/develop/servers/registrar/Protocols.rst new file mode 100644 index 0000000000..9fde50acc8 --- /dev/null +++ b/docs/develop/servers/registrar/Protocols.rst @@ -0,0 +1,1355 @@ +Registrar Protocols +=================== + +Standard Replies +---------------- + +standard success reply message +.............................. + +reply: B_REG_SUCCESS + +- [ ] + +fields: + +- : Request-specific fields. + +standard error reply message +............................ + +reply: B_REG_ERROR + +- "error": B_INT32_TYPE +- [ "error_description": B_STRING_TYPE ] +- [ ] + +fields: + +- "error": The error code (a status_t). +- "error_description": Optional human readable description. +- : Request-specific fields. + + +standard general result reply message +..................................... + +reply: B_REG_RESULT + +- "result": B_INT32_TYPE +- [ "result_description": B_STRING_TYPE ] +- [ ] + +fields: + +- "result": The result value (a status_t). +- "result_description": Optional human readable description. +- : Request-specific fields. + +General Requests +---------------- + +Getting the messengers +...................... + +for MIME, clipboard and disk device management respectively + ++--------------+-------------------------------------------------------+ +| target | registrar app looper (preferred handler) | ++--------------+-------------------------------------------------------+ +| message | - B_REG_GET_MIME_MESSENGER | +| | - B_REG_GET_CLIPBOARD_MESSENGER | +| | - B_REG_GET_DISK_DEVICE_MESSENGER | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "messenger": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error (fatal) | ++--------------+-------------------------------------------------------+ + +reply fields: + +- "messenger": The requested messenger. + +Shut down +......... + ++--------------+-------------------------------------------------------+ +| target | registrar app looper (preferred handler) | ++--------------+-------------------------------------------------------+ +| message | B_REG_SHUT_DOWN | +| | | +| | - "reboot": B_BOOL_TYPE | +| | - "confirm": B_BOOL_TYPE | +| | - "synchronously": B_BOOL_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error (fatal) | ++--------------+-------------------------------------------------------+ + +message fields: + +- "reboot": If true, the system reboots instead of turning the power off. +- "confirm": If true, the user will be asked to confirm to shut down the system. +- "synchronously": If true, the request sender gets a reply only, if the + shutdown process fails. Otherwise the reply will be sent + right before asking the user for confirmation (if desired). + +Roster Requests +--------------- + +App registration (BRoster::AddApplication()) +............................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_ADD_APP | +| | | +| | - "signature": B_MIME_STRING_TYPE | +| | - "ref": B_REF_TYPE | +| | - "flags": B_UINT32_TYPE | +| | - "team": B_INT32_TYPE | +| | - "thread": B_INT32_TYPE | +| | - "port": B_INT32_TYPE | +| | - "full_registration": B_BOOL_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - [ "token": B_INT32_TYPE ] | +| | - [ "other_team": B_INT32_TYPE ] | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "signature": The application signature. +- "ref": An entry_ref to the application executable. +- "flags": The application flags. +- "team": The application team (team_id). +- "port": The app looper port (port_id). +- "full_registration": Whether full or pre-registration is requested. + +reply fields: + +- "token": If pre-registration was requested (uint32). Unique token to be + passed to BRoster::SetThreadAndTeam(). +- "other_team": For single/exclusive launch applications that are launched + the second time. The team ID of the already running instance (team_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an invalid value. + - B_ENTRY_NOT_FOUND: The entry_ref doesn't refer to a file. + - B_ALREADY_RUNNING: For single/exclusive launch applications that are launched the second time. + - B_REG_ALREADY_REGISTERED: The team is already registered. + - ... + +app registration (BRoster::CompleteRegistration()) +.................................................. + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_COMPLETE_REGISTRATION | +| | | +| | - "team": B_INT32_TYPE | +| | - "thread": B_INT32_TYPE | +| | - "port": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The application team (team_id). +- "thread": The application looper thread (thread_id). +- "port": The app looper port (port_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_REG_APP_NOT_PRE_REGISTERED: The team is unknown to the roster or the + application is already fully registered. + - ... + +app registration check (BRoster::IsAppRegistered()) +................................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_IS_APP_REGISTERED | +| | | +| | - "ref": B_REF_TYPE | +| | - ( "team": B_INT32_TYPE | "token": B_INT32_TYPE ) | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "registered": B_BOOL_TYPE | +| | - "pre-registered": B_BOOL_TYPE | +| | - [ "app_info": flattened app_info ] | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "ref": An entry_ref to the application executable. +- "team": The application team (team_id). +- "token": The application's preregistration token. + +reply fields: + +- "registered": true, if the app is (pre-)registered, false otherwise. +- "pre-registered": true, if the app is pre-registered, false otherwise. +- "app_info": Flattened app info, if the app is known (i.e. (pre-)registered). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_ENTRY_NOT_FOUND: The entry_ref doesn't refer to a file. + - ... + +pre-registrated app unregistration (BRoster::RemovePreRegApp()) +............................................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_REMOVE_PRE_REGISTERED_APP | +| | | +| | - "token": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "token": The token BRoster::AddApplication() returned (uint32). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_REG_APP_NOT_PRE_REGISTERED: The token does not identify a pre-registered + application. + - ... + +app unregistration (BRoster::RemoveApp()) +......................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_REMOVE_APP | +| | | +| | - "team": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The application team (team_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_REG_APP_NOT_REGISTERED: The team is unknown to the roster. + - ... + +app pre-registration, set thread/team (BRoster::SetThreadAndTeam()) +................................................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_SET_THREAD_AND_TEAM | +| | | +| | - "token": B_INT32_TYPE | +| | - "team": B_INT32_TYPE | +| | - "thread": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "token": The token BRoster::AddApplication() returned (uint32). +- "team": The application team (team_id). +- "thread": The application looper thread (thread_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_REG_APP_NOT_PRE_REGISTERED: The token does not identify a pre-registered + application. + - ... + +app registration, change app signature (BRoster::SetSignature()) +................................................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_SET_SIGNATURE | +| | | +| | - "team": B_INT32_TYPE | +| | - "signature": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The application team (team_id). +- "signature": The application's new signature. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_REG_APP_NOT_REGISTERED: The team does not identify a registered + application. + - ... + +get an app info (BRoster::Get{Running,Active,}AppInfo()) +........................................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_GET_APP_INFO | +| | | +| | [ "team": B_INT32_TYPE | +| | | "ref": B_REF_TYPE | +| | | "signature": B_STRING_TYPE ] | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "app_info": B_REG_APP_INFO_TYPE | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The application team (team_id). +- "ref": An entry_ref to the application executable. +- "signature": The application signature. +- If both are omitted the active application is referred to. + +reply fields: + +- "app_info": The requested app_info (flat_app_info). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_BAD_TEAM_ID: The supplied team ID does not identify a registered + application. + - B_ERROR: + + - An entry_ref or a signature has been supplied and no such application + is currently running. + - No team ID has been supplied and currently there is no active + application. + + - ... + +get an app list (BRoster::GetAppList()) +....................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_GET_APP_LIST | +| | | +| | - [ "signature": B_STRING_TYPE ] | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "teams": B_INT32_TYPE[] | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "signature": The application signature. + +reply fields: + +- "teams": The requested list of team IDs (team_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +activate an app (BRoster::ActivateApp()) +........................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_ACTIVATE_APP | +| | | +| | "team": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The application team (team_id). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_BAD_TEAM_ID: The supplied team ID does not identify a registered + application. + - ... + +broadcast a message (BRoster::Broadcast()) +.......................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_BROADCAST | +| | | +| | - "team": B_INT32_TYPE | +| | - "message": B_MESSAGE_TYPE | +| | - "reply_target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": The requesting team (team_id). +- "message": The message to be broadcast. +- "reply_target": The reply target for the message. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +start roster watching (BRoster::StartWatching()) +................................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_START_WATCHING | +| | | +| | - "target": B_MESSENGER_TYPE | +| | - "events": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The target the event messages shall be sent to. +- "events": Specifies the events the caller is interested in (uint32). + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +stop roster watching (BRoster::StopWatching()) +.............................................. + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_STOP_WATCHING | +| | | +| | - "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The target that shall not longer receive any event messages. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +MIME Database Requests +---------------------- + +install a mime type (BMimeType::Install()) +.......................................... + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_INSTALL | +| | | +| | - "type": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "type": The mime type + +reply fields: + +- "result": + + - B_OK: success + - B_FILE_EXISTS: the type is already installed + - ... + +remove a mime type (BMimeType::Delete()) +........................................ + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_DELETE | +| | | +| | - "type": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "type": The mime type + +reply fields: + +- "result": + + - B_OK: success + - B_ENTRY_NOT_FOUND: the type was not found + - (other error code): failure + +set a specific attribute of a mime type (BMimeType::Set*()), installing if necessary +.................................................................................... + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_SET_PARAM | +| | | +| | - "type": B_STRING_TYPE | +| | - "which": B_INT32_TYPE | +| | - [ additional fields depending upon the "which" | +| | field (see below) ] | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "type": The mime type +- "which": Which attribute to set. May be one of the following: + ++---------------------------+-------------------------------+-----------------------------------+ +| "which" | additional message fields | field comments | ++===========================+===============================+===================================+ +| B_REG_MIME_ICON | "icon data": B_RAW_TYPE, | B_CMAP8 bitmap data only | +| +-------------------------------+-----------------------------------+ +| | "icon size": B_INT32_TYPE | B_{MINI,LARGE}_ICON or -1 for flat| +| | | vector icon data | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_PREFERRED_APP | "signature": B_STRING_TYPE | | +| +-------------------------------+-----------------------------------+ +| | "app verb": B_INT32_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_ATTR_INFO | "attr info": B_MESSAGE_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_FILE_EXTENSIONS| "extensions": B_MESSAGE_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_DESCRIPTION | "long": B_BOOL_TYPE, | | +| +-------------------------------+-----------------------------------+ +| | "description": B_STRING_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_SNIFFER_RULE | "sniffer rule": B_STRING_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_APP_HINT | "app hint": B_REF_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_ICON_FOR_TYPE | "file type": B_STRING_TYPE, | | +| +-------------------------------+-----------------------------------+ +| | "icon data": B_RAW_TYPE, | | +| +-------------------------------+-----------------------------------+ +| | "icon size": B_INT32_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_SUPPORTED_TYPES| "types": B_MESSAGE_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ + +reply fields: + +- "result": + + - B_OK: success + - (error code): failure + +delete a specific attribute of a mime type (BMimeType::Delete*()), +.................................................................. + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_DELETE_PARAM | +| | | +| | - "type": B_STRING_TYPE | +| | - "which": B_INT32_TYPE | +| | - [ additional fields depending upon the "which" | +| | field (see below) ] | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "type": The mime type +- "which": Which attribute to delete. May be one of the following: + ++---------------------------+-------------------------------+-----------------------------------+ +| "which" | additional message fields | field comments | ++===========================+===============================+===================================+ +| B_REG_MIME_ICON: | "icon size": B_INT32_TYPE | B_{MINI,LARGE}_ICON or -1 for | +| | | vector icon data | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_PREFERRED_APP | "app verb": B_INT32_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_ATTR_INFO | | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_FILE_EXTENSIONS| | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_DESCRIPTION | "long": B_BOOL_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_SNIFFER_RULE | | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_APP_HINT | | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_ICON_FOR_TYPE | "file type": B_STRING_TYPE, | | +| +-------------------------------+-----------------------------------+ +| | "icon size": B_INT32_TYPE | | ++---------------------------+-------------------------------+-----------------------------------+ +| B_REG_MIME_SUPPORTED_TYPES| | | ++---------------------------+-------------------------------+-----------------------------------+ + +reply fields: + +- "result": + + - B_OK: success + - B_ENTRY_NOT_FOUND: no such attribute exists, or the type is not installed + - (other error code): failure + +subscribe a BMessenger to the MIME monitor service (BMimeType::StartWatching()) +............................................................................... + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_START_WATCHING | +| | | +| | "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The BMessenger subscribing to the monitor service + +reply fields: + +- "result": + + - B_OK: success + - (error code): failure + +unsubscribe a BMessenger from the MIME monitor service (BMimeType::StopWatching()) +.................................................................................. + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_STOP_WATCHING | +| | | +| | "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The BMessenger unsubscribing from the monitor service + +reply fields: + +- "result": + + - B_OK: success + - B_ENTRY_NOT_FOUND: the given BMessenger was not subscribed to the service + - (other error code): failure + +perform an update_mime_info() call +.................................. + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_UPDATE_MIME_INFO | +| | | +| | - "entry": B_REF_TYPE | +| | - "recursive": B_BOOLEAN_TYPE | +| | - "synchronous": B_BOOLEAN_TYPE | +| | - "force": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "entry": The base entry to update. +- "recursive": If true and "entry" is a directory, update all entries + below "entry" in the hierarchy. +- "synchronous": If true, the call will block until the operation is + completed. If false, the call will return immediately and the operation + will run asynchronously in another thread. +- "force": Specifies how to handle entries for which a BEOS:TYPE attribute + already exists. Valid values are + B_UPDATE_MIME_INFO_{NO_FORCE, FORCE_KEEP_TYPE, FORCE_UPDATE_ALL}. + +reply fields: + +- "result": + + - B_OK: The asynchronous update_mime_info() call has been successfully + started (and may still be running). + - (error code): failure + +perform a create_app_meta_mime() call +..................................... + ++--------------+-------------------------------------------------------+ +| target | mime manager (BRoster::fMimeMess) | ++--------------+-------------------------------------------------------+ +| message | B_REG_MIME_CREATE_APP_META_MIME | +| | | +| | - "entry": B_REF_TYPE | +| | - "recursive": B_BOOLEAN_TYPE | +| | - "synchronous": B_BOOLEAN_TYPE | +| | - "force": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "entry": The base entry to update. +- "recursive": If true and "entry" is a directory, update all entries + below "entry" in the hierarchy. +- "synchronous": If true, the call will block until the operation is + completed. If false, the call will return immediately and the operation + will run asynchronously in another thread. +- "force": If != 0, also update entries for which meta app information + already exists. + +reply fields: + +- "result": + + - B_OK: The asynchronous update_mime_info() call has been successfully + started (and may still be running). + - (error code): failure + +notify the thread manager to perform a clean up run +................................................... + ++--------------+-----------------------------------------------------------------------------+ +| target | thread manager/mime manager (MIMEManager::fThreadManager/BRoster::fMimeMess)| ++--------------+-----------------------------------------------------------------------------+ +| message | B_REG_MIME_UPDATE_THREAD_FINISHED | ++--------------+-----------------------------------------------------------------------------+ +| reply | none (message should be sent asynchronously) | ++--------------+-----------------------------------------------------------------------------+ + +Message Runner Requests +----------------------- + +message runner registration (BMessageRunner::InitData()) +........................................................ + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_REGISTER_MESSAGE_RUNNER | +| | | +| | - "team": B_INT32_TYPE | +| | - "target": B_MESSENGER_TYPE | +| | - "message": B_MESSAGE_TYPE | +| | - "interval": B_INT64_TYPE | +| | - "count": B_INT32_TYPE | +| | - "reply_target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "token": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| on error: | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "team": ID of the team owning the BMessageRunner (team_id). +- "target": The message target. +- "message": The message to be sent to the target. +- "interval": Period of time before the first message is sent and between + messages (if more than one shall be sent) in microseconds. +- "count": Specifies how many times the message shall be sent. + A value less than 0 for an unlimited number of repetitions. +- "reply_target": Target replies to the delivered message(s) shall be sent to. + +reply fields: + +- "token": Unique token identifying the message runner. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +message runner unregistration (BMessageRunner::~BMessageRunner()) +................................................................. + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message: | B_REG_UNREGISTER_MESSAGE_RUNNER | +| | | +| | - "token": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error: | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "token": Unique token identifying the message runner. Returned by the + B_REG_REGISTER_MESSAGE_RUNNER request. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +set message runner parameters (BMessageRunner::SetParams()) +........................................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message | B_REG_SET_MESSAGE_RUNNER_PARAMS | +| | | +| | - "token": B_INT32_TYPE | +| | - [ "interval": B_INT64_TYPE ] | +| | - [ "count": B_INT32_TYPE ] | ++--------------+-------------------------------------------------------+ +| reply | standard success | ++--------------+-------------------------------------------------------+ +| on error: | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "token": Unique token identifying the message runner. Returned by the + B_REG_REGISTER_MESSAGE_RUNNER request. +- "interval": Period of time before the first message is sent and between + messages (if more than one shall be sent) in microseconds. +- "count": Specifies how many times the message shall be sent. + A value less than 0 for an unlimited number of repetitions. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +get message runner info (BMessageRunner::InitData()) +.................................................... + ++--------------+-------------------------------------------------------+ +| target | roster | ++--------------+-------------------------------------------------------+ +| message: | B_REG_GET_MESSAGE_RUNNER_INFO | +| | | +| | - "token": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard success | +| | | +| | - "interval": B_INT64_TYPE | +| | - "count": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| on error: | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "token": Unique token identifying the message runner. Returned by the + B_REG_REGISTER_MESSAGE_RUNNER request. + +reply fields: + +- "interval": Period of time before the first message is sent and between + messages (if more than one shall be sent) in microseconds. +- "count": Specifies how many times the message still has to be sent. + A value less than 0 for an unlimited number of repetitions. + +error reply fields: + +- "error": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +Clipboard Handler Requests +-------------------------- + +add new clipboard to system (BClipboard::BClipboard()) +...................................................... + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_ADD_CLIPBOARD | +| | | +| | - "name": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard to add + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: name field was not specified in message + +get clipboard write count (BClipboard::GetSystemCount()) +........................................................ + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_GET_CLIPBOARD_COUNT | +| | | +| | - "name": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "count": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: no name / no valid name specified in message + +- "count": + + - number of times this clipboard has been written to + +start watching clipboard (BClipboard::StartWatching()) +...................................................... + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_CLIPBOARD_START_WATCHING | +| | | +| | - "name": B_STRING_TYPE | +| | - "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard +- "target": Messenger pointing to the target to notify + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: no name / no valid name specified in message + no target specified + +stop watching clipboard (BClipboard::StopWatching()) +.................................................... + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_CLIPBOARD_STOP_WATCHING | +| | | +| | - "name": B_STRING_TYPE | +| | - "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard +- "target": Messenger pointing to the target to remove from the notify list + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: no name / no valid name specified in message / no target specified + +download clipboard data (BClipboard::DownloadFromSystem()) +.......................................................... + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_DOWNLOAD_CLIPBOARD | +| | | +| | "name": B_STRING_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "data": B_MESSAGE_TYPE | +| | - "data source": B_MESSENGER_TYPE | +| | - "count": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: no name / no valid name specified in message + no target specified + +- "data": message with Data fields containing the contents of the clipboard +- "data source": messenger to the be_app_messenger of the application which last wrote data +- "count": number of times this clipboard has been written to + +upload clipboard data (BClipboard::UploadToSystem()) +.................................................... + ++--------------+-------------------------------------------------------+ +| target | clipboard handler | ++--------------+-------------------------------------------------------+ +| message | B_REG_UPLOAD_CLIPBOARD | +| | | +| | "name": B_STRING_TYPE | +| | "data": B_MESSAGE_TYPE | +| | "data source": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "count": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ + +message fields: + +- "name": Name used to identify the particular clipboard +- "data": message with Data fields containing the contents of the clipboard +- "data source": messenger to the be_app_messenger of the application which last wrote data + +reply fields: + +- "result": + + - B_OK: success + - B_BAD_VALUE: no name / no valid name specified in message / no target specified + +- "count": + + - number of times this clipboard has been written to + +Disk Device Requests +-------------------- + +get next disk device +.................... + ++--------------+-------------------------------------------------------+ +| target | disk device manager | ++--------------+-------------------------------------------------------+ +| message | B_REG_NEXT_DISK_DEVICE | +| | | +| | - "cookie": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "device": B_MESSAGE_TYPE | +| | - "cookie": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ + +message fields: + +- "cookie": An iteration cookie. Initially 0. + +reply fields: + +- "device": Archived BDiskDevice info. +- "cookie": Next value for the iteration cookie. +- "result": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_ENTRY_NOT_FOUND: Iteration finished. + - ... + +get disk device +............... + ++--------------+-------------------------------------------------------+ +| target | disk device manager | ++--------------+-------------------------------------------------------+ +| message | B_REG_GET_DISK_DEVICE | +| | | +| | - "device_id": B_INT32_TYPE | +| | - | "session_id": B_INT32_TYPE | +| | - | "partition_id": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "device": B_MESSAGE_TYPE | ++--------------+-------------------------------------------------------+ + +message fields: + +- "device_id": ID of the device to be retrieved. +- "session_id": ID of session whose device shall be retrieved. +- "partition_id": ID of partition whose device shall be retrieved. + +reply fields: + +- "device": Archived BDiskDevice info. +- "result": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_ENTRY_NOT_FOUND: A device/session/partition with that ID could not + be found. + - ... + +update disk device +.................. + ++--------------+-------------------------------------------------------+ +| target | disk device manager | ++--------------+-------------------------------------------------------+ +| message | B_REG_UPDATE_DISK_DEVICE | +| | | +| | - "device_id": B_INT32_TYPE | +| | - | "session_id": B_INT32_TYPE | +| | - | "partition_id": B_INT32_TYPE | +| | - "change_counter": B_INT32_TYPE | +| | - "update_policy": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | +| | | +| | - "up_to_date": B_BOOLEAN_TYPE | +| | - [ "device": B_MESSAGE_TYPE ] | ++--------------+-------------------------------------------------------+ + +message fields: + +- "device_id": ID of the device to be retrieved. +- "session_id": ID of session whose device shall be retrieved. +- "partition_id": ID of partition whose device shall be retrieved. +- "change_counter": Change counter of the object (or device in case of + B_REG_DEVICE_UPDATE_DEVICE_CHANGED update policy) in question. +- "update_policy": (uint32) + + - B_REG_DEVICE_UPDATE_CHECK: Check only, if the object is up to date. + - B_REG_DEVICE_UPDATE_CHANGED: Update only, if the object has changed. + - B_REG_DEVICE_UPDATE_DEVICE_CHANGED: Update, if the device has changed, even + if the partition/session has not. + + The latter two have the same semantics, if the object is a device. + +reply fields: + +- "up_to_date": true, if the object (and for + B_REG_DEVICE_UPDATE_DEVICE_CHANGED also the device) is already up to date, + false otherwise. +- "device": Archived BDiskDevice info. +- "result": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - B_ENTRY_NOT_FOUND: A device/session/partition with that ID could not + be found. + - ... + +start disk device watching +.......................... + ++--------------+-------------------------------------------------------+ +| target | disk device manager | ++--------------+-------------------------------------------------------+ +| message | B_REG_DEVICE_START_WATCHING | +| | | +| | - "target": B_MESSENGER_TYPE | +| | - "events": B_INT32_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The target the event messages shall be sent to. +- "events": Specifies the events the caller is interested in (uint32). +- "result": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... + +stop disk device watching +......................... + ++--------------+-------------------------------------------------------+ +| target | disk device manager | ++--------------+-------------------------------------------------------+ +| message | B_REG_DEVICE_STOP_WATCHING | +| | | +| | - "target": B_MESSENGER_TYPE | ++--------------+-------------------------------------------------------+ +| reply | standard general result | ++--------------+-------------------------------------------------------+ +| on error | - B_NO_REPLY (fatal) | +| | - standard error | ++--------------+-------------------------------------------------------+ + +message fields: + +- "target": The target that shall not longer receive any event messages. +- "result": + + - B_BAD_VALUE: A request message field is missing or contains an + invalid value. + - ... diff --git a/src/add-ons/kernel/file_systems/googlefs/google-ext-search.html b/src/add-ons/kernel/file_systems/googlefs/google-ext-search.html deleted file mode 100644 index 204055098a..0000000000 --- a/src/add-ons/kernel/file_systems/googlefs/google-ext-search.html +++ /dev/null @@ -1,140 +0,0 @@ -Google Search: google api help "frequently asked" -plop - -
Go to Google Home  
Web    Images    GroupsNew!    News    Froogle    more »
  
  Advanced Search
  Preferences    
- -
 Web Results 1 - 50 of about 12,800 English pages over the past 3 months for google api help "frequently asked" -plop. (0.40 seconds) 
 
    Sponsored Links
Google Help
Better Understand Your Results &
Learn Fun Facts Too. Get More Info!
www.GoogleStore.com
See your message here...

Google Web APIs - FAQ
... a custom Java client library, documentation on how to use the ... You can find it at -http://api.google.com/GoogleSearch.wsdl ... need to get started is in googleapi.jar ... -
www.google.com/apis/api_faq.html - 29k - Cached - Similar pages

SEO Count - Keyword Ranking Tool - Frequently Asked Questions
Frequently Asked Questions. ... that Google only indexes the www version to help increase -Page ... Since the Google API provides results for UTF-8 Encoding we are able ... -
www.seocount.com/faq.php - 16k - Cached - Similar pages

eBay Hacks - Frequently Asked Questions
... If you need help getting started with eBay, you'd ... is concerned with programming and -the eBay API; that leaves ... 5.36934319 10 41 Joules, as reported by Google ... -
www.ebayhacks.com/exec/show/book_faq - 8k - 5 Dec 2004 - Cached - Similar pages

Free SOAP Resources, freeprogrammingresources.com
... The Google API is used as an example. ... Tutorials, Links FAQs. ... This page explains how -to get started editing the home page of your Manila site using SOAP to make ... -
www.freeprogrammingresources.com/soap.html - Similar pages

FAQ: SEO Search Engine Optimization Frequently Asked Questions
... come from the Top25Web.com server, and it is using the Google API which was recently -made available by Google. ... Post a message in our forums for more help! ... -
www.top25web.com/faq.html - 15k - Cached - Similar pages

Among Other Things Google API Cocoa framework
... to be using the Google API for something ... NetBSD/dreamcast NetBSD/dreamcast: How to -use NetBSD/dreamcast NetBSD/dreamcast Frequently Asked Questions The ... -
interalia.org/archives/2003/ 03/24/google-api-cocoa-framework - 48k - Cached - Similar pages

Google Guide: Useful Links
... www.googleguide.com/searchLeader.html; Google's Online Help: Google Help Central - -www.google.com/help/; ... Google Web API - www.google.com/apis/ API stands ... -
www.googleguide.com/links.html - 12k - 6 Dec 2004 - Cached - Similar pages

FAQ: Very Frequently Asked Questions (with answers) v1.29
... some of the questions that are most frequently asked in comp ... Google search: -<URL:http://groups.google.com/groups ... URLs contain information on how to reinstate ... -
www.codecomments.com/Clipper/message320018.html - 23k - Cached - Similar pages

comp.lang.prolog Frequently Asked Questions
... For details on how to join or send in contributions, check ... readers who would be glad -to help people making a ... Yes, there are: Google Groups has archives of news ... -
www.codecomments.com/Prolog/message321541.html - 42k - Cached - Similar pages
[ More results from www.codecomments.com ]

Frequently Asked Questions
... Frequently Asked Questions. ... Since the API is entirely modular, we are looking for -people who can help fix bugs or add enhancements to the project. ... -
open.echomine.org/cowiki/20.html - 36k - Cached - Similar pages

Chat11.com: SEM - Paid Inclusion Doesn't Seem To Be Helping
... Google, ... I Thought Paid Inclusion Would Help, So Why Are My Pages Not Ranked Better? ... -Our Tutorial About How To Increase Visitors To Your Website. ... -
www.chat11.com/ SEM_-_Paid_Inclusion_Doesn't_Seem_To_Be_Helping - 17k - Cached - Similar pages

Data Transformation Services for SQL Server 2005: Frequently Asked ...
... Tuesday, November 23, 2004. .: Home Articles/Tutorials SQL_Server : Data Transformation -Services for SQL Server 2005: Frequently Asked Design Questions. ... -
www.wwwcoder.com/main/parentid/ 191/site/3373/68/default.aspx - 47k - Cached - Similar pages

Programming Articles on webservices.xml.com
... month's XML Endpoints column, Rich Salz explains how to process SOAP ... Google's Gaffe. -By Paul Prescod Paul Prescod explains why moving its API to use ... -
webservices.xml.com/programming/ - 38k - 5 Dec 2004 - Cached - Similar pages

HTML Help FAQs
... This is a nice site found using Google: ... Borland Delphi and HH. Free code examples -show you how to program the HTML Help API via Borland Delphi. ... -
www.helpware.net/FAR/far_faq.htm - 101k - 5 Dec 2004 - Cached - Similar pages

Ruminations
... Frequently Asked Questions, Getting Started with Radio UserLand, Tips, and Tutorials. ... -Using the Google API with Radio and Frontier - How to make requests ... -
ruminations.weblogger.com/ - 27k - 5 Dec 2004 - Cached - Similar pages

Google launches its Deskbar API
... a big difference in your rankings and our most popular ** How To ** section The ... Deskbar -API can be found here: http://deskbar.google.com/help/api/index.html ... -
news-01.rankforsales.com/news-bf/889-seo-nov-22-04.html - 18k - 6 Dec 2004 - Cached - Similar pages

Java FAQ - Frequently Asked Questions
... Search google. ... The JAI API is the subject of discussion in this Sun sponsored mailing ... -Java FAQ is written and maintained by Andrew Thompson, with help from the ... -
www.physci.org/codes/javafaq.jsp - 53k - Cached - Similar pages

Frequently Asked Questions - comp.lang.java.gui
... first document has requested a notice that he is not a help desk for ... 7.10 Java 3D -API. ... see news:comp.lang.java.3d http://groups.google.com/groups?group=comp.lang ... -
www.physci.org/guifaq.jsp - 44k - Cached - Similar pages

GoogleDuel - About
... Asked Questions (FAQ) An old Frequently Asked Questions list ... sample source code which -illustrates how to use the ... SOAP library to call the Google API from PHP. ... -
www.googleduel.com/about.php - 12k - Cached - Similar pages

Search engine articles, tools, links and resources
... Search Engine Help by Highrankings Search Engine Features Chart ... top Guide to frames -usage How to Optimize a ... Enumeration Google Count - uses Google API Go Rank ... -
www.bearcanyonseo.com/tips_links.html - 29k - Cached - Similar pages

OpenOffice.org FAQ
... Most Frequently Asked Questions On using OpenOffice.org software in ... printing with -the binaries, the help system, licensing ... API FAQ Questions and answers on the ... -
www.openoffice.org/faq.html - 10k - Cached - Similar pages

hey Google - don't auto-update my toolbar!
Google Toolbar, Desktop Search, and API Topics. ... Google, there is absolutely no need -for this. ... Asked Questions section of the toolbar help: http://toolbar.google ... -
www.webmasterworld.com/forum80/457-9-10.htm - Similar pages

hey Google - don't auto-update my toolbar!
Google Toolbar, Desktop Search, and API Topics. ... then the very first link is to the -toolbar help page. ... If Google is willing to support use of the toolbar without ... -
www.webmasterworld.com/forum80/457-10-10.htm - Similar pages
[ More results from www.webmasterworld.com ]

Michel Olagnon's Fortran 90 List
... programs and Microsoft Windows Open Database Connectivity (ODBC) API. ... 3.7 - Other -places for Help on Fortran 90. ... ftp.cs.unm.edu; Free Software; How to get Fortran ... -
www.kcl.ac.uk/kis/support/cc/fortran/engfaq.html - 56k - Cached - Similar pages

Frequently Asked Questions - Confluence
... exporting, searchable attachments, a comprehensive remote API, easy installation ... -starting up to tell it how to use its ... If you need help with a particular server ... -
confluence.atlassian.com/ display/DOC/Frequently+Asked+Questions - 35k - 5 Dec 2004 - Cached - Similar pages

Frequently Asked Questions - Confluence
... I figured-out how to add an inline image. ... page hierachies, page subscription, online -help, WebDAV file storage, a more comprehensive remote API... ... -
confluence.atlassian.com/display/DOC/ Frequently+Asked+Questions?focusedCommentId=11067 - 72k - Cached - Similar pages
[ More results from confluence.atlassian.com ]

Bookmarks for bradg@videotron.ca
... The Mother of All Search Engines Google SEARCH.COM ... J2EE API Java(TM) SE Platform -Documentation Servlets ... Franck Allimant - Accueil (Win JDK Help Files) Getting ... -
pages.videotron.com/gbradet/home_bm.htm - 30k - Cached - Similar pages

Resources for Java server-side developers: CLDC - Bluetooth API ...
... Applications by Qusay H. Mahmoud This two-part series of articles will show you -how to use J2ME ... Home > J2ME Technologies > CLDC - Bluetooth API (JSR-82). Google, ... -
www.java201.com/resources/browse/126-all.html - 13k - Cached - Similar pages

Vivsimo // Frequently Asked Questions
... just a small sampling of who we can help: Researchers; Support ... well we work on top -of the Google Appliance ... delivered as aC software library with an API; they run ... -
vivisimo.com/html/faq - 31k - Cached - Similar pages

DataPower: Technical Resources
... Headers DataPower chief security architect Rich Salz explains how to process SOAP ... -of WSDL, with particular reference to the new Google web services API. ... -
www.datapower.com/xmldev/tech_resources.html - 19k - 5 Dec 2004 - Cached - Similar pages

Search Results | MySmartChannels
... Search Google, ... MySmartChannels I agree that actually trying out the different SQL -functions on a computer will help with the ... Is there an API to MySmartChannels? ... -
myst-technology.com/mysmartchannels/ public/search?q=mysmartchannels&scheme=standalone - 101k - Cached - Similar pages

Macromedia -UltraDevTechNotes:UltraDev Technical FAQ (Frequently ...
... Printable instructions on how to create objects and server behaviors using UltraDev's -JavaScript API are available ... Search powered by Powered by Google. -
www.macromedia.com/support/ ultradev/ts/documents/ultradev_faq.htm - 28k - Cached - Similar pages

Mensniche.com Forum - Main Forum
... SG Forum - Great Resource; need help; PPC Results; 404 Traffic; www.volume ... Meta Tags -Optimization; Pre-Sell; Google PageRank, & How to Get It; Nice Google API tool ... -
mensniche.com/forum/archive/index.php/f-2.html - 15k - Cached - Similar pages

Bookshare.org - Book Information
... new Google API, including how to build and modify scripts that can become custom -business applications based on Google. Google Hacks contains 100 tips, tricks ... -
www.bookshare.org/web/SingleTitle. html?submittitleid=19778 - 18k - Cached - Similar pages

Bookshare.org - Books by Author
... advanced search interface and the new Google API, including how ... Google Hacks contains -100 tips, tricks and scripts ... tips, tricks, and tools to help serious Mac ... -
www.bookshare.org/web/ BooksByAuthor.html?author_id=10726 - 29k - Cached - Similar pages

page87 - links
... PHP Implementation of the Google Web API System 26 ... Promotion Google ranking tips -Google's AdWords Advertising Program How to Advertise Responsibly ... -
www.page87.net/links/ - 70k - Cached - Similar pages

April 2002 | iWalt.com
... Its an AppleScript which calls the Google API and gets the top result for your -query. ... Frequently Asked Questions. ... Help define the site. =-). ... -
www.iwalt.com/weblog/2002/04/ - 39k - Cached - Similar pages

Java Programming FAQs and Tutorials: Learning Java
... Search the Web: Google. ... Tutorials, online courses and more, to help you pass your -Java certification ... Learning how to generate high-quality printouts of components ... -
www.apl.jhu.edu/~hall/java/FAQs-and-Tutorials.html - 21k - Cached - Similar pages

Keyword density research report - Best Practices Search Engine ...
... everything come from the Google API? Did Google have to approve this? If so, -do you have any tips on getting API applications approved? ... -
www.ihelpyouservices.com/forums/ showthread.php?s=&threadid=13023 - 63k - Cached - Similar pages

Recommended Reading List / Answers to Frequently Asked Questions
... Guide Clark Connect Help Downloadable User Guides Webconfig API (For those ... relay -host(I can't send email) Help, I can ... Also, don't forget to google Note: All the ... -
www.clarkconnect.org/forums/showflat. php?Cat=&Board=howtos&Number=40192 - 31k - Cached - Similar pages

XMLhub.com Web Directory: Computers: Programming: Languages ...
... Microsoft: Visual FoxPro v3.0+ - Technical support forums and mutual help system -for ... Usenet microsoft.public.fox.vfp.lck-api - news: - Google Groups; Usenet ... -
www.xmlhub.com/dir/index/Computers/ Programming/Languages/Visual_FoxPro/ - 18k - Cached - Similar pages

Forum FAQ - GameDev.Net Discussion Forums
... If you're looking for API specific tutorials, here are some of the most common to -help get you ... could easily answer yourself with a quick Google search or a ... -
www.gamedev.net/community/ forums/showfaq.asp?forum_id=31 - 32k - 5 Dec 2004 - Cached - Similar pages

NDIS Frequently Asked Questions
... The Microsoft DDK help file and DDK samples, as well as ... On the other hand, the -user-mode WMI API is fairly ... useful information is to perform a Google Search on ... -
www.ndis.com/faq/QA10290101.htm - 35k - Cached - Similar pages

Managing CruiseControl With JMX - Confluence
... It is ridiculously easy to enable controling CC using the JMX (Java Mananagement -eXtensions) api. Here's what you get : ... How to enable the JMX server. ... -
confluence.public.thoughtworks.org/ display/CC/Managing+CruiseControl+With+JMX - 26k - 6 Dec 2004 - Cached - Similar pages

Post Comment
... Gone Wild General RSS Stuff Hardware Help HijackThis Logs ... And why has the Google -API stagnated for 2.5 years ... So what should Google, MSNbot and Yahoo search (to ... -
chris.pirillo.com/blog/cmd=post_comment/ article_id=119543/parent_id=165843 - 57k - Cached - Similar pages

FWE - National Headquarters - Job Search - View Job
... Northwest-Software Engineering GOOGLE - C++, Win32 API, and Linux Kernel Engineering -Opportunities POSTED: 9/30/2004 JOB TITLE: Software Engineer Google is ... -
www.fwe.org/p/p.asp?mlid=354&jid=1018 - 43k - Cached - Similar pages

Firefox Help: Firefox FAQ
... be able to find packages using Google. ... EWH32.api , printme.api and search.api from -plug_ins_disabled ... can convert the bookmarks with the help from BookmarkPriest ... -
www.mozilla.org/support/firefox/faq - 35k - 5 Dec 2004 - Cached - Similar pages

The Star Online Directory - FAQs, Help, and Tutorials
... Active Server Pages, and the Internet Server API. ... public.inetserver.iis.activeserverpages -- news: - Google Groups. Help build the largest human-edited directory ... -
directory.thestar.com.my/cat.asp?/Computers/ Programming/Internet/ASP/FAQs,_Help,_and_Tutorials/ - 15k - Cached - Similar pages

eMarketing Resources @ Spherica
... Rank Checker SEO Count Advanced API Rank Checker ... Google AdWords Keyword Suggestion -Tool Additional eTools Spider ... Index: Simple formula to help determine the ... -
www.spheri.ca/resources.html - 18k - 5 Dec 2004 - Cached - Similar pages

Building XML Web Services with .NET: Hands-On - Course FAQ
... Web services currently available include the Google API, Microsofts ... You learn how -to use the .NET System.Xml class ... Does this course help me prepare for the ... -
www.learningtree.com/courses/508qa.htm - 29k - Cached - Similar pages


Result Page: 

1

2

3

4

5

6

7

8

9

10

Next
-

 
-

Search within results | Language Tools | Search Tips | Dissatisfied? Help us improve


Google Home - Advertising Programs - Business Solutions - About Google

©2004 Google
diff --git a/src/add-ons/kernel/file_systems/googlefs/google.src b/src/add-ons/kernel/file_systems/googlefs/google.src deleted file mode 100644 index c11e51bf39..0000000000 --- a/src/add-ons/kernel/file_systems/googlefs/google.src +++ /dev/null @@ -1,29 +0,0 @@ -# Mozilla/Google plug-in by amitp+mozilla@google.com - - - - - - - - - - - -