### xnregistry：全局对象注册表

在实时系统中，任务之间的同步与通信需要依赖各种内核对象，如信号量、互斥锁、消息队列等。为了支持进程间共享和快速检索，`xkernel` 提供了 `xnregistry`，用于统一管理和访问这些内核对象。

#### 什么是 xnregistry？

`xnregistry` 是 `xkernel` 内核的全局对象注册表，负责管理内核中的命名和未命名对象。它提供了一种机制，允许内核对象以唯一的标识符（如名称）注册，便于在内核和用户空间中查找和访问。

#### xnregistry 的作用

- 统一管理：维护内核对象的生命周期，确保资源的正确分配和释放。
- 快速检索：通过高效的哈希表结构，实现对象的快速查找，满足实时系统的性能要求。
- 进程间通信：支持命名对象的共享，方便不同进程或线程之间的同步与通信。

#### 命名内核对象的管理

命名内核对象是指在创建时指定了名称的对象，通常用于多个进程之间的共享和通信。常见的命名内核对象包括：

- 有名信号量（sem）
- 有名消息队列（mq）
- 实时套接字（如 xddp、bufp、iddp）

##### 创建和注册过程

以两个 `xkernel` 任务通过信号量进行同步为例：

**任务 1 创建一个名为 /tmp/sem1 的信号量**：

```c
/* 任务 1 */
sem_t *demo_sem;

demo_sem = sem_open("/tmp/sem1", O_CREAT | O_EXCL, 0666, 0);
if (demo_sem == SEM_FAILED)
    perror("sem_open");

sem_wait(demo_sem);
/* ... */
sem_post(demo_sem);
```

**任务 2 打开同名信号量**：

```c
/* 任务 2 */
sem_t *demo_sem;

demo_sem = sem_open("/tmp/sem1", 0);
if (demo_sem == SEM_FAILED)
    perror("sem_open");

sem_wait(demo_sem);
/* ... */
sem_post(demo_sem);
```

当任务 1 调用 sem_open 创建信号量时，内核会进行以下操作：

1. 分配 `xnobject` 结构体：从 `registry_obj_slots` 中获取一个空闲的 `xnobject`，用于表示信号量对象。
2. 设置 `xnobject` 的属性：
   - key：设置为信号量的名称 `/tmp/sem1`。
   - objaddr：指向实际的信号量对象（如 cobalt_sem）。
3. 插入哈希表：
  - 对名称进行哈希计算，得到索引值 s。
  - 将 `xnobject` 插入到 `object_index[s]` 哈希桶对应的链表中。

任务 2 想要打开同名信号量时，执行以下步骤：

1. 计算名称的哈希值：对 `/tmp/sem1` 进行哈希计算，得到索引值 s。
2. 在哈希表中查找：
	•	遍历 `object_index[s]` 链表，比较每个 `xnobject` 的 `key`。
	•	找到匹配的 `xnobject` 后，获取其 `objaddr`，即信号量对象的地址。

在成功创建或打开信号量后，系统会生成一个 `xnhandle_t`，表示对象的句柄。这个句柄通常是 `xnobject` 在 `registry_obj_slots` 数组中的偏移量。任务在后续操作（如 `sem_wait`、`sem_post`）中，使用这个句柄快速访问信号量对象，避免再次通过名称查找。
![](https://resource.helplook.net/docker_production/3648ne/article/CYlBhXIW/faff59c61973011f7fe5187919954667.png)


#### 未命名内核对象的管理

未命名内核对象通常用于单个进程或线程内部，不需要跨进程共享。例如：

- 未命名信号量（sem）
- 互斥锁（mutex）
- 条件变量（condition variable）
- 事件（event）

**管理机制**

未命名对象在创建时：

1. 分配 `xnobject`：同样从 `registry_obj_slots` 中获取一个 `xnobject`。
2. 设置属性：
  - key：设置为 NULL，表示匿名对象。
  - objaddr：指向具体的内核对象。
3. 不插入哈希表：由于没有名称，匿名对象不需要插入到哈希表中。
4. 生成句柄：返回 `xnhandle_t`，供后续操作使用。

**访问方式**

任务在后续对未命名对象的操作中，使用句柄 `xnhandle_t` 直接访问对象，而不需要通过名称查找。这种方式提高了访问速度，满足实时系统对性能的要求。

#### xnregistry 的初始化流程

**初始化步骤**

在系统启动时会初始化 `xnregistry`，具体步骤包括：

1. 分配对象槽（registry_obj_slots）：
   - 分配固定数量的 `xnobject`，默认值为 4096。
2. 初始化空闲链表（free_object_list）：
   - 将所有分配的 `xnobject` 加入到空闲链表中，供后续分配使用。
3. 创建哈希表（object_index）：
   - 根据需要的哈希表大小，分配 `object_index` 数组，并初始化每个哈希桶。
4. 初始化同步机制（register_synch）：
   - 创建同步对象，确保对 `xnregistry` 的并发访问是线程安全的。