初识Zircon内核对象

badmonkey 2021年06月27日 306次浏览

初识Zircon内核对象

不同于传统linux内核,Zircon时一个基于内核对象的kernel,系统的不同功能被抽象到了对应的内核对象中,而所有的内核对象都派生自一个基类(Dispatcher)。

Dispatcher

内核对象作为一个基类,在定义的时候,其成员变量使用的也是"基类"(更容易扩展),具体的成员变量如下:

fbl::Canary<fbl::magic("DISP")> canary_;

const zx_koid_t koid_;
ktl::atomic<uint32_t> handle_count_;

zx_signals_t signals_ TA_GUARDED(get_lock());

// List of observers watching for changes in signals on this dispatcher.
fbl::DoublyLinkedList<SignalObserver*> observers_ TA_GUARDED(get_lock());

// Used to store this dispatcher on the dispatcher deleter list.
fbl::SinglyLinkedListNodeState<Dispatcher*> deleter_ll_;

其中内核对象通过一个双向链表维护SignalObserver,其中AddObserver方法定义如下

zx_status_t Dispatcher::AddObserver(SignalObserver* observer, const Handle* handle,zx_signals_t signals, Dispatcher::TriggerMode trigger_mode);

可以看到使用到了handle对象和signals,以及SignalObserver。其中handle是通过observer保存的,最后将observer加入到双向链表中。

同时使用一个双向链表为维护dispatcher deleter list,大概是为了递归删除dispatcher的使用使用的链表??和SafeDeleter的关系??以及线程安全....

此外定义了几个核心方法:

void increment_handle_count();
bool decrement_handle_count();
uint32_t current_handle_count();
zx_status_t AddObserver(SignalObserver* observer, const Handle* handle, zx_signals_t signals,TriggerMode trigger_mode = TriggerMode::Level);
bool RemoveObserver(SignalObserver* observer, zx_signals_t* signals = nullptr);
void Cancel(const Handle* handle);
bool CancelByKey(const Handle* handle, const void* port, uint64_t key);

其中Cancel是将内核对象observer链表中的具有handle的observer移除,CancelByKey同理,只不过还使用到了port 和key。

Dispatcher的一系列的接口

// Interface for derived classes.

virtual zx_obj_type_t get_type() const = 0;

virtual zx_status_t user_signal_self(uint32_t clear_mask, uint32_t set_mask) = 0;
virtual zx_status_t user_signal_peer(uint32_t clear_mask, uint32_t set_mask) = 0;

virtual void on_zero_handles() {} // 最后一个handle被移除时,删除或者recycle内核对象。

virtual zx_koid_t get_related_koid() const = 0;
virtual bool is_waitable() const = 0;

// get_name() will return a null-terminated name of ZX_MAX_NAME_LEN - 1 or fewer
// characters.  For objects that don't have names it will be "".
virtual void get_name(char out_name[ZX_MAX_NAME_LEN]) const __NONNULL((2)) {
    memset(out_name, 0, ZX_MAX_NAME_LEN);
}

// set_name() will truncate to ZX_MAX_NAME_LEN - 1 and ensure there is a
// terminating null
virtual zx_status_t set_name(const char* name, size_t len) { return ZX_ERR_NOT_SUPPORTED; }

SoloDispatcher

独占锁,没有peer的内核对象。实现了user_signal_self

// 没有peer kernel object 对应的get_related_koid 返回0
zx_koid_t get_related_koid() const override TA_REQ(get_lock()) { return 0ULL; }
bool is_waitable() const final { return default_rights() & ZX_RIGHT_WAIT; }

zx_status_t user_signal_self(uint32_t clear_mask, uint32_t set_mask) final {
    if (!is_waitable())
        return ZX_ERR_NOT_SUPPORTED;
    // Generic objects can set all USER_SIGNALs. Particular object
    // types (events and eventpairs) may be able to set more.
    auto allowed_signals = ZX_USER_SIGNAL_ALL | extra_signals;
    if ((set_mask & ~allowed_signals) || (clear_mask & ~allowed_signals))
        return ZX_ERR_INVALID_ARGS;

    UpdateState(clear_mask, set_mask);
    return ZX_OK;
}
// 只有PeeredDispatcher 才有user_signal_peer方法的实现
zx_status_t user_signal_peer(uint32_t clear_mask, uint32_t set_mask) final {
    return ZX_ERR_NOT_SUPPORTED;
}

