* 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:
Ingo Weinhold 2007-10-02 19:47:31 +00:00
parent a82d70c719
commit 636bfc08ae
37 changed files with 717 additions and 160 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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

View 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

View File

@ -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;
};

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -40,6 +40,7 @@ KernelMergeObject kernel_core.o :
team.cpp
thread.cpp
timer.c
wait_for_objects.cpp
: $(TARGET_KERNEL_PIC_CCFLAGS)
;

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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>

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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.

View 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);
}