Skip to content

DeviceManagerListener

Levente Santha edited this page May 14, 2026 · 2 revisions

DeviceManagerListener

Observer interface for device discovery and binding events in JNode's driver framework.

Overview

DeviceManagerListener (core/src/driver/org/jnode/driver/DeviceManagerListener.java) is JNode's observer interface for high-level device manager events — device registration and unregistration. It allows any component to be notified whenever a device enters or leaves the system's device registry, without coupling to the device's lifecycle details.

This differs from DeviceListener (core/src/driver/org/jnode/driver/DeviceListener.java), which fires on device start and stop (the driver lifecycle within an already-registered device). DeviceManagerListener fires at a higher level: when the device is first registered with the manager and when it is about to be removed from the registry entirely.

Key Components

File Role
core/src/driver/org/jnode/driver/DeviceManagerListener.java The listener interface: deviceRegistered(Device), deviceUnregister(Device)
core/src/driver/org/jnode/driver/AbstractDeviceManager.java Listener registration (addListener/removeListener) and event dispatch (fireRegisteredEvent, fireUnregisterEvent)
core/src/driver/org/jnode/driver/DeviceManager.java Public interface declaring addListener(DeviceManagerListener) / removeListener(DeviceManagerListener)
gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java Canonical usage: deferred initialization of the framebuffer console

How It Works

Listener Interface

The interface is minimal — two methods:

// core/src/driver/org/jnode/driver/DeviceManagerListener.java
public interface DeviceManagerListener {
    public void deviceRegistered(Device device);
    public void deviceUnregister(Device device);
}

Registration and Dispatch

Listeners register via AbstractDeviceManager.addListener(DeviceManagerListener). The manager maintains an internal List<DeviceManagerListener>:

// AbstractDeviceManager.java
private final List<DeviceManagerListener> listeners = new LinkedList<DeviceManagerListener>();

public final void addListener(DeviceManagerListener listener) {
    synchronized (listeners) {
        listeners.add(listener);
    }
}

public final void removeListener(DeviceManagerListener listener) {
    synchronized (listeners) {
        listeners.remove(listener);
    }
}

When a device is registered, AbstractDeviceManager.register() calls fireRegisteredEvent():

// Called inside register(), before start()
protected final void fireRegisteredEvent(Device device) {
    final List<DeviceManagerListener> list;
    synchronized (this.listeners) {
        list = new ArrayList<DeviceManagerListener>(this.listeners);
    }
    final StopWatch sw = new StopWatch();
    for (DeviceManagerListener l : list) {
        sw.start();
        l.deviceRegistered(device);
        if (sw.isElapsedLongerThen(100)) {
            BootLogInstance.get().error("DeviceManagerListener took " + sw
                + " in deviceRegistered: " + l.getClass().getName());
        }
    }
}

The same pattern applies to fireUnregisterEvent() — called from unregister() after stopping the device but before removing it from the map.

The listener list is copied under the lock before iteration, ensuring safe concurrent modification. A StopWatch measures each callback; any listener exceeding 100ms triggers an error log.

Canonical Use Case: Deferred Initialization

The primary use case is deferred initialization — a component that depends on a device that may not exist yet. FBConsole in the GUI driver demonstrates this pattern:

// gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java
public static void start() throws Exception {
    final Collection<Device> devs = DeviceUtils.getDevicesByAPI(FrameBufferAPI.class);
    int dev_count = devs.size();
    if (dev_count > 0) {
        startFBConsole(devs.iterator().next());
    } else {
        DeviceUtils.getDeviceManager().addListener(new DeviceManagerListener() {
            public void deviceRegistered(Device device) {
                if (device.implementsAPI(FrameBufferAPI.class)) {
                    startFBConsole(device);
                }
            }
            public void deviceUnregister(Device device) {
                // TODO stop the FBConsole
            }
        });
    }
}

This is the wait-for-device pattern: poll first, and if nothing is found, register a listener to wait asynchronously for a future device.

Relationship to DeviceListener

DeviceManagerListener DeviceListener
Package org.jnode.driver org.jnode.driver
Methods deviceRegistered, deviceUnregister deviceStarted, deviceStop
Fires when Device is registered/unregistered in the manager Device driver starts/stops
Registered on DeviceManager DeviceManager or Device
Scope Manager-wide (all devices) Per-device or manager-wide

Both listener types share the same 100ms warning threshold in AbstractDeviceManager. The distinction is between the device registry lifecycle (DeviceManagerListener) and the device driver lifecycle (DeviceListener).

Gotchas

  • Listener is on the manager, not the device — unlike DeviceListener which can be added directly to a Device instance, DeviceManagerListener is always registered with the DeviceManager and receives events for all devices.
  • Fire order relative to lifecycle — deviceRegistered is fired before the device is started (start(device) is called after the fire). deviceUnregister is fired after the device is stopped but before it is removed from the map.
  • 100ms warning threshold — slow listeners affect the timing of all subsequent listener callbacks and device startup. Avoid blocking I/O in listener callbacks.
  • No filtering by device class — the listener receives every registration. Use device.implementsAPI(SomeAPI.class) to filter.
  • Anonymous inner class memory leak risk — the manager holds a strong reference to the listener. If the listener captures a large context, it won't be GC'd until explicitly removed. Always removeListener() when done, or use weak references for long-lived listeners with short-lived implementations.

Related Pages

  • Device-Manager — The manager this listener attaches to, including event dispatch details.
  • Driver-Framework — The broader driver subsystem where this observer pattern lives.
  • DeviceListener — Lower-level listener for device start/stop events (different scope).
  • Plugin-System — How device finders trigger the registration events observed by this listener.
  • Resource-Management — Hardware resources that devices claim at startup time.

Clone this wiki locally