PeeredDispatcher

Channel一类的内核对象,两个内核对象互斥的访问对signal的锁,同时一个端点被关闭的时候,另一个端点需要更新其peer成员变量。在Dispatcher的基础上新增了holder和peer以及peer_koid,分别用户管理锁和另一端的内核对象。

const fbl::Canary<CanaryTag<Self>::magic> canary_;

zx_koid_t peer_koid_ = 0u;
fbl::RefPtr<Self> peer_ TA_GUARDED(get_lock());

private:
const fbl::RefPtr<PeerHolder<Self>> holder_;

相比于SoloDisPatcher,PeeredDispatcher考虑的更多,对应的实现在zircon/kernel/object/include/dispatcher.h

zx_koid_t get_related_koid() const final TA_REQ(get_lock()) { return peer_koid_; }
bool is_waitable() const final { return default_rights() & ZX_RIGHT_WAIT; }
// 更新自己的signal
zx_status_t user_signal_self(uint32_t clear_mask,
                             uint32_t set_mask) final TA_NO_THREAD_SAFETY_ANALYSIS {
    auto allowed_signals = ZX_USER_SIGNAL_ALL | extra_signals;
    if ((set_mask & ~allowed_signals) || (clear_mask & ~allowed_signals))
        return ZX_ERR_INVALID_ARGS;

    Guard<Mutex> guard{get_lock()};

    UpdateStateLocked(clear_mask, set_mask);
    return ZX_OK;
}
// 更新另一端kernel object 的signal
zx_status_t user_signal_peer(uint32_t clear_mask,
                             uint32_t set_mask) final TA_NO_THREAD_SAFETY_ANALYSIS {
    auto allowed_signals = ZX_USER_SIGNAL_ALL | extra_signals;
    if ((set_mask & ~allowed_signals) || (clear_mask & ~allowed_signals))
        return ZX_ERR_INVALID_ARGS;

    Guard<Mutex> guard{get_lock()};
    // object_signal() may race with handle_close() on another thread.
    if (!peer_)
        return ZX_ERR_PEER_CLOSED;
    peer_->UpdateStateLocked(clear_mask, set_mask);
    return ZX_OK;
}
// 销毁自己的时候,需要更新另一端的peer_ 值
// All subclasses of PeeredDispatcher must implement a public
// |void on_zero_handles_locked()|. The peer lifetime management
// (i.e. the peer zeroing) is centralized here.
void on_zero_handles() final TA_NO_THREAD_SAFETY_ANALYSIS {
    Guard<Mutex> guard{get_lock()};
    auto peer = ktl::move(peer_);
    static_cast<Self*>(this)->on_zero_handles_locked();

    // This is needed to avoid leaks, and to ensure that
    // |user_signal| can correctly report ZX_ERR_PEER_CLOSED.
    if (peer != nullptr) {
        // This defeats the lock analysis in the usual way: it
        // can't reason that the peers' get_lock() calls alias.
        peer->peer_.reset();
        static_cast<Self*>(peer.get())->OnPeerZeroHandlesLocked();
    }
}

// Returns true if the peer has closed. Once the peer has closed it
// will never re-open.
bool PeerHasClosed() const {
    Guard<Mutex> guard{get_lock()};
    return peer_ == nullptr;
}

Lock<Mutex>* get_lock() const final { return holder_->get_lock(); }

RefPtr

出现在zircon/system/ulib/fbl/include/fbl/ref_ptr.h

