* Renamed fs/vfs_select.cpp to wait_for_objects.cpp and got rid of
vfs_select.h, respectively moved most of it into the new kernel private header wait_for_objects.h. * Added new experimental API functions wait_for_objects[_etc](). They work pretty much like poll(), but also for semaphores, ports, and threads. * Removed the "ref" parameter from notify_select_events() and the select_sync_pool functions as well as from fd_ops::fd_[de]select(). It is no longer needed. The FS interface select() hook still has it, though -- the VFS will always pass 0. * de]select_fd() take a select_info* instead of a select_sync* + ref pair, now. Added respective functions for semaphores, ports, and threads. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22416 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
a82d70c719
commit
636bfc08ae
@ -31,11 +31,7 @@ enum select_events {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef COMPILE_FOR_R5
|
||||
extern void notify_select_event(struct selectsync *sync, uint32 ref);
|
||||
#else
|
||||
extern status_t notify_select_event(struct selectsync *sync, uint32 ref, uint8 event);
|
||||
#endif
|
||||
extern status_t notify_select_event(struct selectsync *sync, uint8 event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -658,6 +658,52 @@ extern status_t _get_system_info(system_info *info, size_t size);
|
||||
extern int32 is_computer_on(void);
|
||||
extern double is_computer_on_fire(void);
|
||||
|
||||
|
||||
// WARNING: Experimental API!
|
||||
|
||||
enum {
|
||||
B_OBJECT_TYPE_FD = 0,
|
||||
B_OBJECT_TYPE_SEMAPHORE = 1,
|
||||
B_OBJECT_TYPE_PORT = 2,
|
||||
B_OBJECT_TYPE_THREAD = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
B_EVENT_READ = 0x0001, // FD/port readable
|
||||
B_EVENT_WRITE = 0x0002, // FD/port writable
|
||||
B_EVENT_ERROR = 0x0004, // FD error
|
||||
B_EVENT_PRIORITY_READ = 0x0008, // FD priority readable
|
||||
B_EVENT_PRIORITY_WRITE = 0x0010, // FD priority writable
|
||||
B_EVENT_HIGH_PRIORITY_READ = 0x0020, // FD high priority readable
|
||||
B_EVENT_HIGH_PRIORITY_WRITE = 0x0040, // FD high priority writable
|
||||
B_EVENT_DISCONNECTED = 0x0080, // FD disconnected
|
||||
|
||||
B_EVENT_ACQUIRE_SEMAPHORE = 0x0001, // semaphore can be acquired
|
||||
|
||||
B_EVENT_INVALID = 0x1000 // FD/port/sem/thread ID not or
|
||||
// no longer valid (e.g. has been
|
||||
// close/deleted)
|
||||
};
|
||||
|
||||
typedef struct object_wait_info {
|
||||
int32 object; // ID of the object
|
||||
uint16 type; // type of the object
|
||||
uint16 events; // events mask
|
||||
} object_wait_info;
|
||||
|
||||
// wait_for_objects[_etc]() waits until at least one of the specified events or,
|
||||
// if given, the timeout occurred. When entering the function the
|
||||
// object_wait_info::events field specifies the events for each object the
|
||||
// caller is interested in. When the function returns the fields reflect the
|
||||
// events that actually occurred. The events B_EVENT_INVALID, B_EVENT_ERROR,
|
||||
// and B_EVENT_DISCONNECTED don't need to be specified. They will always be
|
||||
// reported, when they occur.
|
||||
|
||||
extern ssize_t wait_for_objects(object_wait_info* infos, int numInfos);
|
||||
extern ssize_t wait_for_objects_etc(object_wait_info* infos, int numInfos,
|
||||
uint32 flags, bigtime_t timeout);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -17,14 +17,14 @@ extern "C" {
|
||||
|
||||
struct file_descriptor;
|
||||
struct selectsync;
|
||||
struct select_sync;
|
||||
struct select_info;
|
||||
|
||||
struct fd_ops {
|
||||
status_t (*fd_read)(struct file_descriptor *, off_t pos, void *buffer, size_t *length);
|
||||
status_t (*fd_write)(struct file_descriptor *, off_t pos, const void *buffer, size_t *length);
|
||||
off_t (*fd_seek)(struct file_descriptor *, off_t pos, int seekType);
|
||||
status_t (*fd_ioctl)(struct file_descriptor *, ulong op, void *buffer, size_t length);
|
||||
status_t (*fd_select)(struct file_descriptor *, uint8 event, uint32 ref,
|
||||
status_t (*fd_select)(struct file_descriptor *, uint8 event,
|
||||
struct selectsync *sync);
|
||||
status_t (*fd_deselect)(struct file_descriptor *, uint8 event,
|
||||
struct selectsync *sync);
|
||||
@ -77,10 +77,8 @@ extern void close_fd(struct file_descriptor *descriptor);
|
||||
extern void put_fd(struct file_descriptor *descriptor);
|
||||
extern void disconnect_fd(struct file_descriptor *descriptor);
|
||||
extern void inc_fd_ref_count(struct file_descriptor *descriptor);
|
||||
extern status_t select_fd(int fd, struct select_sync *sync, uint32 ref,
|
||||
bool kernel);
|
||||
extern status_t deselect_fd(int fd, struct select_sync *sync, uint32 ref,
|
||||
bool kernel);
|
||||
extern status_t select_fd(int32 fd, struct select_info *info, bool kernel);
|
||||
extern status_t deselect_fd(int32 fd, struct select_info *info, bool kernel);
|
||||
extern bool fd_is_valid(int fd, bool kernel);
|
||||
extern struct vnode *fd_vnode(struct file_descriptor *descriptor);
|
||||
|
||||
|
@ -17,7 +17,7 @@ extern "C" {
|
||||
|
||||
|
||||
status_t add_select_sync_pool_entry(select_sync_pool **pool, selectsync *sync,
|
||||
uint32 ref, uint8 event);
|
||||
uint8 event);
|
||||
status_t remove_select_sync_pool_entry(select_sync_pool **pool,
|
||||
selectsync *sync, uint8 event);
|
||||
void delete_select_sync_pool(select_sync_pool *pool);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <iovec.h>
|
||||
|
||||
struct kernel_args;
|
||||
struct select_info;
|
||||
|
||||
|
||||
#define PORT_FLAG_USE_USER_MEMCPY 0x80000000
|
||||
@ -23,6 +24,9 @@ int delete_owned_ports(team_id owner);
|
||||
int32 port_max_ports(void);
|
||||
int32 port_used_ports(void);
|
||||
|
||||
status_t select_port(int32 object, struct select_info *info, bool kernel);
|
||||
status_t deselect_port(int32 object, struct select_info *info, bool kernel);
|
||||
|
||||
// currently private API
|
||||
status_t writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs,
|
||||
size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <thread.h>
|
||||
|
||||
struct kernel_args;
|
||||
struct select_info;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -25,6 +26,10 @@ extern status_t sem_interrupt_thread(struct thread *t);
|
||||
extern int32 sem_used_sems(void);
|
||||
extern int32 sem_max_sems(void);
|
||||
|
||||
extern status_t select_sem(int32 object, struct select_info *info, bool kernel);
|
||||
extern status_t deselect_sem(int32 object, struct select_info *info,
|
||||
bool kernel);
|
||||
|
||||
extern sem_id create_sem_etc(int32 count, const char *name, team_id owner);
|
||||
|
||||
/* user calls */
|
||||
|
@ -53,6 +53,10 @@ extern int _kern_setrlimit(int resource, const struct rlimit * rlp);
|
||||
extern status_t _kern_shutdown(bool reboot);
|
||||
extern status_t _kern_get_safemode_option(const char *parameter, char *buffer, size_t *_bufferSize);
|
||||
|
||||
extern ssize_t _kern_wait_for_objects(object_wait_info* infos, int numInfos,
|
||||
uint32 flags, bigtime_t timeout);
|
||||
|
||||
|
||||
/* sem functions */
|
||||
extern sem_id _kern_create_sem(int count, const char *name);
|
||||
extern status_t _kern_delete_sem(sem_id id);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <arch/thread.h>
|
||||
|
||||
struct kernel_args;
|
||||
struct select_info;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -65,6 +66,9 @@ thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
|
||||
status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
||||
status_t *_returnCode);
|
||||
|
||||
status_t select_thread(int32 object, struct select_info *info, bool kernel);
|
||||
status_t deselect_thread(int32 object, struct select_info *info, bool kernel);
|
||||
|
||||
// used in syscalls.c
|
||||
status_t _user_set_thread_priority(thread_id thread, int32 newPriority);
|
||||
status_t _user_rename_thread(thread_id thread, const char *name);
|
||||
|
@ -54,6 +54,7 @@ typedef enum job_control_state {
|
||||
|
||||
struct image;
|
||||
// defined in image.c
|
||||
struct select_info;
|
||||
|
||||
struct death_entry {
|
||||
struct list_link link;
|
||||
@ -234,6 +235,8 @@ struct thread {
|
||||
struct list waiters;
|
||||
} exit;
|
||||
|
||||
struct select_info *select_infos;
|
||||
|
||||
struct thread_debug_info debug_info;
|
||||
|
||||
// stack
|
||||
|
52
headers/private/kernel/wait_for_objects.h
Normal file
52
headers/private/kernel/wait_for_objects.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_WAIT_FOR_OBJECTS_H
|
||||
#define _KERNEL_WAIT_FOR_OBJECTS_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
struct select_sync;
|
||||
|
||||
|
||||
typedef struct select_info {
|
||||
struct select_info* next; // next in the object's list
|
||||
struct select_sync* sync;
|
||||
uint16 selected_events;
|
||||
uint16 events;
|
||||
} select_info;
|
||||
|
||||
typedef struct select_sync {
|
||||
vint32 ref_count;
|
||||
benaphore lock;
|
||||
sem_id sem;
|
||||
uint32 count;
|
||||
struct select_info* set;
|
||||
} select_sync;
|
||||
|
||||
#define SELECT_FLAG(type) (1L << (type - 1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
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);
|
||||
|
||||
extern ssize_t _user_wait_for_objects(object_wait_info* userInfos,
|
||||
int numInfos, uint32 flags, bigtime_t timeout);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _KERNEL_WAIT_FOR_OBJECTS_H
|
@ -547,7 +547,6 @@ public:
|
||||
SelectRequest() : FileRequest(SELECT_REQUEST) {}
|
||||
|
||||
uint8 event;
|
||||
uint32 ref;
|
||||
selectsync* sync;
|
||||
};
|
||||
|
||||
@ -1394,7 +1393,6 @@ public:
|
||||
NotifySelectEventRequest() : Request(NOTIFY_SELECT_EVENT_REQUEST) {}
|
||||
|
||||
selectsync* sync;
|
||||
uint32 ref;
|
||||
uint8 event;
|
||||
bool unspecifiedEvent;
|
||||
};
|
||||
|
@ -466,7 +466,7 @@ random_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
#ifdef COMPILE_FOR_R5
|
||||
notify_select_event(sync, ref);
|
||||
#else
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
#endif
|
||||
} else if (event == B_SELECT_WRITE) {
|
||||
/* we're not writable */
|
||||
|
@ -1676,7 +1676,7 @@ tty_select(tty_cookie *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
if (!ttyReference.IsLocked()) {
|
||||
TRACE(("tty_select() done: cookie %p already closed\n", cookie));
|
||||
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -1690,8 +1690,7 @@ tty_select(tty_cookie *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
otherTTY = NULL;
|
||||
|
||||
// add the event to the TTY's pool
|
||||
status_t error = add_select_sync_pool_entry(&tty->select_pool, sync, ref,
|
||||
event);
|
||||
status_t error = add_select_sync_pool_entry(&tty->select_pool, sync, event);
|
||||
if (error != B_OK) {
|
||||
TRACE(("tty_select() done: add_select_sync_pool_entry() failed: %lx\n",
|
||||
error));
|
||||
@ -1708,7 +1707,7 @@ tty_select(tty_cookie *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
case B_SELECT_READ:
|
||||
if (tty->reader_queue.IsEmpty()
|
||||
&& line_buffer_readable(tty->input_buffer) > 0) {
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1716,7 +1715,7 @@ tty_select(tty_cookie *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
{
|
||||
// writes go to the other TTY
|
||||
if (!otherTTY) {
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1730,7 +1729,7 @@ tty_select(tty_cookie *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||
if (!echo
|
||||
|| (tty->writer_queue.IsEmpty()
|
||||
&& line_buffer_writable(tty->input_buffer) > 0)) {
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,13 +211,13 @@ KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request)
|
||||
if (request->unspecifiedEvent) {
|
||||
// old style add-ons can't provide an event argument; we shoot
|
||||
// all events
|
||||
notify_select_event(request->sync, request->ref, B_SELECT_READ);
|
||||
notify_select_event(request->sync, request->ref, B_SELECT_WRITE);
|
||||
notify_select_event(request->sync, request->ref, B_SELECT_ERROR);
|
||||
notify_select_event(request->sync, B_SELECT_READ);
|
||||
notify_select_event(request->sync, B_SELECT_WRITE);
|
||||
notify_select_event(request->sync, B_SELECT_ERROR);
|
||||
} else {
|
||||
PRINT(("notify_select_event(%p, %lu, %d)\n", request->sync,
|
||||
request->ref, (int)request->event));
|
||||
notify_select_event(request->sync, request->ref, request->event);
|
||||
PRINT(("notify_select_event(%p, %d)\n", request->sync,
|
||||
(int)request->event));
|
||||
notify_select_event(request->sync, request->event);
|
||||
}
|
||||
} else
|
||||
result = B_BAD_VALUE;
|
||||
|
@ -736,7 +736,7 @@ Volume::Select(fs_vnode node, fs_cookie cookie, uint8 event, uint32 ref,
|
||||
{
|
||||
// check capability
|
||||
if (!fFileSystem->HasCapability(FS_CAPABILITY_SELECT)) {
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -757,7 +757,6 @@ Volume::Select(fs_vnode node, fs_cookie cookie, uint8 event, uint32 ref,
|
||||
request->node = node;
|
||||
request->fileCookie = cookie;
|
||||
request->event = event;
|
||||
request->ref = ref;
|
||||
request->sync = sync;
|
||||
|
||||
// add a selectsync entry
|
||||
|
@ -224,7 +224,7 @@ BeOSKernelVolume::Select(fs_vnode node, fs_cookie cookie, uint8 event,
|
||||
uint32 ref, selectsync* sync)
|
||||
{
|
||||
if (!fFSOps->select) {
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, ref, event, false);
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, event, false);
|
||||
return B_OK;
|
||||
}
|
||||
return fFSOps->select(fVolumeCookie, node, cookie, event, ref, sync);
|
||||
|
@ -194,7 +194,7 @@ HaikuKernelVolume::Select(fs_vnode node, fs_cookie cookie, uint8 event,
|
||||
uint32 ref, selectsync* sync)
|
||||
{
|
||||
if (!fFSModule->select) {
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, ref, event, false);
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, event, false);
|
||||
return B_OK;
|
||||
}
|
||||
return fFSModule->select(fVolumeCookie, node, cookie, event, ref, sync);
|
||||
|
@ -627,7 +627,7 @@ UserlandRequestHandler::_HandleRequest(SelectRequest* request)
|
||||
if (result == B_OK) {
|
||||
RequestThreadContext context(volume);
|
||||
result = volume->Select(request->node, request->fileCookie,
|
||||
request->event, request->ref, request->sync);
|
||||
request->event, 0, request->sync);
|
||||
}
|
||||
|
||||
// prepare the reply
|
||||
|
@ -82,7 +82,7 @@ notify_listener(int op, nspace_id nsid, ino_t vnida, ino_t vnidb,
|
||||
void
|
||||
notify_select_event(selectsync *sync, uint32 ref)
|
||||
{
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, ref, 0, true);
|
||||
UserlandFS::KernelEmu::notify_select_event(sync, 0, true);
|
||||
}
|
||||
|
||||
// send_notification
|
||||
|
@ -76,9 +76,9 @@ notify_attribute_changed(dev_t device, ino_t node, const char *attribute,
|
||||
|
||||
// notify_select_event
|
||||
status_t
|
||||
notify_select_event(selectsync *sync, uint32 ref, uint8 event)
|
||||
notify_select_event(selectsync *sync, uint8 event)
|
||||
{
|
||||
return UserlandFS::KernelEmu::notify_select_event(sync, ref, event, false);
|
||||
return UserlandFS::KernelEmu::notify_select_event(sync, event, false);
|
||||
}
|
||||
|
||||
// notify_query_entry_created
|
||||
|
@ -170,8 +170,8 @@ UserlandFS::KernelEmu::notify_listener(int32 operation, uint32 details,
|
||||
|
||||
// notify_select_event
|
||||
status_t
|
||||
UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint32 ref,
|
||||
uint8 event, bool unspecifiedEvent)
|
||||
UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint8 event,
|
||||
bool unspecifiedEvent)
|
||||
{
|
||||
// get the request port and the file system
|
||||
RequestPort* port;
|
||||
@ -188,7 +188,6 @@ UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint32 ref,
|
||||
return error;
|
||||
|
||||
request->sync = sync;
|
||||
request->ref = ref;
|
||||
request->event = event;
|
||||
request->unspecifiedEvent = unspecifiedEvent;
|
||||
|
||||
|
@ -17,7 +17,7 @@ void free_path(char *p);
|
||||
status_t notify_listener(int32 operation, uint32 details, dev_t device,
|
||||
ino_t oldDirectory, ino_t directory, ino_t node,
|
||||
const char* oldName, const char* name);
|
||||
status_t notify_select_event(selectsync *sync, uint32 ref, uint8 event,
|
||||
status_t notify_select_event(selectsync *sync, uint8 event,
|
||||
bool unspecifiedEvent);
|
||||
status_t notify_query(port_id port, int32 token, int32 operation,
|
||||
dev_t device, ino_t directory, const char* name, ino_t node);
|
||||
|
@ -470,7 +470,7 @@ socket_request_notification(net_socket *_socket, uint8 event, uint32 ref,
|
||||
benaphore_lock(&socket->lock);
|
||||
|
||||
status_t status = add_select_sync_pool_entry(&socket->select_pool, sync,
|
||||
ref, event);
|
||||
event);
|
||||
|
||||
benaphore_unlock(&socket->lock);
|
||||
|
||||
@ -486,7 +486,7 @@ socket_request_notification(net_socket *_socket, uint8 event, uint32 ref,
|
||||
ssize_t available = socket_read_avail(socket);
|
||||
if ((ssize_t)socket->receive.low_water_mark <= available
|
||||
|| available < B_OK)
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
break;
|
||||
}
|
||||
case B_SELECT_WRITE:
|
||||
@ -494,7 +494,7 @@ socket_request_notification(net_socket *_socket, uint8 event, uint32 ref,
|
||||
ssize_t available = socket_send_avail(socket);
|
||||
if ((ssize_t)socket->send.low_water_mark <= available
|
||||
|| available < B_OK)
|
||||
notify_select_event(sync, ref, event);
|
||||
notify_select_event(sync, event);
|
||||
break;
|
||||
}
|
||||
case B_SELECT_ERROR:
|
||||
|
@ -40,6 +40,7 @@ KernelMergeObject kernel_core.o :
|
||||
team.cpp
|
||||
thread.cpp
|
||||
timer.c
|
||||
wait_for_objects.cpp
|
||||
|
||||
: $(TARGET_KERNEL_PIC_CCFLAGS)
|
||||
;
|
||||
|
@ -13,7 +13,6 @@ KernelMergeObject kernel_fs.o :
|
||||
vfs.cpp
|
||||
vfs_boot.cpp
|
||||
vfs_net_boot.cpp
|
||||
vfs_select.cpp
|
||||
node_monitor.cpp
|
||||
IOScheduler.cpp
|
||||
KPath.cpp
|
||||
|
@ -1839,7 +1839,7 @@ devfs_select(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, uint8 event,
|
||||
|
||||
// If the device has no select() hook, notify select() now.
|
||||
if (!vnode->stream.u.dev.info->select)
|
||||
return notify_select_event((selectsync*)sync, ref, event);
|
||||
return notify_select_event((selectsync*)sync, event);
|
||||
|
||||
return vnode->stream.u.dev.info->select(cookie->device_cookie, event, ref,
|
||||
(selectsync*)sync);
|
||||
|
@ -4,7 +4,6 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <fd.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -15,8 +14,7 @@
|
||||
#include <syscalls.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <vfs.h>
|
||||
|
||||
#include "vfs_select.h"
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
|
||||
//#define TRACE_FD
|
||||
@ -448,6 +446,7 @@ deselect_select_infos(file_descriptor* descriptor, select_info* infos)
|
||||
}
|
||||
}
|
||||
|
||||
notify_select_events(info, B_EVENT_INVALID);
|
||||
info = info->next;
|
||||
put_select_sync(sync);
|
||||
}
|
||||
@ -455,9 +454,10 @@ deselect_select_infos(file_descriptor* descriptor, select_info* infos)
|
||||
|
||||
|
||||
status_t
|
||||
select_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
select_fd(int32 fd, struct select_info* info, bool kernel)
|
||||
{
|
||||
TRACE(("select_fd(fd = %d, selectsync = %p, ref = %lu, 0x%x)\n", fd, sync, ref, sync->set[ref].selected_events));
|
||||
TRACE(("select_fd(fd = %d, info = %p (%p), 0x%x)\n", fd, info,
|
||||
info->sync, info.selected_events));
|
||||
|
||||
FDGetter fdGetter;
|
||||
// define before the context locker, so it will be destroyed after it
|
||||
@ -469,7 +469,6 @@ select_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
if (descriptor == NULL)
|
||||
return B_FILE_ERROR;
|
||||
|
||||
select_info* info = &sync->set[ref];
|
||||
if (info->selected_events == 0)
|
||||
return B_OK;
|
||||
|
||||
@ -485,7 +484,7 @@ select_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
|
||||
// as long as the info is in the list, we keep a reference to the sync
|
||||
// object
|
||||
atomic_add(&sync->ref_count, 1);
|
||||
atomic_add(&info->sync->ref_count, 1);
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
@ -494,7 +493,7 @@ select_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
|
||||
for (uint16 event = 1; event < 16; event++) {
|
||||
if (info->selected_events & SELECT_FLAG(event)
|
||||
&& descriptor->ops->fd_select(descriptor, event, ref,
|
||||
&& descriptor->ops->fd_select(descriptor, event,
|
||||
(selectsync*)info) == B_OK) {
|
||||
selectedEvents |= SELECT_FLAG(event);
|
||||
}
|
||||
@ -503,18 +502,18 @@ select_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
|
||||
// if nothing has been selected, we deselect immediately
|
||||
if (selectedEvents == 0)
|
||||
deselect_fd(fd, sync, ref, kernel);
|
||||
deselect_fd(fd, info, kernel);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
deselect_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
deselect_fd(int32 fd, struct select_info* info, bool kernel)
|
||||
{
|
||||
TRACE(("deselect_fd(fd = %d, selectsync = %p, ref = %lu)\n", fd, sync, ref));
|
||||
TRACE(("deselect_fd(fd = %d, info = %p (%p), 0x%x)\n", fd, info,
|
||||
info->sync, info.selected_events));
|
||||
|
||||
select_info* info = &sync->set[ref];
|
||||
if (info->selected_events == 0)
|
||||
return B_OK;
|
||||
|
||||
@ -552,7 +551,7 @@ deselect_fd(int fd, struct select_sync* sync, uint32 ref, bool kernel)
|
||||
}
|
||||
}
|
||||
|
||||
put_select_sync(sync);
|
||||
put_select_sync(info->sync);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -12,20 +12,19 @@
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <Select.h>
|
||||
|
||||
#include <condition_variable.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <debug.h>
|
||||
#include <khash.h>
|
||||
#include <lock.h>
|
||||
#include <select_sync_pool.h>
|
||||
#include <team.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/ring_buffer.h>
|
||||
#include <vfs.h>
|
||||
#include "vfs_select.h"
|
||||
#include <select_sync_pool.h>
|
||||
#include <debug.h>
|
||||
#include <khash.h>
|
||||
#include <lock.h>
|
||||
#include <vm.h>
|
||||
#include <team.h>
|
||||
|
||||
|
||||
//#define TRACE_PIPEFS
|
||||
@ -960,7 +959,7 @@ Inode::Select(uint8 event, uint32 ref, selectsync *sync, int openMode)
|
||||
} else
|
||||
return B_NOT_ALLOWED;
|
||||
|
||||
if (add_select_sync_pool_entry(pool, sync, ref, event) != B_OK)
|
||||
if (add_select_sync_pool_entry(pool, sync, event) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// signal right away, if the condition holds already
|
||||
@ -968,12 +967,12 @@ Inode::Select(uint8 event, uint32 ref, selectsync *sync, int openMode)
|
||||
if (event == B_SELECT_WRITE
|
||||
&& (fBuffer.Writable() > 0 || fReaderCount == 0)
|
||||
|| event == B_SELECT_ERROR && fReaderCount == 0) {
|
||||
return notify_select_event(sync, ref, event);
|
||||
return notify_select_event(sync, event);
|
||||
}
|
||||
} else {
|
||||
if (event == B_SELECT_READ
|
||||
&& (fBuffer.Readable() > 0 || fWriterCount == 0)) {
|
||||
return notify_select_event(sync, ref, event);
|
||||
return notify_select_event(sync, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ static status_t file_write(struct file_descriptor *, off_t pos, const void *buff
|
||||
static off_t file_seek(struct file_descriptor *, off_t pos, int seek_type);
|
||||
static void file_free_fd(struct file_descriptor *);
|
||||
static status_t file_close(struct file_descriptor *);
|
||||
static status_t file_select(struct file_descriptor *, uint8 event, uint32 ref,
|
||||
static status_t file_select(struct file_descriptor *, uint8 event,
|
||||
struct selectsync *sync);
|
||||
static status_t file_deselect(struct file_descriptor *, uint8 event,
|
||||
struct selectsync *sync);
|
||||
@ -3894,7 +3894,7 @@ file_seek(struct file_descriptor *descriptor, off_t pos, int seekType)
|
||||
|
||||
|
||||
static status_t
|
||||
file_select(struct file_descriptor *descriptor, uint8 event, uint32 ref,
|
||||
file_select(struct file_descriptor *descriptor, uint8 event,
|
||||
struct selectsync *sync)
|
||||
{
|
||||
FUNCTION(("file_select(%p, %u, %lu, %p)\n", descriptor, event, ref, sync));
|
||||
@ -3903,10 +3903,10 @@ file_select(struct file_descriptor *descriptor, uint8 event, uint32 ref,
|
||||
|
||||
// If the FS has no select() hook, notify select() now.
|
||||
if (FS_CALL(vnode, select) == NULL)
|
||||
return notify_select_event(sync, ref, event);
|
||||
return notify_select_event(sync, event);
|
||||
|
||||
return FS_CALL(vnode, select)(vnode->mount->cookie, vnode->private_node,
|
||||
descriptor->cookie, event, ref, sync);
|
||||
descriptor->cookie, event, 0, sync);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VFS_SELECT_H
|
||||
#define VFS_SELECT_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <Select.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
|
||||
struct select_sync;
|
||||
|
||||
typedef struct select_info {
|
||||
select_info* next; // next in the IO context's list
|
||||
select_sync* sync;
|
||||
uint16 selected_events;
|
||||
uint16 events;
|
||||
} select_info;
|
||||
|
||||
typedef struct select_sync {
|
||||
vint32 ref_count;
|
||||
benaphore lock;
|
||||
sem_id sem;
|
||||
uint32 count;
|
||||
select_info* set;
|
||||
} select_sync;
|
||||
|
||||
#define SELECT_FLAG(type) (1L << (type - 1))
|
||||
|
||||
struct select_sync_pool_entry
|
||||
: DoublyLinkedListLinkImpl<select_sync_pool_entry> {
|
||||
selectsync *sync;
|
||||
uint32 ref;
|
||||
uint16 events;
|
||||
};
|
||||
|
||||
typedef DoublyLinkedList<select_sync_pool_entry> SelectSyncPoolEntryList;
|
||||
|
||||
struct select_sync_pool {
|
||||
SelectSyncPoolEntryList entries;
|
||||
};
|
||||
|
||||
void put_select_sync(select_sync* sync);
|
||||
|
||||
status_t notify_select_events(select_info* info, uint16 events);
|
||||
|
||||
#endif /* VFS_SELECT_H */
|
@ -18,6 +18,7 @@
|
||||
#include <util/list.h>
|
||||
#include <arch/int.h>
|
||||
#include <cbuf.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#include <iovec.h>
|
||||
#include <string.h>
|
||||
@ -49,6 +50,7 @@ struct port_entry {
|
||||
sem_id read_sem;
|
||||
sem_id write_sem;
|
||||
int32 total_count; // messages read from port since creation
|
||||
select_info *select_infos;
|
||||
struct list msg_queue;
|
||||
};
|
||||
|
||||
@ -312,6 +314,14 @@ dump_port_info(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
notify_port_select_events(int slot, uint16 events)
|
||||
{
|
||||
if (sPorts[slot].select_infos)
|
||||
notify_select_events_list(sPorts[slot].select_infos, events);
|
||||
}
|
||||
|
||||
|
||||
/** this function cycles through the ports table, deleting all
|
||||
* the ports that are owned by the passed team_id
|
||||
*/
|
||||
@ -499,6 +509,7 @@ create_port(int32 queueLength, const char *name)
|
||||
|
||||
list_init(&sPorts[i].msg_queue);
|
||||
sPorts[i].total_count = 0;
|
||||
sPorts[i].select_infos = NULL;
|
||||
id = sPorts[i].id;
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[i]);
|
||||
@ -565,6 +576,9 @@ close_port(port_id id)
|
||||
readSem = sPorts[slot].read_sem;
|
||||
writeSem = sPorts[slot].write_sem;
|
||||
|
||||
notify_port_select_events(slot, B_EVENT_INVALID);
|
||||
sPorts[slot].select_infos = NULL;
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[slot]);
|
||||
restore_interrupts(state);
|
||||
|
||||
@ -611,6 +625,9 @@ delete_port(port_id id)
|
||||
sPorts[slot].name = NULL;
|
||||
list_move_to_list(&sPorts[slot].msg_queue, &list);
|
||||
|
||||
notify_port_select_events(slot, B_EVENT_INVALID);
|
||||
sPorts[slot].select_infos = NULL;
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[slot]);
|
||||
|
||||
// update the first free slot hint in the array
|
||||
@ -639,6 +656,93 @@ delete_port(port_id id)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
select_port(int32 id, struct select_info *info, bool kernel)
|
||||
{
|
||||
cpu_status state;
|
||||
int32 slot;
|
||||
status_t error = B_OK;
|
||||
|
||||
if (id < 0)
|
||||
return B_BAD_PORT_ID;
|
||||
|
||||
slot = id % sMaxPorts;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_PORT_LOCK(sPorts[slot]);
|
||||
|
||||
if (sPorts[slot].id != id || is_port_closed(slot)) {
|
||||
// bad port ID
|
||||
error = B_BAD_SEM_ID;
|
||||
} else if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) {
|
||||
// kernel port, but call from userland
|
||||
error = B_NOT_ALLOWED;
|
||||
} else {
|
||||
info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
|
||||
|
||||
if (info->selected_events != 0) {
|
||||
uint16 events = 0;
|
||||
int32 writeCount = 0;
|
||||
|
||||
info->next = sPorts[slot].select_infos;
|
||||
sPorts[slot].select_infos = info;
|
||||
|
||||
// check for events
|
||||
if ((info->selected_events & B_EVENT_READ) != 0
|
||||
&& !list_is_empty(&sPorts[slot].msg_queue)) {
|
||||
events |= B_EVENT_READ;
|
||||
}
|
||||
|
||||
if (get_sem_count(sPorts[slot].write_sem, &writeCount) == B_OK
|
||||
&& writeCount > 0) {
|
||||
events |= B_EVENT_WRITE;
|
||||
}
|
||||
|
||||
if (events != 0)
|
||||
notify_select_events(info, events);
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[slot]);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
deselect_port(int32 id, struct select_info *info, bool kernel)
|
||||
{
|
||||
cpu_status state;
|
||||
int32 slot;
|
||||
|
||||
if (id < 0)
|
||||
return B_BAD_PORT_ID;
|
||||
|
||||
if (info->selected_events == 0)
|
||||
return B_OK;
|
||||
|
||||
slot = id % sMaxPorts;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_PORT_LOCK(sPorts[slot]);
|
||||
|
||||
if (sPorts[slot].id == id) {
|
||||
select_info** infoLocation = &sPorts[slot].select_infos;
|
||||
while (*infoLocation != NULL && *infoLocation != info)
|
||||
infoLocation = &(*infoLocation)->next;
|
||||
|
||||
if (*infoLocation == info)
|
||||
*infoLocation = info->next;
|
||||
}
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[slot]);
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
port_id
|
||||
find_port(const char *name)
|
||||
{
|
||||
@ -988,6 +1092,8 @@ read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize,
|
||||
|
||||
sPorts[slot].total_count++;
|
||||
|
||||
notify_port_select_events(slot, B_EVENT_WRITE);
|
||||
|
||||
cachedSem = sPorts[slot].write_sem;
|
||||
|
||||
RELEASE_PORT_LOCK(sPorts[slot]);
|
||||
@ -1151,6 +1257,8 @@ writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs,
|
||||
|
||||
list_add_item(&sPorts[slot].msg_queue, msg);
|
||||
|
||||
notify_port_select_events(slot, B_EVENT_READ);
|
||||
|
||||
// store sem_id in local variable
|
||||
cachedSem = sPorts[slot].read_sem;
|
||||
|
||||
|
@ -25,10 +25,12 @@
|
||||
#include <vm_low_memory.h>
|
||||
#include <vm_page.h>
|
||||
#include <boot/kernel_args.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
//#define TRACE_SEM
|
||||
#ifdef TRACE_SEM
|
||||
# define TRACE(x) dprintf x
|
||||
@ -48,6 +50,7 @@ struct sem_entry {
|
||||
struct thread_queue queue;
|
||||
char *name;
|
||||
team_id owner; // if set to -1, means owned by a port
|
||||
select_info *select_infos;
|
||||
#ifdef DEBUG_LAST_ACQUIRER
|
||||
thread_id last_acquirer;
|
||||
int32 last_acquire_count;
|
||||
@ -81,7 +84,8 @@ static spinlock sem_spinlock = 0;
|
||||
#define RELEASE_SEM_LOCK(s) release_spinlock(&(s).lock)
|
||||
|
||||
static int remove_thread_from_sem(struct thread *thread, struct sem_entry *sem,
|
||||
struct thread_queue *queue, status_t acquireStatus);
|
||||
struct thread_queue *queue, status_t acquireStatus,
|
||||
bool hasThreadLock);
|
||||
|
||||
struct sem_timeout_args {
|
||||
thread_id blocked_thread;
|
||||
@ -255,6 +259,14 @@ free_sem_slot(int slot, sem_id nextID)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
notify_sem_select_events(struct sem_entry* sem, uint16 events)
|
||||
{
|
||||
if (sem->u.used.select_infos)
|
||||
notify_select_events_list(sem->u.used.select_infos, events);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
sem_init(kernel_args *args)
|
||||
{
|
||||
@ -358,6 +370,7 @@ create_sem_etc(int32 count, const char *name, team_id owner)
|
||||
clear_thread_queue(&sem->u.used.queue);
|
||||
sem->u.used.name = tempName;
|
||||
sem->u.used.owner = owner;
|
||||
sem->u.used.select_infos = NULL;
|
||||
id = sem->id;
|
||||
RELEASE_SEM_LOCK(*sem);
|
||||
|
||||
@ -408,6 +421,9 @@ delete_sem(sem_id id)
|
||||
return B_BAD_SEM_ID;
|
||||
}
|
||||
|
||||
notify_sem_select_events(&sSems[slot], B_EVENT_INVALID);
|
||||
sSems[slot].u.used.select_infos = NULL;
|
||||
|
||||
releasedThreads = 0;
|
||||
clear_thread_queue(&releaseQueue);
|
||||
|
||||
@ -449,6 +465,80 @@ delete_sem(sem_id id)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
select_sem(int32 id, struct select_info* info, bool kernel)
|
||||
{
|
||||
cpu_status state;
|
||||
int32 slot;
|
||||
status_t error = B_OK;
|
||||
|
||||
if (id < 0)
|
||||
return B_BAD_SEM_ID;
|
||||
|
||||
slot = id % sMaxSems;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_SEM_LOCK(sSems[slot]);
|
||||
|
||||
if (sSems[slot].id != id) {
|
||||
// bad sem ID
|
||||
error = B_BAD_SEM_ID;
|
||||
} else if (!kernel
|
||||
&& sSems[slot].u.used.owner == team_get_kernel_team_id()) {
|
||||
// kernel semaphore, but call from userland
|
||||
error = B_NOT_ALLOWED;
|
||||
} else {
|
||||
info->selected_events &= B_EVENT_ACQUIRE_SEMAPHORE | B_EVENT_INVALID;
|
||||
|
||||
if (info->selected_events != 0) {
|
||||
info->next = sSems[slot].u.used.select_infos;
|
||||
sSems[slot].u.used.select_infos = info;
|
||||
|
||||
if (sSems[slot].u.used.count > 0)
|
||||
notify_select_events(info, B_EVENT_ACQUIRE_SEMAPHORE);
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE_SEM_LOCK(sSems[slot]);
|
||||
restore_interrupts(state);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
deselect_sem(int32 id, struct select_info* info, bool kernel)
|
||||
{
|
||||
cpu_status state;
|
||||
int32 slot;
|
||||
|
||||
if (id < 0)
|
||||
return B_BAD_SEM_ID;
|
||||
|
||||
if (info->selected_events == 0)
|
||||
return B_OK;
|
||||
|
||||
slot = id % sMaxSems;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_SEM_LOCK(sSems[slot]);
|
||||
|
||||
if (sSems[slot].id == id) {
|
||||
select_info** infoLocation = &sSems[slot].u.used.select_infos;
|
||||
while (*infoLocation != NULL && *infoLocation != info)
|
||||
infoLocation = &(*infoLocation)->next;
|
||||
|
||||
if (*infoLocation == info)
|
||||
*infoLocation = info->next;
|
||||
}
|
||||
|
||||
RELEASE_SEM_LOCK(sSems[slot]);
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Called from a timer handler. Wakes up a semaphore */
|
||||
|
||||
static int32
|
||||
@ -481,7 +571,8 @@ sem_timeout(timer *data)
|
||||
}
|
||||
|
||||
clear_thread_queue(&wakeupQueue);
|
||||
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_TIMED_OUT);
|
||||
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_TIMED_OUT,
|
||||
false);
|
||||
|
||||
RELEASE_SEM_LOCK(sSems[slot]);
|
||||
|
||||
@ -635,7 +726,8 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count,
|
||||
clear_thread_queue(&wakeupQueue);
|
||||
GRAB_SEM_LOCK(sSems[slot]);
|
||||
if (sSems[slot].id == id) {
|
||||
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_INTERRUPTED);
|
||||
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue,
|
||||
B_INTERRUPTED, true);
|
||||
}
|
||||
RELEASE_SEM_LOCK(sSems[slot]);
|
||||
while ((thread = thread_dequeue(&wakeupQueue)) != NULL) {
|
||||
@ -770,6 +862,10 @@ release_sem_etc(sem_id id, int32 count, uint32 flags)
|
||||
sSems[slot].u.used.count += delta;
|
||||
count -= delta;
|
||||
}
|
||||
|
||||
if (sSems[slot].u.used.count > 0)
|
||||
notify_sem_select_events(&sSems[slot], B_EVENT_ACQUIRE_SEMAPHORE);
|
||||
|
||||
RELEASE_SEM_LOCK(sSems[slot]);
|
||||
|
||||
// pull off any items in the release queue and put them in the run queue
|
||||
@ -1022,7 +1118,8 @@ sem_interrupt_thread(struct thread *thread)
|
||||
}
|
||||
|
||||
clear_thread_queue(&wakeupQueue);
|
||||
if (remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_INTERRUPTED) != B_OK) {
|
||||
if (remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue,
|
||||
B_INTERRUPTED, true) != B_OK) {
|
||||
panic("sem_interrupt_thread: thread 0x%lx not found in sem 0x%lx's wait queue\n",
|
||||
thread->id, thread->sem.blocking);
|
||||
}
|
||||
@ -1045,7 +1142,7 @@ sem_interrupt_thread(struct thread *thread)
|
||||
|
||||
static int
|
||||
remove_thread_from_sem(struct thread *thread, struct sem_entry *sem,
|
||||
struct thread_queue *queue, status_t acquireStatus)
|
||||
struct thread_queue *queue, status_t acquireStatus, bool hasThreadLock)
|
||||
{
|
||||
// remove the thread from the queue and place it in the supplied queue
|
||||
if (thread_dequeue_id(&sem->u.used.queue, thread->id) != thread)
|
||||
@ -1070,6 +1167,16 @@ remove_thread_from_sem(struct thread *thread, struct sem_entry *sem,
|
||||
sem->u.used.count -= delta;
|
||||
}
|
||||
|
||||
if (sem->u.used.count > 0 && sem->u.used.select_infos != NULL) {
|
||||
if (hasThreadLock)
|
||||
RELEASE_THREAD_LOCK();
|
||||
|
||||
notify_sem_select_events(sem, B_EVENT_ACQUIRE_SEMAPHORE);
|
||||
|
||||
if (hasThreadLock)
|
||||
GRAB_THREAD_LOCK();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <arch/system_info.h>
|
||||
#include <messaging.h>
|
||||
#include <frame_buffer_console.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
@ -9,8 +9,19 @@
|
||||
/*! Threading routines */
|
||||
|
||||
|
||||
#include <thread.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/khash.h>
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
#include <condition_variable.h>
|
||||
#include <cpu.h>
|
||||
#include <int.h>
|
||||
@ -20,20 +31,13 @@
|
||||
#include <smp.h>
|
||||
#include <syscalls.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <tls.h>
|
||||
#include <user_runtime.h>
|
||||
#include <vfs.h>
|
||||
#include <vm.h>
|
||||
#include <vm_address_space.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
#include <util/khash.h>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#define TRACE_THREAD
|
||||
#ifdef TRACE_THREAD
|
||||
@ -249,6 +253,7 @@ create_thread_struct(struct thread *inthread, const char *name,
|
||||
thread->exit.reason = 0;
|
||||
thread->exit.signal = 0;
|
||||
list_init(&thread->exit.waiters);
|
||||
thread->select_infos = NULL;
|
||||
|
||||
sprintf(temp, "thread_0x%lx_retcode_sem", thread->id);
|
||||
thread->exit.sem = create_sem(0, temp);
|
||||
@ -1223,11 +1228,25 @@ thread_exit(void)
|
||||
debugInfo = thread->debug_info;
|
||||
clear_thread_debug_info(&thread->debug_info, true);
|
||||
|
||||
// Remove the select infos. We notify them a little later.
|
||||
select_info* selectInfos = thread->select_infos;
|
||||
thread->select_infos = NULL;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
destroy_thread_debug_info(&debugInfo);
|
||||
|
||||
// notify select infos
|
||||
select_info* info = selectInfos;
|
||||
while (info != NULL) {
|
||||
select_sync* sync = info->sync;
|
||||
|
||||
notify_select_events(info, B_EVENT_INVALID);
|
||||
info = info->next;
|
||||
put_select_sync(sync);
|
||||
}
|
||||
|
||||
// shutdown the thread messaging
|
||||
|
||||
status = acquire_sem_etc(thread->msg.write_sem, 1, B_RELATIVE_TIMEOUT, 0);
|
||||
@ -1613,6 +1632,61 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
select_thread(int32 id, struct select_info* info, bool kernel)
|
||||
{
|
||||
InterruptsSpinLocker locker(thread_spinlock);
|
||||
|
||||
// get thread
|
||||
struct thread* thread = thread_get_thread_struct_locked(id);
|
||||
if (thread == NULL)
|
||||
return B_BAD_THREAD_ID;
|
||||
|
||||
// We support only B_EVENT_INVALID at the moment.
|
||||
info->selected_events &= B_EVENT_INVALID;
|
||||
|
||||
// add info to list
|
||||
if (info->selected_events != 0) {
|
||||
info->next = thread->select_infos;
|
||||
thread->select_infos = info;
|
||||
|
||||
// we need a sync reference
|
||||
atomic_add(&info->sync->ref_count, 1);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
deselect_thread(int32 id, struct select_info* info, bool kernel)
|
||||
{
|
||||
InterruptsSpinLocker locker(thread_spinlock);
|
||||
|
||||
// get thread
|
||||
struct thread* thread = thread_get_thread_struct_locked(id);
|
||||
if (thread == NULL)
|
||||
return B_BAD_THREAD_ID;
|
||||
|
||||
// remove info from list
|
||||
select_info** infoLocation = &thread->select_infos;
|
||||
while (*infoLocation != NULL && *infoLocation != info)
|
||||
infoLocation = &(*infoLocation)->next;
|
||||
|
||||
if (*infoLocation != info)
|
||||
return B_OK;
|
||||
|
||||
*infoLocation = info->next;
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
// surrender sync reference
|
||||
put_select_sync(info->sync);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
thread_max_threads(void)
|
||||
{
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "vfs_select.h"
|
||||
#include <fs/select_sync_pool.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
@ -15,16 +15,23 @@
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <Select.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <fd.h>
|
||||
#include <fs/select_sync_pool.h>
|
||||
#include <fs/fd.h>
|
||||
#include <port.h>
|
||||
#include <sem.h>
|
||||
#include <syscalls.h>
|
||||
#include <thread.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <vfs.h>
|
||||
|
||||
//#define TRACE_VFS_SELECT
|
||||
#ifdef TRACE_VFS_SELECT
|
||||
|
||||
//#define TRACE_WAIT_FOR_OBJECTS
|
||||
#ifdef TRACE_WAIT_FOR_OBJECTS
|
||||
# define PRINT(x) dprintf x
|
||||
# define FUNCTION(x) dprintf x
|
||||
#else
|
||||
@ -36,6 +43,54 @@
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
struct select_sync_pool_entry
|
||||
: DoublyLinkedListLinkImpl<select_sync_pool_entry> {
|
||||
selectsync *sync;
|
||||
uint16 events;
|
||||
};
|
||||
|
||||
typedef DoublyLinkedList<select_sync_pool_entry> SelectSyncPoolEntryList;
|
||||
|
||||
struct select_sync_pool {
|
||||
SelectSyncPoolEntryList entries;
|
||||
};
|
||||
|
||||
|
||||
struct select_ops {
|
||||
status_t (*select)(int32 object, struct select_info* info, bool kernel);
|
||||
status_t (*deselect)(int32 object, struct select_info* info, bool kernel);
|
||||
};
|
||||
|
||||
|
||||
static const select_ops kSelectOps[] = {
|
||||
// B_OBJECT_TYPE_FD
|
||||
{
|
||||
select_fd,
|
||||
deselect_fd
|
||||
},
|
||||
|
||||
// B_OBJECT_TYPE_SEMAPHORE
|
||||
{
|
||||
select_sem,
|
||||
deselect_sem
|
||||
},
|
||||
|
||||
// B_OBJECT_TYPE_PORT
|
||||
{
|
||||
select_port,
|
||||
deselect_port
|
||||
},
|
||||
|
||||
// B_OBJECT_TYPE_THREAD
|
||||
{
|
||||
select_thread,
|
||||
deselect_thread
|
||||
}
|
||||
};
|
||||
|
||||
static const uint32 kSelectOpsCount = sizeof(kSelectOps) / sizeof(select_ops);
|
||||
|
||||
|
||||
/*!
|
||||
Clears all bits in the fd_set - since we are using variable sized
|
||||
arrays in the kernel, we can't use the FD_ZERO() macro provided by
|
||||
@ -150,7 +205,7 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
||||
sync->set[fd].selected_events |= SELECT_FLAG(B_SELECT_ERROR);
|
||||
|
||||
if (sync->set[fd].selected_events != 0) {
|
||||
select_fd(fd, sync, fd, kernel);
|
||||
select_fd(fd, sync->set + fd, kernel);
|
||||
// array position is the same as the fd for select()
|
||||
}
|
||||
}
|
||||
@ -177,7 +232,7 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
||||
locker.Lock();
|
||||
|
||||
for (fd = 0; fd < numFDs; fd++)
|
||||
deselect_fd(fd, sync, fd, kernel);
|
||||
deselect_fd(fd, sync->set + fd, kernel);
|
||||
|
||||
PRINT(("common_select(): events deselected\n"));
|
||||
|
||||
@ -253,7 +308,7 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
|
||||
| POLLERR | POLLHUP;
|
||||
sync->set[i].events = 0;
|
||||
|
||||
if (select_fd(fd, sync, i, kernel) == B_OK) {
|
||||
if (select_fd(fd, sync->set + i, kernel) == B_OK) {
|
||||
fds[i].revents = 0;
|
||||
if (sync->set[i].selected_events != 0)
|
||||
count++;
|
||||
@ -276,7 +331,7 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
|
||||
locker.Lock();
|
||||
|
||||
for (i = 0; i < numFDs; i++)
|
||||
deselect_fd(fds[i].fd, sync, i, kernel);
|
||||
deselect_fd(fds[i].fd, sync->set + i, kernel);
|
||||
|
||||
// collect the events that are happened in the meantime
|
||||
|
||||
@ -309,7 +364,94 @@ err:
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - VFS private
|
||||
static ssize_t
|
||||
common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
|
||||
bigtime_t timeout, bool kernel)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
// allocate sync object
|
||||
select_sync* sync;
|
||||
status = create_select_sync(numInfos, sync);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// start selecting objects
|
||||
|
||||
BenaphoreLocker locker(sync->lock);
|
||||
|
||||
ssize_t count = 0;
|
||||
bool invalid = false;
|
||||
for (int i = 0; i < numInfos; i++) {
|
||||
uint16 type = infos[i].type;
|
||||
int32 object = infos[i].object;
|
||||
|
||||
// initialize events masks
|
||||
sync->set[i].selected_events = infos[i].events
|
||||
| B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
|
||||
sync->set[i].events = 0;
|
||||
|
||||
if (type < kSelectOpsCount
|
||||
&& kSelectOps[type].select(object, sync->set + i, kernel) == B_OK) {
|
||||
infos[i].events = 0;
|
||||
if (sync->set[i].selected_events != 0)
|
||||
count++;
|
||||
} else {
|
||||
sync->set[i].selected_events = B_EVENT_INVALID;
|
||||
infos[i].events = B_EVENT_INVALID;
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
if (count < 1) {
|
||||
put_select_sync(sync);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
if (!invalid) {
|
||||
status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | flags,
|
||||
timeout);
|
||||
}
|
||||
|
||||
// deselect objects
|
||||
|
||||
locker.Lock();
|
||||
|
||||
for (int i = 0; i < numInfos; i++) {
|
||||
uint16 type = infos[i].type;
|
||||
|
||||
if (type < kSelectOpsCount && (infos[i].events & B_EVENT_INVALID) == 0)
|
||||
kSelectOps[type].deselect(infos[i].object, sync->set + i, kernel);
|
||||
}
|
||||
|
||||
// collect the events that are happened in the meantime
|
||||
|
||||
switch (status) {
|
||||
case B_OK:
|
||||
count = 0;
|
||||
for (int i = 0; i < numInfos; i++) {
|
||||
infos[i].events = sync->set[i].events
|
||||
& sync->set[i].selected_events;
|
||||
if (infos[i].events != 0)
|
||||
count++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK
|
||||
count = status;
|
||||
break;
|
||||
}
|
||||
|
||||
locker.Unlock();
|
||||
put_select_sync(sync);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - kernel private
|
||||
|
||||
|
||||
status_t
|
||||
@ -328,17 +470,28 @@ notify_select_events(select_info* info, uint16 events)
|
||||
// only wake up the waiting select()/poll() call if the events
|
||||
// match one of the selected ones
|
||||
if (info->selected_events & events)
|
||||
return release_sem(info->sync->sem);
|
||||
return release_sem_etc(info->sync->sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
notify_select_events_list(select_info* list, uint16 events)
|
||||
{
|
||||
struct select_info* info = list;
|
||||
while (info != NULL) {
|
||||
notify_select_events(info, events);
|
||||
info = info->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - public kernel API
|
||||
|
||||
|
||||
status_t
|
||||
notify_select_event(struct selectsync *sync, uint32 /*ref*/, uint8 event)
|
||||
notify_select_event(struct selectsync *sync, uint8 event)
|
||||
{
|
||||
return notify_select_events((select_info*)sync, SELECT_FLAG(event));
|
||||
}
|
||||
@ -348,13 +501,12 @@ notify_select_event(struct selectsync *sync, uint32 /*ref*/, uint8 event)
|
||||
|
||||
|
||||
static select_sync_pool_entry *
|
||||
find_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync,
|
||||
uint32 ref)
|
||||
find_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync)
|
||||
{
|
||||
for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator();
|
||||
it.HasNext();) {
|
||||
select_sync_pool_entry *entry = it.Next();
|
||||
if (entry->sync == sync && entry->ref == ref)
|
||||
if (entry->sync == sync)
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -364,18 +516,16 @@ find_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync,
|
||||
|
||||
static status_t
|
||||
add_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync,
|
||||
uint32 ref, uint8 event)
|
||||
uint8 event)
|
||||
{
|
||||
// check, whether the entry does already exist
|
||||
select_sync_pool_entry *entry = find_select_sync_pool_entry(pool, sync,
|
||||
ref);
|
||||
select_sync_pool_entry *entry = find_select_sync_pool_entry(pool, sync);
|
||||
if (!entry) {
|
||||
entry = new (std::nothrow) select_sync_pool_entry;
|
||||
if (!entry)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
entry->sync = sync;
|
||||
entry->ref = ref;
|
||||
entry->events = 0;
|
||||
|
||||
pool->entries.Add(entry);
|
||||
@ -389,7 +539,7 @@ add_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync,
|
||||
|
||||
status_t
|
||||
add_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync,
|
||||
uint32 ref, uint8 event)
|
||||
uint8 event)
|
||||
{
|
||||
// create the pool, if necessary
|
||||
select_sync_pool *pool = *_pool;
|
||||
@ -402,7 +552,7 @@ add_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync,
|
||||
}
|
||||
|
||||
// add the entry
|
||||
status_t error = add_select_sync_pool_entry(pool, sync, ref, event);
|
||||
status_t error = add_select_sync_pool_entry(pool, sync, event);
|
||||
|
||||
// cleanup
|
||||
if (pool->entries.IsEmpty()) {
|
||||
@ -479,7 +629,7 @@ notify_select_event_pool(select_sync_pool *pool, uint8 event)
|
||||
it.HasNext();) {
|
||||
select_sync_pool_entry *entry = it.Next();
|
||||
if (entry->events & SELECT_FLAG(event))
|
||||
notify_select_event(entry->sync, entry->ref, event);
|
||||
notify_select_event(entry->sync, event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,6 +653,14 @@ _kern_poll(struct pollfd *fds, int numFDs, bigtime_t timeout)
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
_kern_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
return common_wait_for_objects(infos, numInfos, flags, timeout, true);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - User syscalls
|
||||
|
||||
|
||||
@ -623,3 +781,36 @@ err:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
_user_wait_for_objects(object_wait_info* userInfos, int numInfos, uint32 flags,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
if (numInfos < 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (userInfos == NULL || !IS_USER_ADDRESS(userInfos))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
int bytes = sizeof(object_wait_info) * numInfos;
|
||||
object_wait_info* infos = (object_wait_info*)malloc(bytes);
|
||||
if (infos == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// copy parameters to kernel space, call the function, and copy the results
|
||||
// back
|
||||
ssize_t result;
|
||||
if (user_memcpy(infos, userInfos, bytes) == B_OK) {
|
||||
result = common_wait_for_objects(infos, numInfos, flags, timeout,
|
||||
false);
|
||||
|
||||
if (user_memcpy(userInfos, infos, bytes) != B_OK)
|
||||
result = B_BAD_ADDRESS;
|
||||
} else
|
||||
result = B_BAD_ADDRESS;
|
||||
|
||||
free(infos);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ MergeObject os_main.o :
|
||||
thread.c
|
||||
time.c
|
||||
syscalls.S
|
||||
wait_for_objects.cpp
|
||||
;
|
||||
|
||||
# We need to specify the dependency on the generated syscalls file explicitly.
|
||||
|
23
src/system/libroot/os/wait_for_objects.cpp
Normal file
23
src/system/libroot/os/wait_for_objects.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <OS.h>
|
||||
#include <syscalls.h>
|
||||
|
||||
|
||||
|
||||
ssize_t
|
||||
wait_for_objects(object_wait_info* infos, int numInfos)
|
||||
{
|
||||
return _kern_wait_for_objects(infos, numInfos, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
wait_for_objects_etc(object_wait_info* infos, int numInfos, uint32 flags,
|
||||
bigtime_t timeout)
|
||||
{
|
||||
return _kern_wait_for_objects(infos, numInfos, flags, timeout);
|
||||
}
|
Loading…
Reference in New Issue
Block a user