On Linux, Genode used to represent each RPC object by a socket
descriptor of the receiving thread (entrypoint) and a globally-unique
value that identifies the object. Because the latter was transferred as
plain message payload, clients had to be trusted to not forge the
values. For this reason, Linux could not be considered as a productive
Genode base platform but remained merely a development vehicle.
This patch changes the RPC mechanism such that each RPC object is
represented by a dedicated socket pair. Entrypoints wait on a set of
the local ends of the socket pairs of all RPC objects managed by the
respective entrypoint. The epoll kernel interface is used as the
underlying mechanism to wait for a set of socket descriptors at the
server side.
When delegating a capability, the remote end of the socket pair is
transferred to the recipient along with a plaintext copy of the
socket-descriptor value of the local end. The latter value serves as a
hint for re-identifiying a capability whenever it is delegated back to
its origin. Note that the client is not trusted to preserve this
information. The integrity of the hint value is protected by comparing
the inode values of incoming and already present capablities at the
originating site (whenever the capability is invoked or presented to the
owner of the RPC object).
The new mechanism effectively equips base-linux with Genode's capablity
model as described in the Chapter 3 of the Genode Foundations book.
That said, the sandboxing of components cannot be assumed at this point
because each component has still direct access to the Linux system-call
interface.
This patch is based on the extensive exploration work conducted by
Stefan Thoeni who strongly motivated the inclusion of this feature into
Genode.
Issue #3581
Older ARM processors like ARMv6, or Cortex A8 need to write back changes
of the page-tables to physical ram because the MMU does not use the cache.
This naturally needs to be done not only when adding a mapping,
but on removal too.
Fix#3715
The topics are either covered by the Genode Founations book for by our
tools, in particular the integration of the prepare_port mechanism with
the run tool.
- don't use 'qemu -serial mon:stdio' anymore as it no longer works as
expected
- use "bash -l" with [terminal] to read user's profile configuration,
e.g., PATH settings
- added missing boot modules and cap quotas
This commit puts all C++ runtime/support symbols of ld.lib.so in a
dedicated section of base/lib/symbols/ld and mirrors the section to
libports/lib/symbols/libc. So, the libc ABI resolves potential C++
runtime dependencies of base-ABI-agnostic components at link time. The
runtime resolution is done by the linker by symbol lookup in ld.lib.so.
Issue #3720
config_0.xml.tmp:26: element config: Schemas validity error :
Element 'config': Character content other than whitespace is
not allowed because the content type is 'element-only'
Issue #3612
This patch increases the default limit of the maximum number of open
file descriptors to the hard limit of the system. This is needed for
complex scenarios, which require more FDs than the default of 1024
at core.
Related to issue #3581Fixes#3721
This commit fixes a regression introduced by "window_layouter: add
dynamic screen handling", rendering the sub-division of screens in
columns and row unusable. The said commit removed a condition needed
for the correct window placement. This patch restores the condition.
Issues #3646
This patch also introduces the use of the RTC for creating directory
names and increases the rate of snapshot creation from 10 seconds to
one minute to make sure that directories are named differently when
reading the RTC clock at granularity of minutes.
Issue #3696
This patch avoids calls of '__sys_getstatfs' (indirectly via
'getmntinfo'), which does not return any meaningful values in Genode's
libc. Otherwise, the libc's dummy implementation prompts resize2fs to
back out.
Issue #3696
This patch makes the e2fsprogs 'mke2fs' and 'resize2fs' available as
standalone components that can be used by Sculpt OS directly without
a Unix emulation environment.
As a result of the API change the memory handling could be simplified.
Since the Block session dataspace is now directly used for DMA, we
actually only have to provide the memory for setting up PRP lists for
large requests (for the moment more than 8 KiB of data).
As we limit the maximum data transfer length to 2 MiB, we get by with
just a page per request. Those memory is allocated beforehand for the
maximum number of I/O requests, which got bumbed to 512 entries. Since
not all NVMe controllers support such large a maximum data transfer
length and this many entries, especially older ones, the values are
capped according to the properties of the controller during
initialization. (The memory demands of the component are around 3 MiB
due to setting up for the common case, even if a particular controller
is only able to make use of less.)
(Although there are controllers whose maximum memory page size is more
than 4K, the driver is hardcoded to solely use 4K pages.)
In addition to those changes, the driver now supports the 'SYNC' and
'TRIM' operations of the Block session by using the NVMe 'FLUSH' and
'WRITE_ZEROS' commands.
Fixes#3702.
The former scheme left open a race window between
_process_incoming_signals() and wait_and_dispatch_one_io_signal()
resulting in both threads calling block_for_signal() and blocking
forever with one unprocessed signal.
Fixes#3704
This patch adds support for booting base-hw kernel on qemu-arm virt
machines. The arm_virt machine has 2GB of RAM, 2 Cortex A15 cores and
uses GICv2 interrupt controller. The arm_64_virt machine also has 2GB of
RAM, but has 4 Cortex A53 cores and uses GICv3. Both machines use PSCI
to boot additional CPU cores.
Fixes#3673
So far this only exposes two functions allowing the code to turn on
additional CPUs. There is much more functionality defined by PSCI spec
but so far its not needed by Genode.
Fixes#3672
The update modification timestamp is implemented as one-shot where
the caller is expected to try again if the first attempt failed (see
current libc implementation). So the message is misleading as further
attempts might succeed.
Issue #3713.
This patch fixes a regression with run/log_core introduced by
2064ffd64b nova: support multidimensional affinity space
The run tool uses a log message 'run_boot_string' to detect successful
boot as well as to detect unexpected reboots. This message should never
be logged twice and, thus, should not be part of the core_log. The patch
mentioned above moved the former run_boot_string after the core_log
initialization.
This is a follow-up fix for commit 202333c881.
It checks for the diagnostic registers being already setup correctly.
Otherwise on platforms with secure firmware, like Pandaboard it will stuck.
Ref #3639
ASLR collides with the libc's fork mechanism on 32-bit. In particular,
the tool_chain_auto.run scenario would sporadically fail while mirroring
the parent's address space.
Fixes#3710
This is needed to execute the tool-chain scenario on base-nova.
Otherwise, the fork mechanism stumbles upon a region conflict
between ldso allocations and the application heap.
Fixes#3706
This patch reflects the Out_of_caps exception from core to the client,
in addition to the already covered Out_of_ram exception. It thereby
eliminates a potential abort in core, which I observed with the
tool_chain_auto.run script:
Kernel: RPC upgrade_cap_slab
Error: Uncaught exception of type 'Genode::Quota_guard<Genode::Cap_quota>::Limit_exceeded'
Warning: abort called - thread: entrypoint
In addition to propagating the exception, the patch add the client-side
exception-handling code to the base library.
Fixes#3703
This run script is outdated and not regularly tested. In fact, the
tested mechanism (obtaining values from a '.sysctl/' directory) is
nowhere to be found, neither in noux nor the libc. The test still
returns success as it merely checks for the completion of the sequence,
not the printed results. Hence, it is not worth preserving.
Issue #3696
This run script tested the terminal VFS plugin as a new feature of noux.
In the meantime, the plugin remains as the only way for the interaction
of command-line-based applications with the terminal session. Hence,
the mechanism is now stressed by many other scenarios.
Issue #3696
This patch prefixes a few symbols in the make binary that are offered by
both the libc and the make binary. The clash of symbol names produces
confusing runtime linkage otherwise. This becomes a problem during
fork/evecve.
This patch reduces the size of session labels for all services other
than LOG, keeping only the last element. This avoids exceeding the
maximum label length in the presence of deep fork hierarchies, e.g., for
running the tool chain.
Fixes#3700
When the last writer closes the pipe, we must trigger the I/O progress
handler to deliver the final EOF to the client (READ_OK with out count
of 0).
Fixes#3697
This patch replaces the former Noux instance by a sub init that hosts
the combination of VFS + fs_rom + bash. If bash exits, the whole sub
init exits, which implicitly tears down the terminal session used by the
sub init. The latter is expected by the test sequence.
Issue #3696
The tar vfs plugin returns an inode value of zero and a type directory
for null records, which wrongly triggers the file-system loop detection
of the find utility. This patch returns the node pointer as inode value
instead, which is a unique value.
Fixes#3695
This patch changes the 'Single_file_system' to return NO_PERM only if
the to-be-unlinked file corresponds to the single file. This way, a
<rom> co-mounted with a <ram> file-system does not stand in the way of
unlinking files from the <ram>. The concrete symptom occurred the
following scenario:
<vfs>
<dir name="home">
<ram/>
<rom name="..."/>
</dir>
</vfs>
The following sequence of commands wrongly resulted in "Operation not
permitted":
$ mkdir -p /home/a/b/c
$ rm -f /home/a/b/c/d
In this case, rm should not fail (unlink should return ENOENT)
Fixes#3690
When updating the domain object of interfaces that stay with the same domain
during a reconfiguration, until now, the normal "detach raw" function was used.
This caused the old domain object to discard a dynamic IP config as all
interfaces detached. This caused interfaces also to discard network links
established with the old configuration although it wasn't necessary. Thus, now
we use a dedicated "detach" in case that an interface actually stays with its
domain. This new "detach" doesn't decrease the interface counter of the domain,
so, it'll not discard its dynamic IP config. If, however, during a
reconfiguration, there's no interface calling this function (all interfaces
move to another or no domain), the dynamic IP config is still discarded as
expected.
Fixes#3686
Until now, the DHCP client was called also for DHCP requests when an interface
had a domain but yet no IP config. Now, an interface distinguishes between DHCP
requests and replies first and then accordingly calls the DHCP server or the
DHCP client if they're available. This also prevents that the DHCP client has
to handle packet headers other than that of DHCP.
Fixes#3681
Let the DHCP client be a constructible member of Interface that is constructed
only as long as the interface is attached to a domain with a dynamic IP config.
This prevents DHCP client timeouts from a period with dynamic IP config to
trigger after a reconfiguration to a static IP config. Furthermore, handle
DHCP-reply packets at an interface only when the DHCP client its constructed.
Otherwise drop such packets.
Ref #3681
This commit fixes the following issues regarding cache maintainance
under ARM:
* read out I-, and D-cache line size at runtime and use the correct one
* remove 'update_data_region' call from unprivileged syscalls
* rename 'update_instr_region' syscall to 'cache_coherent_region' to
reflect what it doing, namely make I-, and D-cache coherent
* restrict 'cache_coherent_region' syscall to one page at a time
* lookup the region given in a 'cache_coherent_region' syscall in the
page-table of the PD to prevent machine exceptions in the kernel
* only clean D-cache lines, do not invalidate them when pages where
added on Cortex-A8 and ARMv6 (MMU sees phys. memory here)
* remove unused code relicts of cache maintainance
In addition it introduces per architecture memory clearance functions
used by core, when preparing new dataspaces. Thereby, it optimizes:
* on ARMv7 using per-word assignments
* on ARMv8 using cacheline zeroing
* on x86_64 using 'rept stosq' assembler instruction
Fix#3685
This depot package is the runtime for rtc_drv and system_rtc server with
coordinated update of system and hardware RTC via reports. It replaces
drivers_rtc which was never freestanding drivers package and, therefore,
has to be accompanied with a running platform_drv etc.
Fixes#3680
- use two disks with two partitions each
- one disk uses MBR and one GPT
- connect one 'part_block' to each disk
- run 'block_tester' and 'test-block-client' connecting to one partiion
on each disk
- x86 uses 'ahci_drv' as disk back-end, Linux 'lx_block'
- on autopilot enable for Qemu only
issue #3671
Formerly, _next was always updated to the last free'd allocation, which
left large gaps on alloc/free bursts. Now, we try keep allocation
density high from the start of the array and ensure that allocations
happen at the lowest available index in the bit array.
Fixes#3679
The function is exposed in libc headers provided by Genode, the code for
the function is being compiled and actually works, but the symbol is
missing from the symbols file resulting in linking failures. Add it to
the libc symbols file.
Fixes#3676Fixes#3677
This patch increases the Sculpt version to avoid the risk of binary
compatibility clashes with index files published for the just-released
Sculpt 20.02 version.
Without this patch, the text area would mistakenly delete the characters
types after placing the cursor with the mouse as soon as shift is used
as modifier.
- Don't reset sculpt partition on USB changes whenever ram fs is
selected for use.
- Reconfigure runtime immediately when plugging USB devices.
This prevents the usb-block driver and part_block from
dangling in the graph. They disappear immediately now.
This patch restores the anchoring of the popup menu to the original
behavior, placing the popup to the right of the '+' button. The
anchoring got lost due to the recent structural changes of the GUI,
which affect the hover XML structure.
The new implementation relieves the main entrypoint from monitor jobs
for contended lock primitives and is based on custom applicant data
structures, per-lock resp. per-semaphore applicant lists, and a
libc-internal blockade with timeouts based on libc kernel primitives.
This patch makes the 'with_raw_node' method more useful in situations
where content of an Xml_node is fed into an Xml_generator, i.e., the
rules report/rom mechanism of the window layouter.
The applicant_to_wake_up() member must be initialized to 0 to keep the
same semantic as before the change by
"base: add mutex as derivate of lock"
Issue #3662
Be less rigid when checking for available network to support
setups where the uplink or depot repositories are provided by
another source than "wired" or "wifi" NIC services,
e.g., a virtual machine with pass-through network device.
net:
* increase queue size to 1024 (more stable on Linux)
* use mac address from Nic session instead of random one
* handle data that is larger than rx descriptor correctly (copy less)
* clear descriptor header (12 bytes) on rx
generic:
* always use 'avail_idx' (tx and rx)
* added barriers when reading/writing queues (TMP)
Ref #3620
We do not use the VMM with several CPUs until now.
On the other hand there is a dead-lock due to the
generic timer calling the cpu handler function explicitly,
which already holds the lock. For the time-being remove the lock.
Ref #3620
The new text_area component is able to view and edit files.
Internally, it employs a menu_view for the graphics output.
Only basic notepad-like text-editing functions are supported.
At the current time, it is solely meant as a companion of the Sculpt
manager.
Issue #3650
This patch improves the robustness of menu_view when encounting missing
textures, which can happen during development when using styled buttons
and frames. With the patch, menu_view outputs diagnostic messages,
pinpointing the problem.
The patch also updates the texture handling to use the 'File_content'
utility and the VFS for obtaining PNG images.
Issue #3629
This patch allows for the customization of the text color and alpha
value of the label widget by the means of a style-definition file.
The mechanism is exemplified with the new "invisible" label style
that sets the alpha value to zero.
Issue #3629
- use Job API as block connection back end
- use Request_stream API as front end
- use Mmio framework for gpt and mbr parsing
- implement sync correctly
fixes#3652
Generated a separate 'config.h' for arm, arm_64, x86_32, x86_64 for the
current version (6.1.2) of GMP. This became necessary because
configurations differ for each architecture.
'config.h' generaton on x86_64 host in'gmp-6.1.2' directory:
for x86_64 (native):
! configure
for x86_32:
! configure --host=x86-pc-linux-gnu --build=x86_64-pc-linux-gnu
for arm:
! configure --host=arm-linux-gnu --build=x86_64-pc-linux-gnu \
! CC=/usr/local/gcc-linaro-arm/bin/arm-linux-gnueabi-gcc ABI=32
for arm_v8:
! configure --host=aarch64-linux-gnu --build=x86_64-pc-linux-gnu \
! CC=/usr/local/gcc-linaro/bin/aarch64-linux-gnu-gcc ABI=64
issue #3598
This commit adds dynamic switching in between different defined
screens via keyboard shortcuts, or by editing the rules file.
In the window_layouter package it defines per default ten screens,
reachable by pressing the screen key along with numbers 0-9.
Fix#3646
The mutex class is more restrictive in usage compared to
Genode::Lock.
- At initialiation time it is ever unlocked.
- No thread is permitted to lock twice. Warn about it
in case it happens.
- Only the lock onwer is permitted to unlock the mutex.
Warn about it and don't unlock the mutex in case it happens.
Issue #3612
In preparation of ipc receive, by now a bunch of capabilities got
allocated to be ready iin case of capability receiption. After that
unuse slots were freed again. This overhead of senseless (de-)allocations
is replaced in this commit by just restock capability slots that got
used by the last receive.
Fix#3640
Error return codes are used with non-const functions in the signaling modules.
This would have been impractical for the in-place translation of the module to
Ada in the context of the Spunky project. Besides, it is easy to get rid of
them and it makes the execution flow more clear.
Ref #3308
Besides reducing the use of pointers in base-hw, this prepares for the in-place
translation of the signaling module to Ada in the context of the Spunky
project.
Ref #3308
This prevents the use of Kernel::Object as base class for the specific kernel
objects and instead makes it a member of the kernel objects. Besides
simplifying inheritance hierarchies in base-hw, this prepares for the in-place
translation of the signaling module (and others) to Ada in the context of the
Spunky project.
Ref #3308
Besides simplifying the execution flow in the signaling module, this prepares
for the in-place translation of the signaling module to Ada in the context of
the Spunky project.
Ref #3308
This prevents the use of C++ features in the public method interface of the
synchronous-IPC module that would be impractical for the in-place
translation of the module into Ada in the context of the Spunky project.
* Get rid of thread accessor.
* Get rid of non-const functions with return values.
* Get rid of pointer return-values.
Ref #3308
Besides simplifying inheritance hierarchies in base-hw, this prepares for the
in-place translation of the synchronous-IPC module to Ada in the context of the
Spunky project.
Ref #3308
This is a simplication of the asyncronous-IPC module of the base-hw kernel.
Besides structuring the code in a cleaner way, it prepares for the in-place
translation of the module into Ada in the context of the Spunky project.
* Get rid of virtual methods in Ipc_node.
* Move all stuff related to protection domains, capabilities, and UTCBs to
the Thread class. this code might later be moved to a dedicated module, but
for now it's just fine to have it done by the thread module.
Ref #3308
Moved code waking up processors for Cortex A53 before changing privilege
level because sending events to higher privilege levels is not allowed.
Fixed enable_mmu for Cortex A53 to properly return cpu id.
Fixed starting code for secondary cores to properly initialize stacks.
Added code to wake up secondary cores on rpi3.
Ref #3573
We cannot count on the correct initialization of the diagnostic register
of the secondary cores. But the boot core gets initialized by the bootchain,
so we can copy over those values.
Fix#3639
If the root child requests a LOG service with the label "unlabeled" then
return a LOG session that logs unprefixed messages. This allows a external
test controller to recognize log messages produced by a blessed component.
This new attribute can be used to enforce a minimum width in the unit of
the size of the character 'x'. Furthermore, the patch sets the minimum
height of a label to 0 if no 'text' attribute is present. By combining
both features, the label becomes usable as a horizontal spacer.
Issue #3629
This patch refines the hover handling such that a float widget never
responds to hovering unless a child is hovered. This way, it becomes
possible to stack multiple float widgets within one frame and still
reach all child widgets.
Issue #3629
Similarly to the way of how a <cursor> can be defined for a <label>
widget, a selection can be expressed as follows:
<label ...>
<selection at="2" length="12"/>
</label>
Issue #3607
Issue #3629
When setting the <dialog> attribute 'hover_details' to "yes", the hover
report features the character position of a hovered label.
Issue #3607
Issue #3629
This patch equips the label widget with the ability to display a text
cursor, as illustrated by the following example:
<label text="...">
<cursor at="10"/>
</label>
Issue #3607
Issue #3629
The value range supported by the 'Animated_rect' utility is constrained
to 2^11 by the used 32-bit integer type. The interpolation is performed
on fixpoint numbers with a fractional precision of 10 bits. The
non-linear interpolation as performed by the 'Lazy_value' utility
involves squaring the values. Hence, the interpolated integral values
must not exceed 2^11 (2*11 bits for the square plus 10 bit for the
fractional part require 32 bits). This range is too small for
high-resolution displays. Hence this patch replaces the 32-bit integer
type by a 64-bit integer type.
Fixes#3627
The wm used to remember the last pointer position when observing a leave
event. With such a stale pointer position, the wm would eventually
wrongly create an artifical motion event when a supposedly hovered
window changes its position (during an animated move). This can lead to
the propagation of the stale pointer position to the wm client, which,
in turn, may interpret the outdated position (e.g., the menu view would
report a wrong hover state).
This patch removes the stale state by resetting the '_pointer_pos' when
observing a leave event.
Fixes#3632
When specifying "/" or "" as rel_path to the 'Directory' constructor,
the constructed directory should refer to the same directory. The
implementation of the join utility did not consider this corner case. It
occurred during the attempt to use fs_query with "/" given as path.
This patch also adds a Directory::Entry::dir accessor that returns true
if the entry is a directory.
Fixes#3630
By writing out all dangling characters at destruction time, the
'Buffered_output' utility can be used as a local variable rather
than a long-living object.
Besides updating to a newer version the update adds the AC97 ICH driver
and addresses shortcomings with the OpenBSD emulation environment:
* Fix 'delay(9)' implementation - it now properly uses 'us' as unit,
which results on faster initialization of the drivers.
* Fix LOG output that got lost during commit f23579532 and bring over
the printf implementation from dde_linux for more structured
printing.
* As said the driver now recognizes the AUICH devices. So far it was
only tested with the device model in VirtualBox where it produces
stuttering audio, investigating the cause is still ongoing.
Fixes#3641.
- Remove dated 'Block::Driver' front end and implement
'Block::Request_stream' front end
- Remove all dynamic memory allocations but DMA memory allocations
- Remove 'Platform_hba' and implement platform specific functions in
'spec/<platform>/*'
- Ata and Atapi don't inherit from 'Port' any more, but are a member of
'Port' as a protocol implementation
- Use platform driver for MMIO mappings (x86)
- Exchange stateful initialization of Ata/Atapi with a sequential
initialization using 'wait_for_any' and 'retry' patterns
- Fix Atapi initialization by setting the byte count limit
- Set FIS receive base only when Cmd::FRE is disabled and Cmd::FR is 0
- Put everything in namespaces ('Ahci', 'Ata', or 'Atapi')
- Ata decides during read/write operations to use native-command queuing
or normal DMA requests
- Remove port claiming logic (is now done via 'Constructibles')
fixes#3636
The libc monitor facility enables the execution of monitor jobs by the
main thread when the monitor pool was charged. In comparison to the
current suspend/resume_all mechanism the main thread iterates over all
job functions in contrast to waking up all threads to check their
conditions by themselves. Threads are only woken up if the completion
condition was met.
This commit is the result of a collaboration with Christian Prochaska.
Many thanks for your support, Christian.
Fixes#3550
sleep(), usleep(), and nanosleep() now return immediately on
zero-timeout. Also, non-zero timeouts sleep at least 1 ms (the current
minimal timeout in libc), which compensates rounding errors.
Issue #3550
The ARP destination MAC was set to the Ethernet source MAC which is not
necessarily the MAC of the other ARP peer. Instead use the ARP source MAC of
the ARP request.
Instead of listening for new TCP/IP connections only,
the TCP terminal connects to a server when an IP address is
configured in the policy for a terminal client.
Fix#3619
If the suspend method for the main thread detects that the suspend
condition is false it must return the passed timeout value (not always
0). Otherwise, the caller may incorrectly assume the timeout expired.
Especially the initial reset ended up with an unusable keyboard in rare
cases before. This commit disables keyboard and mouse handling of i8042
during command sequences according to a note from
https://www.win.tue.nl/~aeb/linux/kbd/scancodes-12.html
The new utility can be used to revert quoted XML attribute values.
Such quoting is needed whenever an attribute value can contain '"'
characters. E.g., in the menu_view's <label text="..."> widget.
Issue #1757
If the ROM service returned in invalid dataspace, reflect this condition
via a size of zero instead of triggering an exception of type
'Reconstructible<Attached_dataspace>::Deref_unconstructed_object'.
Issue #3606
An invalid ROM dataspace can occur, for example, when requesting a ROM
from the report_rom service before the first report was posted. Such a
<rom> node can still be useful if it's dynamic. E.g., it can be watched.
Hence, the corner case of an invalid ROM dataspace should be gracefully
handled instead of causing an abort.
Issue #3606
This patch adds a special variant of a 'Content_producer' called
'Xml_producer', which allows the direct use of an 'Xml_generator'
for generating the ROM-module content.
This patch extracts the child-management functionality from the init
component into a new library called "sandbox". The library API is
located at 'os/include/os/sandbox.h'.
The sandbox API allows for the interaction of the component with the
sandboxed children by providing locally implemented services. This
mechanism is illustrated by the new test at os/src/test/sandbox.
Issue #3601
This patch extends the 'Buffered_xml' utility with a new constructor
that fills the buffer with the output of an 'Xml_generator'. It thereby
presents an easy way to generate XML to be consumed locally.
The patch also add a deprecation mark to the original 'xml' accessor
because copying 'Xml_node' objects (here as return value) is dangerous.
The new 'with_xml_node' method should instead be used to access the XML
content stored in the buffer.
Fixes#3602
The XML parser used to rely in C++ exceptions while parsing, which is an
artifact from the initial implementation. This patch reworks the code such
that exceptions are avoided in the common cases.
Fixes#3605