RefPtr本质其实是对原生的指针进行封装,在zircon中封装的是Dispathcer的指针(内核对象的指针),而Dispathcer继承了RefCountedUpgradeable和Recyclable,通过封装更好的对Dispathcer的引用计数和生命周期进行了管理,而不用用户每次使用过Dispathcer指针后,显示的去维护其引用计数和是否需要recycle,只需要使用RefPtr<Dispathcer>就可以啦。

handle

定义出现在zircon/kernel/object/handle.h,对应的实现是zircon/kernel/object/handle.cc

handle是进程和内核对象交互的桥梁,它包含了进程和内核对象的相关信息,其属性成员包括

ktl::atomic<zx_koid_t> process_id_; // 进程的进程id
fbl::RefPtr<Dispatcher> dispatcher_; // 引用的内核对象
const zx_rights_t rights_; // 具有的权限
const uint32_t base_value_; // 通过FromU32方法获得base_value_ 对应的handle对象,同时还会用于计算zx_handle_t
static constexpr size_t PreserveSize = 24; // 
friend HandleTableArena; //管理handle
NodeState node_state_; // 一个handle的双向链表 

HandleOwner:将handle封装到一个独占其所有权(ownership)的unique_ptr中,同时当handle不在被使用的时候将handle删除掉。

HandleTableArena:管理handle,包括handle的内存分配和去配,根据handle映射到对应的index,获取新的base_value_

void* Alloc(const fbl::RefPtr<Dispatcher>&, const char* what, uint32_t* base_value);
void Delete(Handle* handle);
// GetNewBaseValue is a helper needed to actually create a Handle.
uint32_t GetNewBaseValue(void* addr);
// A helper for the GetNewBaseValue computation.
uint32_t HandleToIndex(Handle* handle);

handle对象的特有的方法(这里没有列出getter,setter方法)

const fbl::RefPtr<Dispatcher>& dispatcher() const { return dispatcher_; }

static void Init();
static Handle* FromU32(uint32_t value);
static uint32_t Count(const fbl::RefPtr<const Dispatcher>&);
// 调用私用的构造方法,并返回HandleOwner
static HandleOwner Make(fbl::RefPtr<Dispatcher> dispatcher, zx_rights_t rights);
static HandleOwner Make(KernelHandle<Dispatcher> kernel_handle, zx_rights_t rights);
static HandleOwner Dup(Handle* source, zx_rights_t rights);


// Called only by Make.
Handle(fbl::RefPtr<Dispatcher> dispatcher, zx_rights_t rights, uint32_t base_value);
// Called only by Dup.
Handle(Handle* rhs, zx_rights_t rights, uint32_t base_value);

~Handle() = default;
void TearDown(); // HandleTableArena中的delete方法调用TearDown方法
static uintptr_t IndexToHandle(uint32_t index);// 索引对应的Handle

kernel的handle被单独抽象成了KernelHandle

SignalObserver

SignalObserver是一个抽象类,定义了几个处理signal的接口,同时保存了signals和handle对象。定义的接口如下

// Called when the set of active signals matches an expected set.
//
// At the time this is call, it is safe to delete this object: the
// caller will not interact with it again.
//
// WARNING: This is called under Dispatcher's lock
virtual void OnMatch(zx_signals_t signals) = 0;

// Called when the registered handle (which refers to a handle to the
// Dispatcher object) is being destroyed/"closed"/transferred. (The
// object itself may also be destroyed shortly afterwards.)
//
// At the time this is call, it is safe to delete this object: the
// caller will not interact with it again.
//
// WARNING: This is called under Dispatcher's lock
virtual void OnCancel(zx_signals_t signals) = 0;

// Determine if this observer matches the given port and key.
//
// If true, this object will be removed.
//
// WARNING: This is called under Dispatcher's lock.
virtual bool MatchesKey(const void* port, uint64_t key) { return false; }
// 保存signal和handle
private:
// Dispatcher state, guarded by Dispatcher's lock.
friend class Dispatcher;
zx_signals_t triggering_signals_;
const Handle* handle_;

具体的实现有wait_signal_observer,可以参考其中的onMatchonCancel的实现,貌似做了一些cannary的检查,signal状态保存,以及signal的响应?