3

我在我的 macOS 内核扩展中使用同步 KPI 来验证一个功能是否在另一个功能启动之前完全执行(当然这两个功能都在不同的线程中执行)。

这些是同步方法:

msleep(void *channel,lck_mtx_t *mtx,int priority,const char *wmesg,  struct  timespec *timeout);
wakeup(void *channel);

channel指向表示第一个函数的布尔值的指针也已完全执行。

这是我在第一个函数中的实现:

OSIncrementAtomic(channel);
wakeup(channel);

在我等待channel设置的另一个功能上:

msleep(channel, NULL, 0, "", ts);

但是,如果第一个函数在第二个函数之前终止(这是常见的情况),我会等待超时ts

我的问题是是否有办法跳过已经发生msleep的情况wakeup

谢谢,

4

2 回答 2

2

您使用msleep.

首先,channel是一个不透明的值,而不是“指向布尔值的指针”;你不增加它,它不会被调用修改。相反,您只需确保它是唯一的,即不被其他不相关的调用使用msleep。约定是使用相关数据结构的内存地址来实现唯一性。如果在您的情况下您无法确保msleep之前调用过wakeup,那么您将使用马赫信号量,而不是msleep/ wakeup

另一个问题是,正如@mrdvlpr 已经在评论中指出的那样,msleep需要一个互斥锁才能唤醒。如果你用 调用它mtx=NULL,它会无限期地休眠,并且wakeup在同一个频道上调用 to 不会有任何效果。wakeup如果您想稍后用or唤醒wakeup_once,您需要提供一个有效且锁定的互斥锁而不是NULL.

XNU中没有超时的最小但功能调用msleep如下所示:

lck_grp_t *lck_grp;
lck_mtx_t *lck_mtx;

lck_grp = lck_grp_alloc_init("com.example.mslpex", LCK_GRP_ATTR_NULL);
if (!lck_grp)
    /* handle failure */
lck_mtx = lck_mtx_alloc_init(lck_grp, LCK_ATTR_NULL);
if (!lck_mtx)
    /* handle failure */

/* ... */

lck_mtx_lock(lck_mtx);
error = msleep(channel, lck_mtx, pri|PDROP, "mslpex", NULL);
if (error)
    /* handle failure */
else
    /* handle success */

/* ... */

lck_mtx_free(lck_mtx, lck_grp);
lck_grp_free(lck_grp);

相应的叫醒电话很简单:

wakeup(channel);

为了系统稳定性,您可能希望在调用时使用超时,以便从未按预期调用msleep的情况中恢复。wakeup

于 2018-02-16T08:30:25.503 回答
1

与互斥锁一起使用lck_mtx_sleep_deadline()(或包装器)。IOLockSleepDeadline()在等待的线程上:

  1. 锁定互斥锁
  2. 检查等待条件(第一个函数还在运行吗?)
  3. 如果是,请致电lck_mtx_sleep_deadline()
  4. 解锁互斥锁

while()根据您的情况,您可能希望使步骤 2+3循环。

在您的“第一个功能”中:

  1. 锁定互斥锁
  2. 清除等待条件(增量通道)
  3. 向事件发送唤醒。(例如thread_wakeup_prim((event_t) event, oneThread, THREAD_AWAKENED);
  4. 解锁互斥锁。

您可能也可以以某种方式直接使用较低级别的msleep()/来完成所有这些wakeup(),但我对那个 API 不太熟悉。

于 2017-11-01T14:46:43.623 回答