diff --git a/libc/Makefile b/libc/Makefile
index b8d67ff5..20dcddb5 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -189,6 +189,8 @@ on_exit.o \
openat.o \
open.o \
pipe.o \
+poll.o \
+ppoll.o \
print.o \
putc.o \
raise.o \
diff --git a/libc/include/poll.h b/libc/include/poll.h
new file mode 100644
index 00000000..77717bfb
--- /dev/null
+++ b/libc/include/poll.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ poll.h
+ Input/output multiplexing.
+
+*******************************************************************************/
+
+#ifndef _POLL_H
+#define _POLL_H 1
+
+#include
+
+__BEGIN_DECLS
+
+@include(time_t.h)
+
+__END_DECLS
+#include
+#include
+#include
+__BEGIN_DECLS
+
+int poll(struct pollfd* fds, nfds_t nfds, int timeout);
+int ppoll(struct pollfd* fds, nfds_t nfds, const struct timespec* timeout,
+ const sigset_t* sigmask);
+
+__END_DECLS
+
+#endif
diff --git a/libc/poll.cpp b/libc/poll.cpp
new file mode 100644
index 00000000..d9048840
--- /dev/null
+++ b/libc/poll.cpp
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ poll.cpp
+ Input/output multiplexing.
+
+*******************************************************************************/
+
+#include
+#include
+
+extern "C" int poll(struct pollfd* fds, nfds_t nfds, int timeout)
+{
+ struct timespec ts;
+ ts.tv_sec = timeout;
+ ts.tv_nsec = 0;
+ return ppoll(fds, nfds, &ts, NULL);
+}
diff --git a/libc/ppoll.cpp b/libc/ppoll.cpp
new file mode 100644
index 00000000..ddbf9fdd
--- /dev/null
+++ b/libc/ppoll.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ ppoll.cpp
+ Input/output multiplexing.
+
+*******************************************************************************/
+
+#include
+
+#include
+
+DEFN_SYSCALL4(int, sys_ppoll, SYSCALL_PPOLL, struct pollfd*, nfds_t,
+ const struct timespec*, const sigset_t*);
+
+extern "C" int ppoll(struct pollfd* fds, nfds_t nfds,
+ const struct timespec* timeout, const sigset_t* sigmask)
+{
+ return sys_ppoll(fds, nfds, timeout, sigmask);
+}
diff --git a/sortix/Makefile b/sortix/Makefile
index 466198a6..9119a1f1 100644
--- a/sortix/Makefile
+++ b/sortix/Makefile
@@ -106,6 +106,7 @@ mtable.o \
panic.o \
pci.o \
pipe.o \
+poll.o \
process.o \
refcount.o \
scheduler.o \
diff --git a/sortix/descriptor.cpp b/sortix/descriptor.cpp
index ce2b7078..cfe0fc10 100644
--- a/sortix/descriptor.cpp
+++ b/sortix/descriptor.cpp
@@ -416,4 +416,9 @@ int Descriptor::gettermmode(ioctx_t* ctx, unsigned* mode)
return vnode->gettermmode(ctx, mode);
}
+int Descriptor::poll(ioctx_t* ctx, PollNode* node)
+{
+ return vnode->poll(ctx, node);
+}
+
} // namespace Sortix
diff --git a/sortix/fs/user.cpp b/sortix/fs/user.cpp
index b7eabccf..18822222 100644
--- a/sortix/fs/user.cpp
+++ b/sortix/fs/user.cpp
@@ -213,6 +213,7 @@ public:
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
virtual int settermmode(ioctx_t* ctx, unsigned mode);
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
+ virtual int poll(ioctx_t* ctx, PollNode* node);
private:
bool SendMessage(Channel* channel, size_t type, void* ptr, size_t size,
@@ -1115,6 +1116,11 @@ int Unode::gettermmode(ioctx_t* ctx, unsigned* mode)
return ret;
}
+int Unode::poll(ioctx_t* /*ctx*/, PollNode* /*node*/)
+{
+ return errno = ENOTSUP, -1;
+}
+
//
// Initialization.
//
diff --git a/sortix/include/sortix/kernel/descriptor.h b/sortix/include/sortix/kernel/descriptor.h
index fb61b45b..e66e1faf 100644
--- a/sortix/include/sortix/kernel/descriptor.h
+++ b/sortix/include/sortix/kernel/descriptor.h
@@ -41,6 +41,7 @@ struct kernel_dirent;
namespace Sortix {
+class PollNode;
class Inode;
class Vnode;
struct ioctx_struct;
@@ -77,6 +78,7 @@ public:
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
int settermmode(ioctx_t* ctx, unsigned mode);
int gettermmode(ioctx_t* ctx, unsigned* mode);
+ int poll(ioctx_t* ctx, PollNode* node);
private:
Ref open_elem(ioctx_t* ctx, const char* filename, int flags,
diff --git a/sortix/include/sortix/kernel/inode.h b/sortix/include/sortix/kernel/inode.h
index 3cfd96f0..2dacdb55 100644
--- a/sortix/include/sortix/kernel/inode.h
+++ b/sortix/include/sortix/kernel/inode.h
@@ -41,6 +41,7 @@ struct kernel_dirent;
namespace Sortix {
+class PollNode;
struct ioctx_struct;
typedef struct ioctx_struct ioctx_t;
@@ -87,6 +88,7 @@ public:
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws) = 0;
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
virtual int gettermmode(ioctx_t* ctx, unsigned* mode) = 0;
+ virtual int poll(ioctx_t* ctx, PollNode* node) = 0;
};
@@ -151,6 +153,7 @@ public:
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
virtual int settermmode(ioctx_t* ctx, unsigned mode);
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
+ virtual int poll(ioctx_t* ctx, PollNode* node);
};
diff --git a/sortix/include/sortix/kernel/poll.h b/sortix/include/sortix/kernel/poll.h
new file mode 100644
index 00000000..7da30245
--- /dev/null
+++ b/sortix/include/sortix/kernel/poll.h
@@ -0,0 +1,83 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ sortix/kernel/poll.h
+ Kernel declarations for event polling.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SORTIX_KERNEL_POLL_H
+#define INCLUDE_SORTIX_KERNEL_POLL_H
+
+#include
+
+namespace Sortix {
+
+class PollChannel;
+class PollNode;
+
+class PollChannel
+{
+public:
+ PollChannel();
+ ~PollChannel();
+ void Signal(short events);
+ void Register(PollNode* node);
+ void Unregister(PollNode* node);
+
+private:
+ void SignalUnlocked(short events);
+
+private:
+ struct PollNode* first;
+ struct PollNode* last;
+ kthread_mutex_t channel_lock;
+ kthread_cond_t no_pending_cond;
+
+};
+
+class PollNode
+{
+ friend class PollChannel;
+
+public:
+ PollNode() { next = NULL; prev = NULL; channel = NULL; }
+
+private:
+ PollNode* next;
+ PollNode* prev;
+
+public:
+ PollChannel* channel;
+
+public:
+ kthread_mutex_t* wake_mutex;
+ kthread_cond_t* wake_cond;
+ short events;
+ short revents;
+ bool* woken;
+
+public:
+ void Cancel();
+
+};
+
+} // namespace Sortix
+
+#endif
diff --git a/sortix/include/sortix/kernel/vnode.h b/sortix/include/sortix/kernel/vnode.h
index a18a3cc7..42a09b2f 100644
--- a/sortix/include/sortix/kernel/vnode.h
+++ b/sortix/include/sortix/kernel/vnode.h
@@ -34,6 +34,7 @@ struct kernel_dirent;
namespace Sortix {
+class PollNode;
class Inode;
struct ioctx_struct;
typedef struct ioctx_struct ioctx_t;
@@ -74,6 +75,7 @@ public:
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
int settermmode(ioctx_t* ctx, unsigned mode);
int gettermmode(ioctx_t* ctx, unsigned* mode);
+ int poll(ioctx_t* ctx, PollNode* node);
public /*TODO: private*/:
Ref inode;
diff --git a/sortix/include/sortix/poll.h b/sortix/include/sortix/poll.h
new file mode 100644
index 00000000..b79ae372
--- /dev/null
+++ b/sortix/include/sortix/poll.h
@@ -0,0 +1,57 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ sortix/poll.h
+ Interface for waiting on file descriptor events.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SORTIX_POLL_H
+#define INCLUDE_SORTIX_POLL_H
+
+#include
+
+__BEGIN_DECLS
+
+typedef unsigned long int nfds_t;
+
+struct pollfd
+{
+ int fd;
+ short events;
+ short revents;
+};
+
+#define POLLERR (1<<0)
+#define POLLHUP (1<<1)
+#define POLLNVAL (1<<2)
+
+#define POLLIN (1<<3)
+#define POLLRDNORM (1<<4)
+#define POLLRDBAND (1<<5)
+#define POLLPRI (1<<6)
+#define POLLOUT (1<<7)
+#define POLLWRNORM (1<<8)
+#define POLLWRBAND (1<<9)
+
+#define POLL__ONLY_REVENTS (POLLERR | POLLHUP | POLLNVAL)
+
+__END_DECLS
+
+#endif
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index b8e77f09..fab1d7c2 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -93,6 +93,7 @@
#define SYSCALL_FCHMODAT 69
#define SYSCALL_LINKAT 70
#define SYSCALL_FSM_FSBIND 71
-#define SYSCALL_MAX_NUM 72 /* index of highest constant + 1 */
+#define SYSCALL_PPOLL 72
+#define SYSCALL_MAX_NUM 73 /* index of highest constant + 1 */
#endif
diff --git a/sortix/inode.cpp b/sortix/inode.cpp
index 95c31d6f..7afa5c43 100644
--- a/sortix/inode.cpp
+++ b/sortix/inode.cpp
@@ -267,4 +267,18 @@ int AbstractInode::gettermmode(ioctx_t* /*ctx*/, unsigned* /*mode*/)
return errno = ENOTTY, -1;
}
+int AbstractInode::poll(ioctx_t* /*ctx*/, PollNode* /*node*/)
+{
+#if 0 // TODO: Support poll on regular files as per POSIX.
+ if ( inode_type == INODE_TYPE_FILE )
+ {
+ // TODO: Correct bits?
+ node->revents |= (POLLIN | POLLOUT) & node->events;
+ // TODO: What if not listening on events (POLLIN | POLLOUT)?
+ return 0;
+ }
+#endif
+ return errno = ENOTSUP, -1;
+}
+
} // namespace Sortix
diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp
index 16c2a196..c5d27229 100644
--- a/sortix/kernel.cpp
+++ b/sortix/kernel.cpp
@@ -73,6 +73,7 @@
#include "io.h"
#include "pipe.h"
#include "interrupt.h"
+#include "poll.h"
#include "dispmsg.h"
#include "fs/kram.h"
#include "fs/user.h"
@@ -396,6 +397,9 @@ static void BootThread(void* /*user*/)
// Initialize the pipe system.
Pipe::Init();
+ // Initialize poll system call.
+ Poll::Init();
+
// Initialize the kernel information query syscall.
Info::Init();
diff --git a/sortix/poll.cpp b/sortix/poll.cpp
new file mode 100644
index 00000000..56000198
--- /dev/null
+++ b/sortix/poll.cpp
@@ -0,0 +1,263 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ poll.cpp
+ Interface for waiting on file descriptor events.
+
+*******************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "syscall.h"
+#include "process.h"
+#include "poll.h"
+
+namespace Sortix {
+
+PollChannel::PollChannel()
+{
+ first = NULL;
+ last = NULL;
+ channel_lock = KTHREAD_MUTEX_INITIALIZER;
+ no_pending_cond = KTHREAD_COND_INITIALIZER;
+}
+
+PollChannel::~PollChannel()
+{
+ ScopedLock lock(&channel_lock);
+ // TODO: Is this the correct error to signal with?
+ SignalUnlocked(POLLHUP);
+ // Note: We can't stop early in case of a signal, because that would mean
+ // other threads are still using our data, and since this is the destructor,
+ // leaving early _will_ cause data corruption. Luckily, this loop will
+ // terminate because everyone is now woken up and will cancel, which is what
+ // we wait for to finish. No new requests can come, since we are the
+ // destructor - whoever owns this object is no longer using it.
+ while ( first )
+ kthread_cond_wait(&no_pending_cond, &channel_lock);
+}
+
+void PollChannel::Signal(short events)
+{
+ ScopedLock lock(&channel_lock);
+ SignalUnlocked(events);
+}
+
+void PollChannel::SignalUnlocked(short events)
+{
+ for ( PollNode* node = first; node; node = node->next )
+ if ( node->revents |= events & (node->events | POLL__ONLY_REVENTS) )
+ {
+ ScopedLock node_lock(node->wake_mutex);
+ if ( !*node->woken )
+ {
+ *node->woken = true;
+ kthread_cond_signal(node->wake_cond);
+ }
+ }
+}
+
+void PollChannel::Register(PollNode* node)
+{
+ ScopedLock lock(&channel_lock);
+ node->channel = this;
+ if ( !first )
+ first = last = node,
+ node->next = node->prev = NULL;
+ else
+ node->next = NULL,
+ node->prev = last,
+ last->next = node,
+ last = node;
+}
+
+void PollChannel::Unregister(PollNode* node)
+{
+ ScopedLock lock(&channel_lock);
+ node->channel = NULL;
+ if ( node->prev )
+ node->prev->next = node->next;
+ else
+ first = node->next;
+ if ( node->next )
+ node->next->prev = node->prev;
+ else
+ last = node->prev;
+ if ( !first )
+ kthread_cond_signal(&no_pending_cond);
+}
+
+void PollNode::Cancel()
+{
+ if ( channel )
+ channel->Unregister(this);
+}
+
+namespace Poll {
+
+static struct pollfd* CopyFdsFromUser(struct pollfd* user_fds, nfds_t nfds)
+{
+ size_t size = sizeof(struct pollfd) * nfds;
+ struct pollfd* fds = new struct pollfd[nfds];
+ if ( !fds )
+ return NULL;
+ if ( !CopyFromUser(fds, user_fds, size) )
+ {
+ delete[] fds;
+ return NULL;
+ }
+ return fds;
+}
+
+static bool CopyFdsToUser(struct pollfd* user_fds,
+ const struct pollfd* kernel_fds, nfds_t nfds)
+{
+ size_t size = sizeof(struct pollfd) * nfds;
+ return CopyToUser(user_fds, kernel_fds, size);
+}
+
+static bool FetchTimespec(struct timespec* dest, const struct timespec* user)
+{
+ if ( !user )
+ dest->tv_sec = -1,
+ dest->tv_nsec = 0;
+ else if ( !CopyFromUser(dest, user, sizeof(*dest)) )
+ return false;
+ return true;
+}
+
+static int sys_ppoll(struct pollfd* user_fds, nfds_t nfds,
+ const struct timespec* user_timeout_ts,
+ const sigset_t* user_sigmask)
+{
+ ioctx_t ctx; SetupKernelIOCtx(&ctx);
+
+ struct timespec timeout_ts;
+ if ( !FetchTimespec(&timeout_ts, user_timeout_ts) )
+ return -1;
+
+ if ( 0 < timeout_ts.tv_sec || timeout_ts.tv_nsec || user_sigmask )
+ return errno = ENOSYS, -1;
+
+ struct pollfd* fds = CopyFdsFromUser(user_fds, nfds);
+ if ( !fds ) { return -1; }
+
+ PollNode* nodes = new PollNode[nfds];
+ if ( !nodes ) { delete[] fds; return -1; }
+
+ Process* process = CurrentProcess();
+
+ kthread_mutex_t wakeup_mutex = KTHREAD_MUTEX_INITIALIZER;
+ kthread_cond_t wakeup_cond = KTHREAD_COND_INITIALIZER;
+
+ kthread_mutex_lock(&wakeup_mutex);
+
+ int ret = -1;
+ bool self_woken = false;
+ volatile bool remote_woken = false;
+ bool unexpected_error = false;
+
+ nfds_t reqs = nfds;
+ for ( reqs = 0; !unexpected_error && reqs < nfds; reqs++ )
+ {
+ PollNode* node = nodes + reqs;
+ if ( fds[reqs].fd < 0 )
+ {
+ fds[reqs].revents = POLLNVAL;
+ // TODO: Should we set POLLNVAL in node->revents too? Should this
+ // system call ignore this error and keep polling, or return to
+ // user-space immediately? What if conditions are already true on
+ // some of the file descriptors (those we have processed so far?)?
+ node->revents = 0;
+ continue;
+ }
+ Ref desc = process->GetDescriptor(fds[reqs].fd);
+ if ( !desc ) { unexpected_error = true; break; }
+ node->events = fds[reqs].events;
+ node->revents = 0;
+ node->wake_mutex = &wakeup_mutex;
+ node->wake_cond = &wakeup_cond;
+ node->woken = (bool*) &remote_woken;
+ // TODO: How should erors be handled?
+ if ( desc->poll(&ctx, node) == 0 )
+ self_woken = true;
+ else if ( errno != EAGAIN )
+ unexpected_error = self_woken = true;
+ }
+
+ if ( timeout_ts.tv_sec < 0 )
+ self_woken = true;
+
+ while ( !(self_woken || remote_woken) )
+ {
+ if ( !kthread_cond_wait_signal(&wakeup_cond, &wakeup_mutex) )
+ errno = -EINTR,
+ self_woken = true;
+ }
+
+ kthread_mutex_unlock(&wakeup_mutex);
+
+ for ( nfds_t i = 0; i < reqs; i++ )
+ nodes[i].Cancel();
+
+ if ( !unexpected_error )
+ {
+ int num_events = 0;
+ for ( nfds_t i = 0; i < reqs; i++ )
+ {
+ if ( fds[i].fd < -1 )
+ continue;
+ if ( (fds[i].revents = nodes[i].revents) )
+ num_events++;
+ }
+
+ if ( CopyFdsToUser(user_fds, fds, nfds) )
+ ret = num_events;
+ }
+
+ delete[] nodes;
+ delete[] fds;
+ return ret;
+}
+
+void Init()
+{
+ Syscall::Register(SYSCALL_PPOLL, (void*) sys_ppoll);
+}
+
+} // namespace Poll
+
+} // namespace Sortix
diff --git a/sortix/poll.h b/sortix/poll.h
new file mode 100644
index 00000000..4cb5ea67
--- /dev/null
+++ b/sortix/poll.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2012.
+
+ This file is part of Sortix.
+
+ Sortix is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ Sortix. If not, see .
+
+ poll.h
+ Interface for waiting on file descriptor events.
+
+*******************************************************************************/
+
+#ifndef SORTIX_POLL_H
+#define SORTIX_POLL_H
+
+namespace Sortix {
+namespace Poll {
+
+void Init();
+
+} // nanmespace Poll
+} // namespace Sortix
+
+#endif
diff --git a/sortix/vnode.cpp b/sortix/vnode.cpp
index 24549b29..b8dfa870 100644
--- a/sortix/vnode.cpp
+++ b/sortix/vnode.cpp
@@ -213,4 +213,9 @@ int Vnode::gettermmode(ioctx_t* ctx, unsigned* mode)
return inode->gettermmode(ctx, mode);
}
+int Vnode::poll(ioctx_t* ctx, PollNode* node)
+{
+ return inode->poll(ctx, node);
+}
+
} // namespace Sortix