2005-03-29 01:45:56 +04:00
|
|
|
/*
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
* Copyright 2007-2008, Ingo Weinhold, bonefish@cs.tu-berlin.de.
|
|
|
|
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
2005-03-29 01:45:56 +04:00
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
#include <fs/select_sync_pool.h>
|
|
|
|
#include <wait_for_objects.h>
|
2007-03-29 20:09:53 +04:00
|
|
|
|
2006-03-27 14:27:05 +04:00
|
|
|
#include <new>
|
2007-10-01 05:37:28 +04:00
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
#include <poll.h>
|
2007-10-01 05:37:28 +04:00
|
|
|
#include <signal.h>
|
2005-03-18 00:27:01 +03:00
|
|
|
#include <stdlib.h>
|
2002-11-03 06:19:34 +03:00
|
|
|
#include <string.h>
|
2007-03-29 20:09:53 +04:00
|
|
|
#include <sys/select.h>
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
#include <OS.h>
|
|
|
|
#include <Select.h>
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
#include <AutoDeleter.h>
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
#include <fs/fd.h>
|
|
|
|
#include <port.h>
|
|
|
|
#include <sem.h>
|
2007-10-01 05:37:28 +04:00
|
|
|
#include <syscalls.h>
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
#include <syscall_restart.h>
|
2007-10-02 23:47:31 +04:00
|
|
|
#include <thread.h>
|
2008-04-30 20:12:20 +04:00
|
|
|
#include <tracing.h>
|
2007-10-01 05:37:28 +04:00
|
|
|
#include <util/AutoLock.h>
|
2007-10-02 23:47:31 +04:00
|
|
|
#include <util/DoublyLinkedList.h>
|
2007-10-01 05:37:28 +04:00
|
|
|
#include <vfs.h>
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
|
|
|
|
//#define TRACE_WAIT_FOR_OBJECTS
|
|
|
|
#ifdef TRACE_WAIT_FOR_OBJECTS
|
2005-03-18 00:27:01 +03:00
|
|
|
# define PRINT(x) dprintf x
|
|
|
|
# define FUNCTION(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define PRINT(x) ;
|
|
|
|
# define FUNCTION(x) ;
|
|
|
|
#endif
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
using std::nothrow;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
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);
|
|
|
|
|
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
|
|
|
|
#if WAIT_FOR_OBJECTS_TRACING
|
|
|
|
|
|
|
|
|
|
|
|
namespace WaitForObjectsTracing {
|
|
|
|
|
|
|
|
|
|
|
|
class SelectTraceEntry : public AbstractTraceEntry {
|
|
|
|
protected:
|
|
|
|
SelectTraceEntry(int count, fd_set* readSet, fd_set* writeSet,
|
|
|
|
fd_set* errorSet)
|
|
|
|
:
|
|
|
|
fReadSet(NULL),
|
|
|
|
fWriteSet(NULL),
|
|
|
|
fErrorSet(NULL),
|
|
|
|
fCount(count)
|
|
|
|
{
|
|
|
|
int sets = (readSet != NULL ? 1 : 0) + (writeSet != NULL ? 1 : 0)
|
|
|
|
+ (errorSet != NULL ? 1 : 0);
|
|
|
|
if (sets > 0 && count > 0) {
|
|
|
|
uint32 bytes = _howmany(count, NFDBITS) * sizeof(fd_mask);
|
|
|
|
uint8* allocated = (uint8*)alloc_tracing_buffer(bytes * sets);
|
|
|
|
if (allocated != NULL) {
|
|
|
|
if (readSet != NULL) {
|
|
|
|
fReadSet = (fd_set*)allocated;
|
|
|
|
memcpy(fReadSet, readSet, bytes);
|
|
|
|
allocated += bytes;
|
|
|
|
}
|
|
|
|
if (writeSet != NULL) {
|
|
|
|
fWriteSet = (fd_set*)allocated;
|
|
|
|
memcpy(fWriteSet, writeSet, bytes);
|
|
|
|
allocated += bytes;
|
|
|
|
}
|
|
|
|
if (errorSet != NULL) {
|
|
|
|
fErrorSet = (fd_set*)allocated;
|
|
|
|
memcpy(fErrorSet, errorSet, bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddDump(TraceOutput& out, const char* name)
|
|
|
|
{
|
|
|
|
out.Print(name);
|
|
|
|
|
|
|
|
_PrintSet(out, "read", fReadSet);
|
|
|
|
_PrintSet(out, ", write", fWriteSet);
|
|
|
|
_PrintSet(out, ", error", fErrorSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void _PrintSet(TraceOutput& out, const char* name, fd_set* set)
|
|
|
|
{
|
|
|
|
|
|
|
|
out.Print("%s: <", name);
|
|
|
|
|
|
|
|
if (set != NULL) {
|
|
|
|
bool first = true;
|
|
|
|
for (int i = 0; i < fCount; i++) {
|
|
|
|
if (!FD_ISSET(i, set))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
out.Print("%d", i);
|
|
|
|
first = false;
|
|
|
|
} else
|
|
|
|
out.Print(", %d", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Print(">");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
fd_set* fReadSet;
|
|
|
|
fd_set* fWriteSet;
|
|
|
|
fd_set* fErrorSet;
|
|
|
|
int fCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SelectBegin : public SelectTraceEntry {
|
|
|
|
public:
|
|
|
|
SelectBegin(int count, fd_set* readSet, fd_set* writeSet,
|
|
|
|
fd_set* errorSet, bigtime_t timeout)
|
|
|
|
:
|
|
|
|
SelectTraceEntry(count, readSet, writeSet, errorSet),
|
|
|
|
fTimeout(timeout)
|
|
|
|
{
|
|
|
|
Initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void AddDump(TraceOutput& out)
|
|
|
|
{
|
|
|
|
SelectTraceEntry::AddDump(out, "select begin: ");
|
|
|
|
out.Print(", timeout: %lld", fTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bigtime_t fTimeout;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class SelectDone : public SelectTraceEntry {
|
|
|
|
public:
|
|
|
|
SelectDone(int count, fd_set* readSet, fd_set* writeSet,
|
|
|
|
fd_set* errorSet, status_t status)
|
|
|
|
:
|
|
|
|
SelectTraceEntry(status == B_OK ? count : 0, readSet, writeSet,
|
|
|
|
errorSet),
|
|
|
|
fStatus(status)
|
|
|
|
{
|
|
|
|
Initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void AddDump(TraceOutput& out)
|
|
|
|
{
|
|
|
|
if (fStatus == B_OK)
|
|
|
|
SelectTraceEntry::AddDump(out, "select done: ");
|
|
|
|
else
|
|
|
|
out.Print("select done: error: 0x%lx", fStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
status_t fStatus;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-05-10 20:23:48 +04:00
|
|
|
class PollTraceEntry : public AbstractTraceEntry {
|
|
|
|
protected:
|
|
|
|
PollTraceEntry(pollfd* fds, int count, bool resultEvents)
|
|
|
|
:
|
|
|
|
fEntries(NULL),
|
|
|
|
fCount(0)
|
|
|
|
{
|
|
|
|
if (fds != NULL && count > 0) {
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
if (resultEvents ? fds[i].revents : fds[i].events)
|
|
|
|
fCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fCount == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fEntries = (FDEntry*)alloc_tracing_buffer(fCount * sizeof(FDEntry));
|
|
|
|
if (fEntries != NULL) {
|
|
|
|
for (int i = 0; i < fCount; fds++) {
|
|
|
|
uint16 events = resultEvents ? fds->revents : fds->events;
|
|
|
|
if (events != 0) {
|
|
|
|
fEntries[i].fd = fds->fd;
|
|
|
|
fEntries[i].events = events;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddDump(TraceOutput& out)
|
|
|
|
{
|
|
|
|
if (fEntries == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
const char* name;
|
|
|
|
uint16 event;
|
|
|
|
} kEventNames[] = {
|
|
|
|
{ "r", POLLIN },
|
|
|
|
{ "w", POLLOUT },
|
|
|
|
{ "rb", POLLRDBAND },
|
|
|
|
{ "wb", POLLWRBAND },
|
|
|
|
{ "rp", POLLPRI },
|
|
|
|
{ "err", POLLERR },
|
|
|
|
{ "hup", POLLHUP },
|
|
|
|
{ "inv", POLLNVAL },
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
bool firstFD = true;
|
|
|
|
for (int i = 0; i < fCount; i++) {
|
|
|
|
if (firstFD) {
|
|
|
|
out.Print("<%u: ", fEntries[i].fd);
|
|
|
|
firstFD = false;
|
|
|
|
} else
|
|
|
|
out.Print(", <%u: ", fEntries[i].fd);
|
|
|
|
|
|
|
|
bool firstEvent = true;
|
|
|
|
for (int k = 0; kEventNames[k].name != NULL; k++) {
|
|
|
|
if ((fEntries[i].events & kEventNames[k].event) != 0) {
|
|
|
|
if (firstEvent) {
|
|
|
|
out.Print("%s", kEventNames[k].name);
|
|
|
|
firstEvent = false;
|
|
|
|
} else
|
|
|
|
out.Print(", %s", kEventNames[k].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Print(">");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
struct FDEntry {
|
|
|
|
uint16 fd;
|
|
|
|
uint16 events;
|
|
|
|
};
|
|
|
|
|
|
|
|
FDEntry* fEntries;
|
|
|
|
int fCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class PollBegin : public PollTraceEntry {
|
|
|
|
public:
|
|
|
|
PollBegin(pollfd* fds, int count, bigtime_t timeout)
|
|
|
|
:
|
|
|
|
PollTraceEntry(fds, count, false),
|
|
|
|
fTimeout(timeout)
|
|
|
|
{
|
|
|
|
Initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void AddDump(TraceOutput& out)
|
|
|
|
{
|
|
|
|
out.Print("poll begin: ");
|
|
|
|
PollTraceEntry::AddDump(out);
|
|
|
|
out.Print(", timeout: %lld", fTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bigtime_t fTimeout;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class PollDone : public PollTraceEntry {
|
|
|
|
public:
|
|
|
|
PollDone(pollfd* fds, int count, int result)
|
|
|
|
:
|
|
|
|
PollTraceEntry(fds, result >= 0 ? count : 0, true),
|
|
|
|
fResult(result)
|
|
|
|
{
|
|
|
|
Initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void AddDump(TraceOutput& out)
|
|
|
|
{
|
|
|
|
if (fResult >= 0) {
|
|
|
|
out.Print("poll done: count: %d: ", fResult);
|
|
|
|
PollTraceEntry::AddDump(out);
|
|
|
|
} else
|
|
|
|
out.Print("poll done: error: 0x%x", fResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
int fResult;
|
|
|
|
};
|
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
} // namespace WaitForObjectsTracing
|
|
|
|
|
|
|
|
# define T(x) new(std::nothrow) WaitForObjectsTracing::x
|
|
|
|
|
|
|
|
#else
|
|
|
|
# define T(x)
|
|
|
|
#endif // WAIT_FOR_OBJECTS_TRACING
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
/*!
|
|
|
|
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
|
|
|
|
sys/select.h for this task.
|
|
|
|
All other FD_xxx() macros are safe to use, though.
|
|
|
|
*/
|
2002-11-03 06:19:34 +03:00
|
|
|
static inline void
|
2007-03-29 20:09:53 +04:00
|
|
|
fd_zero(fd_set *set, int numFDs)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
|
|
|
if (set != NULL)
|
2007-03-29 20:09:53 +04:00
|
|
|
memset(set, 0, _howmany(numFDs, NFDBITS) * sizeof(fd_mask));
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
static status_t
|
|
|
|
create_select_sync(int numFDs, select_sync*& _sync)
|
|
|
|
{
|
|
|
|
// create sync structure
|
|
|
|
select_sync* sync = new(nothrow) select_sync;
|
|
|
|
if (sync == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
ObjectDeleter<select_sync> syncDeleter(sync);
|
|
|
|
|
|
|
|
// create info set
|
|
|
|
sync->set = new(nothrow) select_info[numFDs];
|
|
|
|
if (sync->set == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
ArrayDeleter<select_info> setDeleter(sync->set);
|
|
|
|
|
|
|
|
// create select event semaphore
|
|
|
|
sync->sem = create_sem(0, "select");
|
|
|
|
if (sync->sem < 0)
|
|
|
|
return sync->sem;
|
|
|
|
|
|
|
|
sync->count = numFDs;
|
|
|
|
sync->ref_count = 1;
|
|
|
|
|
|
|
|
for (int i = 0; i < numFDs; i++) {
|
|
|
|
sync->set[i].next = NULL;
|
|
|
|
sync->set[i].sync = sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
setDeleter.Detach();
|
|
|
|
syncDeleter.Detach();
|
|
|
|
_sync = sync;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
put_select_sync(select_sync* sync)
|
|
|
|
{
|
|
|
|
FUNCTION(("put_select_sync(%p): -> %ld\n", sync, sync->ref_count - 1));
|
|
|
|
|
|
|
|
if (atomic_add(&sync->ref_count, -1) == 1) {
|
|
|
|
delete_sem(sync->sem);
|
|
|
|
delete[] sync->set;
|
|
|
|
delete sync;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
static int
|
2007-03-29 20:09:53 +04:00
|
|
|
common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
2002-11-03 06:19:34 +03:00
|
|
|
bigtime_t timeout, const sigset_t *sigMask, bool kernel)
|
|
|
|
{
|
|
|
|
status_t status = B_OK;
|
|
|
|
int fd;
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
FUNCTION(("[%ld] common_select(%d, %p, %p, %p, %lld, %p, %d)\n",
|
|
|
|
find_thread(NULL), numFDs, readSet, writeSet, errorSet, timeout,
|
|
|
|
sigMask, kernel));
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
// check if fds are valid before doing anything
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
for (fd = 0; fd < numFDs; fd++) {
|
2002-11-03 06:19:34 +03:00
|
|
|
if (((readSet && FD_ISSET(fd, readSet))
|
|
|
|
|| (writeSet && FD_ISSET(fd, writeSet))
|
|
|
|
|| (errorSet && FD_ISSET(fd, errorSet)))
|
|
|
|
&& !fd_is_valid(fd, kernel))
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
}
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// allocate sync object
|
|
|
|
select_sync* sync;
|
|
|
|
status = create_select_sync(numFDs, sync);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
T(SelectBegin(numFDs, readSet, writeSet, errorSet, timeout));
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
// start selecting file descriptors
|
2007-10-01 05:37:28 +04:00
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
for (fd = 0; fd < numFDs; fd++) {
|
2007-10-01 05:37:28 +04:00
|
|
|
sync->set[fd].selected_events = 0;
|
|
|
|
sync->set[fd].events = 0;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
if (readSet && FD_ISSET(fd, readSet))
|
2007-10-01 05:37:28 +04:00
|
|
|
sync->set[fd].selected_events = SELECT_FLAG(B_SELECT_READ);
|
2002-11-03 06:19:34 +03:00
|
|
|
if (writeSet && FD_ISSET(fd, writeSet))
|
2007-10-01 05:37:28 +04:00
|
|
|
sync->set[fd].selected_events |= SELECT_FLAG(B_SELECT_WRITE);
|
2002-11-03 06:19:34 +03:00
|
|
|
if (errorSet && FD_ISSET(fd, errorSet))
|
2007-10-01 05:37:28 +04:00
|
|
|
sync->set[fd].selected_events |= SELECT_FLAG(B_SELECT_ERROR);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-01 22:48:52 +04:00
|
|
|
if (sync->set[fd].selected_events != 0) {
|
2007-10-02 23:47:31 +04:00
|
|
|
select_fd(fd, sync->set + fd, kernel);
|
2007-10-01 22:48:52 +04:00
|
|
|
// array position is the same as the fd for select()
|
|
|
|
}
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// set new signal mask
|
|
|
|
sigset_t oldSigMask;
|
|
|
|
if (sigMask != NULL)
|
|
|
|
sigprocmask(SIG_SETMASK, sigMask, &oldSigMask);
|
|
|
|
|
|
|
|
// wait for something to happen
|
|
|
|
status = acquire_sem_etc(sync->sem, 1,
|
2008-02-23 18:59:30 +03:00
|
|
|
B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// restore the old signal mask
|
|
|
|
if (sigMask != NULL)
|
|
|
|
sigprocmask(SIG_SETMASK, &oldSigMask, NULL);
|
|
|
|
|
2005-03-21 01:15:33 +03:00
|
|
|
PRINT(("common_select(): acquire_sem_etc() returned: %lx\n", status));
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
// deselect file descriptors
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
for (fd = 0; fd < numFDs; fd++)
|
2007-10-02 23:47:31 +04:00
|
|
|
deselect_fd(fd, sync->set + fd, kernel);
|
2005-03-21 01:15:33 +03:00
|
|
|
|
|
|
|
PRINT(("common_select(): events deselected\n"));
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// collect the events that happened in the meantime
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
int count = 0;
|
2007-03-23 23:40:03 +03:00
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
if (status == B_INTERRUPTED) {
|
|
|
|
// We must not clear the sets in this case, as applications may
|
|
|
|
// rely on the contents of them.
|
2007-10-01 05:37:28 +04:00
|
|
|
put_select_sync(sync);
|
2008-04-30 20:12:20 +04:00
|
|
|
T(SelectDone(numFDs, readSet, writeSet, errorSet, status));
|
2007-10-01 05:37:28 +04:00
|
|
|
return B_INTERRUPTED;
|
2007-03-29 20:09:53 +04:00
|
|
|
}
|
2007-03-23 23:40:03 +03:00
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// Clear sets to store the received events
|
|
|
|
// (we can't use the macros, because we have variable sized arrays;
|
|
|
|
// the other FD_xxx() macros are safe, though).
|
|
|
|
fd_zero(readSet, numFDs);
|
|
|
|
fd_zero(writeSet, numFDs);
|
|
|
|
fd_zero(errorSet, numFDs);
|
|
|
|
|
|
|
|
if (status == B_OK) {
|
|
|
|
for (count = 0, fd = 0;fd < numFDs; fd++) {
|
2007-10-01 05:37:28 +04:00
|
|
|
if (readSet && sync->set[fd].events & SELECT_FLAG(B_SELECT_READ)) {
|
2007-03-29 20:09:53 +04:00
|
|
|
FD_SET(fd, readSet);
|
|
|
|
count++;
|
|
|
|
}
|
2007-10-01 05:37:28 +04:00
|
|
|
if (writeSet
|
|
|
|
&& sync->set[fd].events & SELECT_FLAG(B_SELECT_WRITE)) {
|
2007-03-29 20:09:53 +04:00
|
|
|
FD_SET(fd, writeSet);
|
|
|
|
count++;
|
|
|
|
}
|
2007-10-01 05:37:28 +04:00
|
|
|
if (errorSet
|
|
|
|
&& sync->set[fd].events & SELECT_FLAG(B_SELECT_ERROR)) {
|
2007-03-29 20:09:53 +04:00
|
|
|
FD_SET(fd, errorSet);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// B_TIMED_OUT and B_WOULD_BLOCK are supposed to return 0
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
put_select_sync(sync);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
T(SelectDone(numFDs, readSet, writeSet, errorSet, status));
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2007-03-29 20:09:53 +04:00
|
|
|
common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
|
|
|
status_t status = B_OK;
|
|
|
|
int count = 0;
|
2003-09-06 21:31:33 +04:00
|
|
|
uint32 i;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// allocate sync object
|
|
|
|
select_sync* sync;
|
|
|
|
status = create_select_sync(numFDs, sync);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2008-05-10 20:23:48 +04:00
|
|
|
T(PollBegin(fds, numFDs, timeout));
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
// start polling file descriptors (by selecting them)
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
for (i = 0; i < numFDs; i++) {
|
2002-11-03 06:19:34 +03:00
|
|
|
int fd = fds[i].fd;
|
|
|
|
|
|
|
|
// initialize events masks
|
2007-10-01 22:48:52 +04:00
|
|
|
sync->set[i].selected_events = fds[i].events & ~POLLNVAL
|
|
|
|
| POLLERR | POLLHUP;
|
2007-10-01 05:37:28 +04:00
|
|
|
sync->set[i].events = 0;
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
if (select_fd(fd, sync->set + i, kernel) == B_OK) {
|
2007-10-01 22:48:52 +04:00
|
|
|
fds[i].revents = 0;
|
|
|
|
if (sync->set[i].selected_events != 0)
|
|
|
|
count++;
|
|
|
|
} else
|
|
|
|
fds[i].revents = POLLNVAL;
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count < 1) {
|
|
|
|
count = B_BAD_VALUE;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
status = acquire_sem_etc(sync->sem, 1,
|
2008-02-23 18:59:30 +03:00
|
|
|
B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
// deselect file descriptors
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
for (i = 0; i < numFDs; i++)
|
2007-10-02 23:47:31 +04:00
|
|
|
deselect_fd(fds[i].fd, sync->set + i, kernel);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
// collect the events that are happened in the meantime
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case B_OK:
|
2007-03-29 20:09:53 +04:00
|
|
|
for (count = 0, i = 0; i < numFDs; i++) {
|
2002-11-03 06:19:34 +03:00
|
|
|
if (fds[i].revents == POLLNVAL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// POLLxxx flags and B_SELECT_xxx flags are compatible
|
2007-10-01 22:48:52 +04:00
|
|
|
fds[i].revents = sync->set[i].events
|
|
|
|
& sync->set[i].selected_events;
|
2002-11-03 06:19:34 +03:00
|
|
|
if (fds[i].revents != 0)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case B_INTERRUPTED:
|
|
|
|
count = B_INTERRUPTED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// B_TIMED_OUT, and B_WOULD_BLOCK
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
2007-10-01 05:37:28 +04:00
|
|
|
put_select_sync(sync);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2008-05-10 20:23:48 +04:00
|
|
|
T(PollDone(fds, numFDs, count));
|
|
|
|
|
2002-11-03 06:19:34 +03:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
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
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
put_select_sync(sync);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - kernel private
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2007-10-01 05:37:28 +04:00
|
|
|
notify_select_events(select_info* info, uint16 events)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
2007-10-01 05:37:28 +04:00
|
|
|
FUNCTION(("notify_select_events(%p (%p), 0x%x)\n", info, info->sync,
|
|
|
|
events));
|
2005-03-18 00:27:01 +03:00
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
if (info == NULL
|
|
|
|
|| info->sync == NULL
|
|
|
|
|| info->sync->sem < B_OK)
|
2002-11-03 06:19:34 +03:00
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2008-04-30 20:12:20 +04:00
|
|
|
atomic_or(&info->events, events);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// only wake up the waiting select()/poll() call if the events
|
|
|
|
// match one of the selected ones
|
|
|
|
if (info->selected_events & events)
|
2007-10-02 23:47:31 +04:00
|
|
|
return release_sem_etc(info->sync->sem, 1, B_DO_NOT_RESCHEDULE);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-01 05:37:28 +04:00
|
|
|
// #pragma mark - public kernel API
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2007-10-02 23:47:31 +04:00
|
|
|
notify_select_event(struct selectsync *sync, uint8 event)
|
2007-10-01 05:37:28 +04:00
|
|
|
{
|
|
|
|
return notify_select_events((select_info*)sync, SELECT_FLAG(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// #pragma mark - private kernel exported API
|
2005-03-18 00:27:01 +03:00
|
|
|
|
|
|
|
|
|
|
|
static select_sync_pool_entry *
|
2007-10-02 23:47:31 +04:00
|
|
|
find_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync)
|
2005-03-18 00:27:01 +03:00
|
|
|
{
|
|
|
|
for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator();
|
|
|
|
it.HasNext();) {
|
|
|
|
select_sync_pool_entry *entry = it.Next();
|
2007-10-02 23:47:31 +04:00
|
|
|
if (entry->sync == sync)
|
2005-03-18 00:27:01 +03:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
add_select_sync_pool_entry(select_sync_pool *pool, selectsync *sync,
|
2007-10-02 23:47:31 +04:00
|
|
|
uint8 event)
|
2005-03-18 00:27:01 +03:00
|
|
|
{
|
|
|
|
// check, whether the entry does already exist
|
2007-10-02 23:47:31 +04:00
|
|
|
select_sync_pool_entry *entry = find_select_sync_pool_entry(pool, sync);
|
2005-03-18 00:27:01 +03:00
|
|
|
if (!entry) {
|
2006-03-27 14:27:05 +04:00
|
|
|
entry = new (std::nothrow) select_sync_pool_entry;
|
2005-03-18 00:27:01 +03:00
|
|
|
if (!entry)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
entry->sync = sync;
|
|
|
|
entry->events = 0;
|
2005-03-21 01:15:33 +03:00
|
|
|
|
|
|
|
pool->entries.Add(entry);
|
2005-03-18 00:27:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
entry->events |= SELECT_FLAG(event);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
add_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync,
|
2007-10-02 23:47:31 +04:00
|
|
|
uint8 event)
|
2005-03-18 00:27:01 +03:00
|
|
|
{
|
|
|
|
// create the pool, if necessary
|
|
|
|
select_sync_pool *pool = *_pool;
|
|
|
|
if (!pool) {
|
2006-03-27 14:27:05 +04:00
|
|
|
pool = new (std::nothrow) select_sync_pool;
|
2005-03-18 00:27:01 +03:00
|
|
|
if (!pool)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
*_pool = pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the entry
|
2007-10-02 23:47:31 +04:00
|
|
|
status_t error = add_select_sync_pool_entry(pool, sync, event);
|
2005-03-18 00:27:01 +03:00
|
|
|
|
|
|
|
// cleanup
|
|
|
|
if (pool->entries.IsEmpty()) {
|
|
|
|
delete pool;
|
|
|
|
*_pool = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
remove_select_sync_pool_entry(select_sync_pool **_pool, selectsync *sync,
|
|
|
|
uint8 event)
|
|
|
|
{
|
|
|
|
select_sync_pool *pool = *_pool;
|
|
|
|
if (!pool)
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
// clear the event flag of the concerned entries
|
|
|
|
bool found = false;
|
|
|
|
for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator();
|
|
|
|
it.HasNext();) {
|
|
|
|
select_sync_pool_entry *entry = it.Next();
|
|
|
|
if (entry->sync == sync) {
|
|
|
|
found = true;
|
|
|
|
entry->events &= ~SELECT_FLAG(event);
|
|
|
|
|
|
|
|
// remove the entry, if no longer needed
|
|
|
|
if (entry->events == 0) {
|
|
|
|
it.Remove();
|
|
|
|
delete entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
// delete the pool, if no longer needed
|
|
|
|
if (pool->entries.IsEmpty()) {
|
|
|
|
delete pool;
|
|
|
|
*_pool = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-21 01:15:33 +03:00
|
|
|
void
|
|
|
|
delete_select_sync_pool(select_sync_pool *pool)
|
|
|
|
{
|
|
|
|
if (!pool)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (select_sync_pool_entry *entry = pool->entries.Head()) {
|
|
|
|
pool->entries.Remove(entry);
|
|
|
|
delete entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-18 00:27:01 +03:00
|
|
|
void
|
|
|
|
notify_select_event_pool(select_sync_pool *pool, uint8 event)
|
|
|
|
{
|
|
|
|
if (!pool)
|
|
|
|
return;
|
|
|
|
|
2005-03-21 01:15:33 +03:00
|
|
|
FUNCTION(("notify_select_event_pool(%p, %u)\n", pool, event));
|
|
|
|
|
2005-03-18 00:27:01 +03:00
|
|
|
for (SelectSyncPoolEntryList::Iterator it = pool->entries.GetIterator();
|
|
|
|
it.HasNext();) {
|
|
|
|
select_sync_pool_entry *entry = it.Next();
|
|
|
|
if (entry->events & SELECT_FLAG(event))
|
2007-10-02 23:47:31 +04:00
|
|
|
notify_select_event(entry->sync, event);
|
2005-03-18 00:27:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// #pragma mark - Kernel POSIX layer
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
|
2004-06-15 19:29:37 +04:00
|
|
|
ssize_t
|
2007-03-29 20:09:53 +04:00
|
|
|
_kern_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
2002-11-03 06:19:34 +03:00
|
|
|
bigtime_t timeout, const sigset_t *sigMask)
|
|
|
|
{
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
if (timeout >= 0)
|
|
|
|
timeout += system_time();
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
return common_select(numFDs, readSet, writeSet, errorSet, timeout,
|
|
|
|
sigMask, true);
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:29:37 +04:00
|
|
|
ssize_t
|
2007-03-29 20:09:53 +04:00
|
|
|
_kern_poll(struct pollfd *fds, int numFDs, bigtime_t timeout)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
if (timeout >= 0)
|
|
|
|
timeout += system_time();
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
return common_poll(fds, numFDs, timeout, true);
|
2002-11-03 06:19:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
// #pragma mark - User syscalls
|
2005-03-29 01:45:56 +04:00
|
|
|
|
|
|
|
|
2004-06-15 19:29:37 +04:00
|
|
|
ssize_t
|
2007-03-29 20:09:53 +04:00
|
|
|
_user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet,
|
|
|
|
fd_set *userErrorSet, bigtime_t timeout, const sigset_t *userSigMask)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
|
|
|
fd_set *readSet = NULL, *writeSet = NULL, *errorSet = NULL;
|
2007-03-29 20:09:53 +04:00
|
|
|
uint32 bytes = _howmany(numFDs, NFDBITS) * sizeof(fd_mask);
|
2002-11-03 06:19:34 +03:00
|
|
|
sigset_t sigMask;
|
|
|
|
int result;
|
|
|
|
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
syscall_restart_handle_timeout_pre(timeout);
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
if (numFDs < 0)
|
2002-11-03 06:19:34 +03:00
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if ((userReadSet != NULL && !IS_USER_ADDRESS(userReadSet))
|
|
|
|
|| (userWriteSet != NULL && !IS_USER_ADDRESS(userWriteSet))
|
|
|
|
|| (userErrorSet != NULL && !IS_USER_ADDRESS(userErrorSet))
|
|
|
|
|| (userSigMask != NULL && !IS_USER_ADDRESS(userSigMask)))
|
2002-11-03 06:19:34 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
// copy parameters
|
|
|
|
|
|
|
|
if (userReadSet != NULL) {
|
2005-03-18 00:27:01 +03:00
|
|
|
readSet = (fd_set *)malloc(bytes);
|
2002-11-03 06:19:34 +03:00
|
|
|
if (readSet == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
if (user_memcpy(readSet, userReadSet, bytes) < B_OK) {
|
|
|
|
result = B_BAD_ADDRESS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userWriteSet != NULL) {
|
2005-03-18 00:27:01 +03:00
|
|
|
writeSet = (fd_set *)malloc(bytes);
|
2002-11-03 06:19:34 +03:00
|
|
|
if (writeSet == NULL) {
|
|
|
|
result = B_NO_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (user_memcpy(writeSet, userWriteSet, bytes) < B_OK) {
|
|
|
|
result = B_BAD_ADDRESS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userErrorSet != NULL) {
|
2005-03-18 00:27:01 +03:00
|
|
|
errorSet = (fd_set *)malloc(bytes);
|
2002-11-03 06:19:34 +03:00
|
|
|
if (errorSet == NULL) {
|
|
|
|
result = B_NO_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (user_memcpy(errorSet, userErrorSet, bytes) < B_OK) {
|
|
|
|
result = B_BAD_ADDRESS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userSigMask != NULL)
|
|
|
|
sigMask = *userSigMask;
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
result = common_select(numFDs, readSet, writeSet, errorSet, timeout,
|
|
|
|
userSigMask ? &sigMask : NULL, false);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
// copy back results
|
|
|
|
|
|
|
|
if (result >= B_OK
|
2007-03-29 20:09:53 +04:00
|
|
|
&& ((readSet != NULL
|
|
|
|
&& user_memcpy(userReadSet, readSet, bytes) < B_OK)
|
|
|
|
|| (writeSet != NULL
|
|
|
|
&& user_memcpy(userWriteSet, writeSet, bytes) < B_OK)
|
|
|
|
|| (errorSet != NULL
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
&& user_memcpy(userErrorSet, errorSet, bytes) < B_OK))) {
|
2002-11-03 06:19:34 +03:00
|
|
|
result = B_BAD_ADDRESS;
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
} else
|
|
|
|
syscall_restart_handle_timeout_post(result, timeout);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
err:
|
|
|
|
free(readSet);
|
|
|
|
free(writeSet);
|
|
|
|
free(errorSet);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-15 19:29:37 +04:00
|
|
|
ssize_t
|
2007-03-29 20:09:53 +04:00
|
|
|
_user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout)
|
2002-11-03 06:19:34 +03:00
|
|
|
{
|
|
|
|
struct pollfd *fds;
|
|
|
|
size_t bytes;
|
|
|
|
int result;
|
|
|
|
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
syscall_restart_handle_timeout_pre(timeout);
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
if (numFDs < 0)
|
2002-11-03 06:19:34 +03:00
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (userfds == NULL || !IS_USER_ADDRESS(userfds))
|
2002-11-03 06:19:34 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
// copy parameters
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
fds = (struct pollfd *)malloc(bytes = numFDs * sizeof(struct pollfd));
|
2002-11-03 06:19:34 +03:00
|
|
|
if (fds == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
if (user_memcpy(fds, userfds, bytes) < B_OK) {
|
|
|
|
result = B_BAD_ADDRESS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2007-03-29 20:09:53 +04:00
|
|
|
result = common_poll(fds, numFDs, timeout, false);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
// copy back results
|
|
|
|
if (result >= B_OK && user_memcpy(userfds, fds, bytes) < B_OK)
|
|
|
|
result = B_BAD_ADDRESS;
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
else
|
|
|
|
syscall_restart_handle_timeout_post(result, timeout);
|
2002-11-03 06:19:34 +03:00
|
|
|
|
|
|
|
err:
|
|
|
|
free(fds);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
|
|
|
|
ssize_t
|
|
|
|
_user_wait_for_objects(object_wait_info* userInfos, int numInfos, uint32 flags,
|
|
|
|
bigtime_t timeout)
|
|
|
|
{
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
syscall_restart_handle_timeout_pre(flags, timeout);
|
|
|
|
|
2007-10-02 23:47:31 +04:00
|
|
|
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);
|
|
|
|
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK)
|
2007-10-02 23:47:31 +04:00
|
|
|
result = B_BAD_ADDRESS;
|
axeld + bonefish:
* Implemented automatic syscall restarts:
- A syscall can indicate that it has been interrupted and can be
restarted by setting a respective bit in thread::flags. It can
store parameters it wants to be preserved for the restart in
thread::syscall_restart::parameters. Another thread::flags bit
indicates whether it has been restarted.
- handle_signals() clears the restart flag, if the handled signal
has a handler function installed and SA_RESTART is not set. Another
thread flag (THREAD_FLAGS_DONT_RESTART_SYSCALL) can prevent syscalls
from being restarted, even if they could be (not used yet, but we
might want to use it in resume_thread(), so that we stay
behaviorally compatible with BeOS).
- The architecture specific syscall handler restarts the syscall, if
the restart flag is set. Implemented for x86 only.
- Added some support functions in the private <syscall_restart.h> to
simplify the syscall restart code in the syscalls.
- Adjusted all syscalls that can potentially be restarted accordingly.
- _user_ioctl() sets new thread flag THREAD_FLAGS_IOCTL_SYSCALL while
calling the underlying FS's/driver's hook, so that syscall restarts
can also be supported there.
* thread_at_kernel_exit() invokes handle_signals() in a loop now, as
long as the latter indicates that the thread shall be suspended, so
that after waking up signals received in the meantime will be handled
before the thread returns to userland. Adjusted handle_signals()
accordingly -- when encountering a suspending signal we don't check
for further signals.
* Fixed sigsuspend(): Suspending the thread and rescheduling doesn't
result in the correct behavior. Instead we employ a temporary
condition variable and interruptably wait on it. The POSIX test
suite test passes, now.
* Made the switch_sem[_etc]() behavior on interruption consistent.
Depending on when the signal arrived (before the call or when already
waiting) the first semaphore would or wouldn't be released. Now we
consistently release it.
* Refactored _user_{read,write}[v]() syscalls. Use a common function for
either pair. The iovec version doesn't fail anymore, if anything could
be read/written at all. It also checks whether a complete vector
could be read/written, so that we won't skip data, if the underlying
FS/driver couldn't read/write more ATM.
* Some refactoring in the x86 syscall handler: The int 99 and sysenter
handlers use a common subroutine to avoid code duplication.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23983 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-02-17 18:48:30 +03:00
|
|
|
else
|
|
|
|
syscall_restart_handle_timeout_post(result, timeout);
|
2007-10-02 23:47:31 +04:00
|
|
|
} else
|
|
|
|
result = B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
free(infos);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|