kernel: Add event queue implementation to wait for objects efficiently.
Based on hamishm's original patch from 2015, but heavily modified,
refactored, and reworked.
From the original commit message:
> When an object is deleted, a B_EVENT_INVALID event is delivered,
> and the object is unregistered from the queue.
>
> The special event flag B_EVENT_ONE_SHOT can be passed in when adding
> an object so that the object is automatically unregistered when an
> event is delivered.
Modifications to the original change include:
* Removed the public interface (syscalls remain private for the moment)
* Event list queueing/dequeueing almost entirely rewritten, including:
- Clear events field when dequeueing.
- Have B_EVENT_QUEUED actually indicate whether the event has been
appended to the linked list (or not), based around lock state.
The previous logic was prone to races and double-insertions.
- "Modify" is now just "Deselect + Select" performed at once;
previously it could cause use-after-frees.
- Unlock for deselect only once at the end of dequeue.
- Handle INVALID events still in the queue upon destruction,
fixing memory leaks.
* Deduplified code with wait_for_objects.
* Use of C++ virtual dispatch instead of C-style enum + function calls,
and BReferenceable plus destructors for teardown.
* Removed select/modify/delete flags. Select/Modify are now the same
operation on the syscall interface, and "Delete" is done when 0
is passed for "events". Additionally, the events selected can be fetched
by passing -1 for "events".
* Implemented level-triggered mode.
* Use of BStackOrHeapArray and other convenience routines in syscalls.
Change-Id: I1d2f094fd981c95215a59adbc087523c7bbbe40b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6745
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
a3f83f646c
commit
f66d2b46a8
@@ -636,7 +636,7 @@ enum {
|
||||
|
||||
B_EVENT_ACQUIRE_SEMAPHORE = 0x0001, /* semaphore can be acquired */
|
||||
|
||||
B_EVENT_INVALID = 0x1000 /* FD/port/sem/thread ID not or
|
||||
B_EVENT_INVALID = 0x1000, /* FD/port/sem/thread ID not or
|
||||
no longer valid (e.g. has been
|
||||
close/deleted) */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2015, Hamish Morrison, [email protected].
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_EVENT_QUEUE_H
|
||||
#define _KERNEL_EVENT_QUEUE_H
|
||||
|
||||
#include <OS.h>
|
||||
#include <event_queue_defs.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern int _user_event_queue_create(int openFlags);
|
||||
extern status_t _user_event_queue_select(int queue, event_wait_info* userInfos,
|
||||
int numInfos);
|
||||
extern ssize_t _user_event_queue_wait(int queue, event_wait_info* infos,
|
||||
int numInfos, uint32 flags, bigtime_t timeout);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct event_queue;
|
||||
struct file_descriptor;
|
||||
struct io_context;
|
||||
struct net_socket;
|
||||
@@ -54,6 +55,7 @@ struct file_descriptor {
|
||||
struct vnode *vnode;
|
||||
struct fs_mount *mount;
|
||||
struct net_socket *socket;
|
||||
struct event_queue *queue;
|
||||
} u;
|
||||
void *cookie;
|
||||
int32 open_mode;
|
||||
@@ -71,7 +73,8 @@ enum fd_types {
|
||||
FDTYPE_INDEX,
|
||||
FDTYPE_INDEX_DIR,
|
||||
FDTYPE_QUERY,
|
||||
FDTYPE_SOCKET
|
||||
FDTYPE_SOCKET,
|
||||
FDTYPE_EVENT_QUEUE
|
||||
};
|
||||
|
||||
// additional open mode - kernel special
|
||||
|
||||
@@ -15,18 +15,12 @@ struct select_sync;
|
||||
|
||||
|
||||
typedef struct select_info {
|
||||
struct select_info* next; // next in the object's list
|
||||
struct select_sync* sync;
|
||||
int32 events;
|
||||
uint16 selected_events;
|
||||
struct select_info* next;
|
||||
struct select_sync* sync;
|
||||
int32 events;
|
||||
uint16 selected_events;
|
||||
} select_info;
|
||||
|
||||
typedef struct select_sync {
|
||||
int32 ref_count;
|
||||
sem_id sem;
|
||||
uint32 count;
|
||||
struct select_info* set;
|
||||
} select_sync;
|
||||
|
||||
#define SELECT_FLAG(type) (1L << (type - 1))
|
||||
|
||||
@@ -39,9 +33,10 @@ typedef struct select_sync {
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern void acquire_select_sync(select_sync* sync);
|
||||
extern void put_select_sync(select_sync* sync);
|
||||
extern status_t notify_select_events(select_info* info, uint16 events);
|
||||
extern void notify_select_events_list(select_info* list, uint16 events);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2023, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SYSTEM_EVENT_QUEUE_DEFS_H
|
||||
#define _SYSTEM_EVENT_QUEUE_DEFS_H
|
||||
|
||||
|
||||
// extends B_EVENT_* constants defined in OS.h
|
||||
enum {
|
||||
B_EVENT_LEVEL_TRIGGERED = (1 << 26), /* Event is level-triggered, not edge-triggered */
|
||||
B_EVENT_ONE_SHOT = (1 << 27), /* Delete event after delivery */
|
||||
|
||||
/* bits 28 through 30 are reserved for the kernel */
|
||||
};
|
||||
|
||||
|
||||
typedef struct event_wait_info {
|
||||
int32 object;
|
||||
uint16 type;
|
||||
int32 events; /* select(): > 0 to select, -1 to get selection, 0 to deselect */
|
||||
void* user_data;
|
||||
} event_wait_info;
|
||||
|
||||
|
||||
#endif /* _SYSTEM_EVENT_QUEUE_DEFS_H */
|
||||
@@ -23,6 +23,7 @@ extern "C" {
|
||||
|
||||
struct attr_info;
|
||||
struct dirent;
|
||||
struct event_wait_info;
|
||||
struct fd_info;
|
||||
struct fd_set;
|
||||
struct fs_info;
|
||||
@@ -74,6 +75,12 @@ extern status_t _kern_get_safemode_option(const char *parameter,
|
||||
extern ssize_t _kern_wait_for_objects(object_wait_info* infos, int numInfos,
|
||||
uint32 flags, bigtime_t timeout);
|
||||
|
||||
extern int _kern_event_queue_create(int openFlags);
|
||||
extern status_t _kern_event_queue_select(int queue,
|
||||
struct event_wait_info* userInfos, int numInfos);
|
||||
extern ssize_t _kern_event_queue_wait(int queue, struct event_wait_info* infos,
|
||||
int numInfos, uint32 flags, bigtime_t timeout);
|
||||
|
||||
/* user mutex functions */
|
||||
extern status_t _kern_mutex_lock(int32* mutex, const char* name,
|
||||
uint32 flags, bigtime_t timeout);
|
||||
|
||||
Reference in New Issue
Block a user