Windows-ядро Linux как реализация событий - PullRequest
0 голосов
/ 07 мая 2019

Нам нужно реализовать Windows-подобное ядро ​​для Linux.Эти функции должны вести себя как соответствующие KeInitializeEvent , KeSetEvent , KeResetEvent , KePulseEvent и KeWaitForSingleObject из Windowsядро. Синхронизация здесь называется автосброс , а Уведомление событие называется ручной сброс .Вот код:

Event.h

#define WAIT_FOREVER     -1

#define event_init(event, manual_reset, initial_state) __event_init(event, manual_reset, initial_state)
#define event_set(event) __event_set(event)
#define event_reset(event) __event_reset(event)
#define event_pulse(event) __event_pulse(event)
#define event_wait(event, ms_timeout) __event_wait(event, (ms_timeout == WAIT_FOREVER) ? (WAIT_FOREVER) : ((ms_timeout * HZ) / 1000))

typedef struct _wait_t
{
    atomic_t b;
    wait_queue_head_t q;
    struct list_head list;
} wait_t;

typedef struct _event_t
{
    struct list_head Wait;
    bool AutoReset;
    bool State;
} event_t;

void __event_init_lib(void);
void __event_init(event_t *event, bool manual_reset, bool initial_state);
bool __event_set(event_t *event);
bool __event_reset(event_t *event);
bool __event_pulse(event_t *event);
status_t __event_wait(event_t *event, time_t timeout);

Event.c

wait_t g_stor[100];
spinlock_t g_lock;

void __event_init_lib(void)
{
    wait_t *ptr;

    for (int i = 0; i < ARRAY_SIZE(g_stor); ++i)
    {
        ptr = &g_stor[i];
        atomic_set(&ptr->b, 2);
        init_waitqueue_head(&ptr->q);
        INIT_LIST_HEAD(&ptr->list);
    }

    spin_lock_init(&g_lock);
}

void __event_init(event_t *event, bool manual_reset, bool initial_state)
{
    INIT_LIST_HEAD(&event->Wait);

    event->State = initial_state;
    event->AutoReset = !manual_reset;
}

status_t __event_wait(event_t *event, time_t timeout)
{
    bool b;
    wait_t *ptr;
    status_t status;

    spin_lock(&g_lock);
    if (event->State)
    {
        if (event->AutoReset) event->State = false;
        spin_unlock(&g_lock);
        return s_success;
    }
    for (int i = 0; i < ARRAY_SIZE(g_stor); ++i)
    {
        ptr = &g_stor[i];
        if (atomic_cmpxchg(&ptr->b, 2, 0) == 2) break;
    }
    list_add_tail(&ptr->list, &event->Wait);            // note: we need to insert in the end of the list
    spin_unlock(&g_lock);

    if (timeout == WAIT_FOREVER) wait_event(ptr->q, b = (atomic_cmpxchg(&ptr->b, 1, 2) == 1));
    else wait_event_timeout(ptr->q, b = (atomic_cmpxchg(&ptr->b, 1, 2) == 1), timeout);

    if (b) status = s_success;
    else status = s_timeout;

    return status;
}

bool __event_set(event_t *event)
{
    bool PrevState;
    struct list_head *entry;
    wait_t *Wait;

    //if (!event->AutoReset && event->State) return true;
    spin_lock(&g_lock);
    PrevState = event->State;
    event->State = true;
    if (!PrevState && !list_empty(&event->Wait))             // check if we became signaled right now
                                                             // and we have waiters
    {
        if (event->AutoReset)
        {
            entry = event->Wait.next;
            Wait = container_of(entry, wait_t, list);
            atomic_set(&Wait->b, 1);
            wake_up(&(Wait->q));
            event->State = false;
            list_del(entry);
        }
        else
        {
            entry = event->Wait.next;
            while (entry != &event->Wait)
            {
                Wait = container_of(entry, wait_t, list);
                atomic_set(&Wait->b, 1);
                wake_up(&(Wait->q));
                entry = entry->next;
                list_del(entry->prev);
            }
        }
    }
    spin_unlock(&g_lock);
    return PrevState;
}

bool __event_reset(event_t *event)
{
    bool PrevState;

    spin_lock(&g_lock);
    PrevState = event->State;
    event->State = false;
    spin_unlock(&g_lock);
    return PrevState;
}

bool __event_pulse(event_t *event)
{
    bool PrevState;
    struct list_head *entry;
    wait_t *Wait;

    spin_lock(&g_lock);
    PrevState = event->State;
    if (!PrevState && !list_empty(&event->Wait))           // check if we became signaled right now
                                                           // and we have waiters
    {
        if (event->AutoReset)
        {
            entry = event->Wait.next;
            Wait = container_of(entry, wait_t, list);
            atomic_set(&Wait->b, 1);
            wake_up(&(Wait->q));
            list_del(entry);
        }
        else
        {
            entry = event->Wait.next;
            while (entry != &event->Wait)
            {
                Wait = container_of(entry, wait_t, list);
                atomic_set(&Wait->b, 1);
                wake_up(&(Wait->q));
                entry = entry->next;
                list_del(entry->prev);
            }
        }
    }
    event->State = false;
    spin_unlock(&g_lock);
    return PrevState;
}

Я думаю, что каждый ожидающий поток нуждается в собственной переменной условия, потому что если мы имеемодну переменную условия и установите ее в true , новый официант может прибыть и непреднамеренно пройти через wait_event , даже не засыпая.Таким образом, нам нужно вести список переменных условий, следовательно, чтобы пробудить правильный поток, нам также нужно несколько очередей ожидания.Также источник ReactOS предполагает, что событие поддерживает список официантов.

Поскольку мы не можем использовать переменные локального хранилища переменных в режиме ядра (по крайней мере, нелегко) Я решил реализовать массив блоков ожидания.Когда нам нужно вставить официанта в список, мы зацикливаем этот массив в поисках свободного блока ожидания.Это наводит меня на мысль, что нам нужно использовать одну глобальную блокировку, как ReactOS (блокировка диспетчера), а не отдельную блокировку для каждого объекта события.

Нам нужен объект события для нашего драйвера видеокамерыпортирован из винды.Кажется, все работает нормально, однако частота кадров в секунду иногда падает с 14 кадров в секунду до 10 (и изображение мерцает).Это заставило меня поверить, что с реализацией мероприятия что-то не так.

Если у вас есть предложения, поделитесь.Спасибо.

...