Hello,
This patch (3/5) reorganises console read and selection operations on the
boot server to improve
asynchronous I/O response times and prevent memory issues in pending read
operations. Key Changes:
poll() and wake_pipe Architecture: The temporary select() loop in
the main function has been replaced with a
modern poll() mechanism. Incoming read requests (queue_read) now
wake the main loop via a wake_pipe to
dynamically monitor stdin.
Dedicated Select Thread: A dedicated select_thread and queue
(selq), supported by CLOCK_MONOTONIC,
have been added to safely process non-console select requests
without clock drift side-effects.
Buffer and Memory Safeguards: Console and in-band reads have been
limited by `CONSOLE_READ_MAX`
and `IO_INBAND_MAX`. To prevent OOL queue page leaks, appropriate
`memcpy` + `munmap` pruning operations
have been implemented within `read_reply`, and a feature for
handling zero-length reads immediately has been added.
Lock Clean-up and EOF Handling: Lock boundaries (queuelock,
selq_lock) have been simplified, the old spin lock within
`unlock_readlock` has been removed, and atomic `stdin_eof`
monitoring has been integrated to respond immediately to
EOF conditions.
The patch is provided below for your consideration ;)
>From 6a9ac9915e800ddc9fe597d17f84bae441d13f30 Mon Sep 17 00:00:00 2001
From: Alperen ERKAN <[email protected]>
Date: Sat, 16 Sep 2026 12:50:33 +0300
Subject: [PATCH 3/5] boot: rework console read queue and add select queue
Replace the ad-hoc select() loop in main with poll() driven by a
wake pipe, rework the queued console read logic to bound request
sizes, track stdin EOF and answer zero-length reads immediately, and
add a select queue with a dedicated select thread. Also clean up
the device server entry points and the console io_read/io_write
routines.
---
hurd/boot/boot.c | 653
++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 470 insertions(+), 183 deletions(-)
diff --git a/hurd/boot/boot.c b/hurd/boot/boot.c
--- a/hurd/boot/boot.c
+++ b/hurd/boot/boot.c
@@ -907,24 +946,63 @@ main (int argc, char **argv, char **envp)
mach_port_deallocate (mach_task_self (), pseudo_master_device_port);
err = pthread_create (&pthread_id, NULL, msg_thread, NULL);
- if (!err)
- pthread_detach (pthread_id);
- else
- {
- errno = err;
- perror ("pthread_create");
- }
+ if (err)
+ error (1, err, "pthread_create");
+ pthread_detach (pthread_id);
+
+ err = pthread_create (&pthread_id, NULL, select_thread, NULL);
+ if (err)
+ error (1, err, "pthread_create");
+ pthread_detach (pthread_id);
for (;;)
{
- fd_set rmask;
- FD_ZERO (&rmask);
- FD_SET (0, &rmask);
- if (select (1, &rmask, 0, 0, 0) == 1)
+ int want_stdin;
+ struct pollfd pfd[2];
+ int n;
+
+ if (atomic_load_explicit (&stdin_eof, memory_order_relaxed))
+ {
+ /* Satisfy remaining waiters with EOF replies. */
+ pthread_spin_lock (&queuelock);
+ want_stdin = qrhead != NULL;
+ pthread_spin_unlock (&queuelock);
+ if (want_stdin)
+ {
+ read_reply ();
+ continue;
+ }
+ }
+ else
+ {
+ pthread_spin_lock (&queuelock);
+ want_stdin = qrhead != NULL;
+ pthread_spin_unlock (&queuelock);
+ }
+
+ pfd[0].fd = wake_pipe[0];
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ pfd[1].fd = 0;
+ pfd[1].events = POLLIN;
+ pfd[1].revents = 0;
+
+ n = poll (pfd, want_stdin ? 2 : 1, -1);
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ error (5, errno, "poll");
+ }
+
+ if (pfd[0].revents & POLLIN)
+ {
+ char c[128];
+ read (wake_pipe[0], c, sizeof c);
+ }
+
+ if (want_stdin && (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)))
read_reply ();
- else if (errno != EINTR)
- /* We hosed */
- error (5, errno, "select");
}
}
@@ -987,136 +1218,367 @@ struct qr
enum read_type type;
mach_port_t reply_port;
mach_msg_type_name_t reply_type;
- int amount;
+ vm_size_t amount;
struct qr *next;
};
struct qr *qrhead, *qrtail;
-/* Queue a read for later reply. */
-kern_return_t
-queue_read (enum read_type type,
- mach_port_t reply_port,
- mach_msg_type_name_t reply_type,
- int amount)
+struct selq
+{
+ mach_port_t reply_port;
+ mach_msg_type_name_t reply_type;
+ int is_timeout; /* Use io_select_timeout_reply. */
+ int type; /* Requested SELECT_* mask. */
+ struct timespec deadline; /* Valid iff IS_TIMEOUT. */
+ struct selq *next;
+};
+static struct selq *selq_head, *selq_tail;
+static pthread_mutex_t selq_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Send the reply for a queued console read QR. BUF/LEN are the data;
+ if ERR is nonzero, it is an errno-style error code and no data is
+ returned. */
+static void
+send_read_reply (struct qr *qr, const void *buf, ssize_t len, int err)
+{
+ switch (qr->type)
+ {
+ case DEV_READ:
+ ds_device_read_reply (qr->reply_port, qr->reply_type, err,
+ (io_buf_ptr_t) (err ? 0 : buf),
+ err ? 0 : len);
+ break;
+
+ case DEV_READI:
+ ds_device_read_reply_inband (qr->reply_port, qr->reply_type, err,
+ err ? (const void *) 0 : buf,
+ err ? 0 : len);
+ break;
+
+ case IO_READ:
+ io_read_reply (qr->reply_port, qr->reply_type, err,
+ err ? (void *) 0 : buf, err ? 0 : len);
+ break;
+ }
+}
+
+/* Queue a read for later reply. */
+static kern_return_t
+queue_read (enum read_type type, mach_port_t reply_port,
+ mach_msg_type_name_t reply_type, vm_size_t amount)
{
struct qr *qr;
- qr = malloc (sizeof (struct qr));
+ /* Zero-length requests and EOF get an immediate answer. */
+ if (amount == 0 || atomic_load_explicit (&stdin_eof,
memory_order_relaxed))
+ {
+ struct qr qr0 = { type, reply_port, reply_type, 0, NULL };
+ send_read_reply (&qr0, NULL, 0, 0);
+ return D_SUCCESS;
+ }
+
+ qr = malloc (sizeof *qr);
if (!qr)
return D_NO_MEMORY;
- pthread_spin_lock (&queuelock);
-
qr->type = type;
qr->reply_port = reply_port;
qr->reply_type = reply_type;
qr->amount = amount;
qr->next = 0;
+
+ pthread_spin_lock (&queuelock);
if (qrtail)
qrtail->next = qr;
else
- qrhead = qrtail = qr;
-
+ qrhead = qr;
+ qrtail = qr;
pthread_spin_unlock (&queuelock);
+
+ /* Wake the main thread so it starts polling stdin. */
+ if (write (wake_pipe[1], "", 1) < 0 && errno != EAGAIN && errno != EINTR)
+ /* ignore */;
+
return D_SUCCESS;
}
-/* TRUE if there's data available on stdin, which should be used to satisfy
- console read requests. */
-static int should_read = 0;
-
-/* Reply to a queued read. */
+/* Reply to the oldest queued console read, if any, using input from
+ host stdin. Called by the main thread when stdin is readable (or
+ at EOF, where read returns 0). */
static void
read_reply (void)
{
- int avail;
struct qr *qr;
- char * buf;
- int amtread;
-
- /* By forcing SHOULD_READ to true before trying the lock, we ensure that
- either we get the lock ourselves or that whoever currently holds the
- lock will service this read when he unlocks it. */
- should_read = 1;
- if (pthread_spin_trylock (&readlock))
- return;
+ ssize_t amtread = 0;
+ void *buf = NULL;
+ vm_size_t bufsize = 0;
+ char inband_buf[IO_INBAND_MAX];
- /* Since we're committed to servicing the read, no one else need do so.
*/
- should_read = 0;
+ pthread_spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
- if (!avail)
+ pthread_spin_lock (&queuelock);
+ qr = qrhead;
+ if (qr)
+ {
+ qrhead = qr->next;
+ if (qrhead == NULL)
+ qrtail = NULL;
+ }
+ pthread_spin_unlock (&queuelock);
+
+ if (! qr)
{
pthread_spin_unlock (&readlock);
return;
}
- pthread_spin_lock (&queuelock);
-
- if (!qrhead)
+ if (qr->type == DEV_READI)
{
- pthread_spin_unlock (&queuelock);
+ /* Amounts for in-band reads were validated at enqueue time. */
+ amtread = read (0, inband_buf, qr->amount);
+ if (amtread == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
pthread_spin_unlock (&readlock);
- return;
+ if (amtread < 0)
+ send_read_reply (qr, NULL, 0, errno ? errno : EIO);
+ else
+ send_read_reply (qr, inband_buf, amtread, 0);
+ }
+ else
+ {
+ bufsize = qr->amount;
+ buf = mmap (0, bufsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf == MAP_FAILED)
+ {
+ int e = errno ? errno : EIO;
+ pthread_spin_unlock (&readlock);
+ send_read_reply (qr, NULL, 0, e);
+ free (qr);
+ return;
+ }
+ amtread = read (0, buf, bufsize);
+ if (amtread == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+ if (amtread > 0 && (vm_size_t) amtread < bufsize)
+ {
+ /* Shrink the mapping so the tail pages cannot leak. */
+ void *nbuf = mmap (0, amtread, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (nbuf != MAP_FAILED)
+ {
+ memcpy (nbuf, buf, amtread);
+ munmap (buf, bufsize);
+ buf = nbuf;
+ bufsize = amtread;
+ }
+ }
+ if (amtread < 0)
+ {
+ int e = errno;
+ munmap (buf, bufsize);
+ pthread_spin_unlock (&readlock);
+ send_read_reply (qr, NULL, 0, e);
+ free (qr);
+ return;
+ }
+ pthread_spin_unlock (&readlock);
+ send_read_reply (qr, buf, amtread, 0);
+ munmap (buf, bufsize);
}
- qr = qrhead;
- qrhead = qr->next;
- if (qr == qrtail)
- qrtail = 0;
+ free (qr);
+}
- pthread_spin_unlock (&queuelock);
+/* Queue an io_select request; satisfied by SELECT_THREAD. */
+static kern_return_t
+queue_select (mach_port_t reply_port, mach_msg_type_name_t reply_type,
+ int type, int is_timeout, const struct timespec *ts)
+{
+ struct selq *sq;
- if (qr->type == DEV_READ)
+ if (type == 0)
+ return 0;
+
+ sq = malloc (sizeof *sq);
+ if (! sq)
+ return ENOMEM;
+
+ sq->reply_port = reply_port;
+ sq->reply_type = reply_type;
+ sq->is_timeout = is_timeout;
+ sq->type = type;
+ sq->next = NULL;
+ if (is_timeout)
{
- buf = mmap (0, qr->amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
- assert_backtrace (buf != MAP_FAILED);
+ if (clock_gettime (CLOCK_MONOTONIC, &sq->deadline) < 0)
+ {
+ free (sq);
+ return errno;
+ }
+ sq->deadline.tv_sec += ts->tv_sec;
+ sq->deadline.tv_nsec += ts->tv_nsec;
+ if (sq->deadline.tv_nsec >= 1000000000L)
+ {
+ sq->deadline.tv_nsec -= 1000000000L;
+ sq->deadline.tv_sec += 1;
+ }
}
+
+ pthread_mutex_lock (&selq_lock);
+ if (selq_tail)
+ selq_tail->next = sq;
else
- buf = alloca (qr->amount);
- amtread = read (0, buf, qr->amount);
+ selq_head = sq;
+ selq_tail = sq;
+ pthread_mutex_unlock (&selq_lock);
- pthread_spin_unlock (&readlock);
+ if (write (select_pipe[1], "", 1) < 0 && errno != EAGAIN && errno !=
EINTR)
+ /* ignore */;
- switch (qr->type)
+ return MIG_NO_REPLY;
+}
+
+static void *
+select_thread (void *arg)
+{
+ pthread_setname_np (pthread_self (), "select");
+
+ for (;;)
{
- case DEV_READ:
- if (amtread >= 0)
- ds_device_read_reply (qr->reply_port, qr->reply_type, 0,
- (io_buf_ptr_t) buf, amtread);
- else
- ds_device_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0);
- break;
+ int want_r = 0, want_w = 0, want_x = 0;
+ int n, i, npfd = 0;
+ int stdin_ready, stdout_ready, urg_ready;
+ struct selq *sq, **psq, *done = NULL, **pdone = &done;
+ struct pollfd pfd[3];
+ int timeout_ms = -1;
+ struct timespec now;
+
+ pthread_mutex_lock (&selq_lock);
+ for (sq = selq_head; sq; sq = sq->next)
+ {
+ if (sq->type & (SELECT_READ | SELECT_URG))
+ want_r = 1;
+ if (sq->type & SELECT_WRITE)
+ want_w = 1;
+ if (sq->type & SELECT_URG)
+ want_x = 1;
+ }
+ if (selq_head)
+ clock_gettime (CLOCK_MONOTONIC, &now);
+ for (sq = selq_head; sq; sq = sq->next)
+ {
+ if (sq->is_timeout)
+ {
+ long long ms = (sq->deadline.tv_sec - now.tv_sec) * 1000LL
+ + (sq->deadline.tv_nsec - now.tv_nsec) / 1000000LL;
+ int m = ms <= 0 ? 0 : (ms > 0x7fffffffLL ? 0x7fffffff : (int) ms);
+ if (timeout_ms < 0 || m < timeout_ms)
+ timeout_ms = m;
+ }
+ }
+ pthread_mutex_unlock (&selq_lock);
- case DEV_READI:
- if (amtread >= 0)
- ds_device_read_reply_inband (qr->reply_port, qr->reply_type, 0,
- buf, amtread);
- else
- ds_device_read_reply_inband (qr->reply_port, qr->reply_type, errno,
- 0, 0);
- break;
+ pfd[npfd].fd = select_pipe[0];
+ pfd[npfd].events = POLLIN;
+ npfd++;
+ if (want_r)
+ {
+ pfd[npfd].fd = 0;
+ pfd[npfd].events = POLLIN | (want_x ? POLLPRI : 0);
+ npfd++;
+ }
+ if (want_w)
+ {
+ pfd[npfd].fd = 1;
+ pfd[npfd].events = POLLOUT;
+ npfd++;
+ }
- case IO_READ:
- if (amtread >= 0)
- io_read_reply (qr->reply_port, qr->reply_type, 0,
- buf, amtread);
- else
- io_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0);
- break;
- }
+ n = poll (pfd, npfd, timeout_ms);
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ continue;
+ }
- free (qr);
-}
+ if (pfd[0].revents & POLLIN)
+ {
+ char c[128];
+ read (select_pipe[0], c, sizeof c);
+ }
-/* Unlock READLOCK, and also service any new read requests that it was
- blocking. */
-static void
-unlock_readlock (void)
-{
- pthread_spin_unlock (&readlock);
- while (should_read)
- read_reply ();
+ stdin_ready = 0, stdout_ready = 0, urg_ready = 0;
+ for (i = 1; i < npfd; i++)
+ {
+ if ((pfd[i].revents & (POLLIN | POLLHUP | POLLERR))
+ && (pfd[i].events & POLLIN))
+ stdin_ready = 1;
+ if ((pfd[i].revents & POLLOUT) && (pfd[i].events & POLLOUT))
+ stdout_ready = 1;
+ if ((pfd[i].revents & POLLPRI) && (pfd[i].events & POLLPRI))
+ urg_ready = 1;
+ }
+ if (atomic_load_explicit (&stdin_eof, memory_order_relaxed))
+ stdin_ready = 1;
+
+ clock_gettime (CLOCK_MONOTONIC, &now);
+
+ pthread_mutex_lock (&selq_lock);
+ for (psq = &selq_head; (sq = *psq); )
+ {
+ int result = 0, expired = 0;
+
+ if (sq->is_timeout
+ && (sq->deadline.tv_sec < now.tv_sec
+ || (sq->deadline.tv_sec == now.tv_sec
+ && sq->deadline.tv_nsec <= now.tv_nsec)))
+ expired = 1;
+
+ if (! expired)
+ {
+ if (stdin_ready && (sq->type & SELECT_READ))
+ result |= SELECT_READ;
+ if (stdout_ready && (sq->type & SELECT_WRITE))
+ result |= SELECT_WRITE;
+ if (urg_ready && (sq->type & SELECT_URG))
+ result |= SELECT_URG;
+ }
+
+ if (result || expired)
+ {
+ *psq = sq->next;
+ if (selq_tail == sq)
+ selq_tail = NULL; /* recompute below if needed */
+ sq->type = result;
+ *pdone = sq;
+ pdone = &sq->next;
+ sq->next = NULL;
+ }
+ else
+ psq = &sq->next;
+ }
+ /* Fix up tail after removals. */
+ if (! selq_head)
+ selq_tail = NULL;
+ else
+ {
+ for (sq = selq_head; sq->next; sq = sq->next)
+ ;
+ selq_tail = sq;
+ }
+ pthread_mutex_unlock (&selq_lock);
+
+ while ((sq = done))
+ {
+ done = sq->next;
+ if (sq->is_timeout)
+ io_select_timeout_reply (sq->reply_port, sq->reply_type, 0,
+ sq->type);
+ else
+ io_select_reply (sq->reply_port, sq->reply_type, 0, sq->type);
+ free (sq);
+ }
+ }
}
@@ -1372,11 +1367,6 @@ ds_device_open (mach_port_t master_port,
if (!strcmp (name, "console"))
{
-#if 0
- mach_port_insert_right (mach_task_self (), pseudo_console,
- pseudo_console, MACH_MSG_TYPE_MAKE_SEND);
- console_send_rights++;
-#endif
console_mscount++;
*device = pseudo_console;
*devicetype = MACH_MSG_TYPE_MAKE_SEND;
@@ -1430,7 +1430,7 @@ ds_device_open_new (mach_port_t master_port,
kern_return_t
ds_device_close (device_t device)
{
- if (device != pseudo_console && device != pseudo_root)
+ if (device != pseudo_console && device != pseudo_root && device !=
pseudo_time)
return D_NO_SUCH_DEVICE;
return 0;
}
@@ -1447,24 +1448,25 @@ ds_device_write (device_t device,
{
if (device == pseudo_console)
{
-#if 0
- if (console_send_rights)
+ *bytes_written = write (1, data, datalen);
+ if (*bytes_written == -1)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
+ if (verbose)
+ fprintf (stderr, "console write: %s\r\n", strerror (errno));
+ return D_IO_ERROR;
}
-#endif
- *bytes_written = write (1, data, datalen);
-
- return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ return D_SUCCESS;
}
else if (device == pseudo_root)
{
size_t wrote;
if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
- return D_IO_ERROR;
+ {
+ if (verbose)
+ fprintf (stderr, "store_write: %s\r\n", strerror (errno));
+ return D_IO_ERROR;
+ }
*bytes_written = wrote;
return D_SUCCESS;
}
@@ -1485,24 +1486,25 @@ ds_device_write_inband (device_t device,
{
if (device == pseudo_console)
{
-#if 0
- if (console_send_rights)
+ *bytes_written = write (1, data, datalen);
+ if (*bytes_written == -1)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
+ if (verbose)
+ fprintf (stderr, "console write: %s\r\n", strerror (errno));
+ return D_IO_ERROR;
}
-#endif
-
- *bytes_written = write (1, data, datalen);
- return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ return D_SUCCESS;
}
else if (device == pseudo_root)
{
size_t wrote;
if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
- return D_IO_ERROR;
+ {
+ if (verbose)
+ fprintf (stderr, "store_write: %s\r\n", strerror (errno));
+ return D_IO_ERROR;
+ }
*bytes_written = wrote;
return D_SUCCESS;
}
@@ -1522,42 +1532,52 @@ ds_device_read (device_t device,
mach_msg_type_number_t *datalen)
{
error_t err;
+
+ /* Zero-length requests get an immediate empty answer. */
+ if (bytes_wanted == 0)
+ {
+ *data = 0;
+ *datalen = 0;
+ return D_SUCCESS;
+ }
+
if (device == pseudo_console)
{
int avail;
-#if 0
- if (console_send_rights)
- {
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
-#endif
+ if (bytes_wanted < 0)
+ return D_INVALID_SIZE;
+ if (bytes_wanted > CONSOLE_READ_MAX)
+ bytes_wanted = CONSOLE_READ_MAX;
pthread_spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
+ if (ioctl (0, FIONREAD, &avail) < 0)
+ {
+ pthread_spin_unlock (&readlock);
+ return errno;
+ }
if (avail)
{
void *new_data = mmap (0, bytes_wanted, PROT_READ|PROT_WRITE,
MAP_ANON, 0, 0);
if (new_data == MAP_FAILED)
{
- unlock_readlock ();
+ pthread_spin_unlock (&readlock);
return errno;
}
*data = new_data;
*datalen = read (0, *data, bytes_wanted);
- unlock_readlock ();
+ if (*datalen == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+ pthread_spin_unlock (&readlock);
return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
}
else
{
- unlock_readlock ();
- err = queue_read (DEV_READ, reply_port, reply_type, bytes_wanted);
- if (err)
- return err;
- return MIG_NO_REPLY;
+ pthread_spin_unlock (&readlock);
+ err = queue_read (DEV_READ, reply_port, reply_type,
+ (vm_size_t) bytes_wanted);
+ return err == D_SUCCESS ? MIG_NO_REPLY : err;
}
}
else if (device == pseudo_root)
@@ -1575,7 +1579,11 @@ ds_device_read (device_t device,
size_t data_size = 0;
err = store_read (root_store, recnum, bytes_wanted, (void **)data,
&data_size);
if (err)
- return D_IO_ERROR;
+ {
+ if (verbose)
+ fprintf (stderr, "store_read: %s\r\n", strerror (err));
+ return D_IO_ERROR;
+ }
*datalen = data_size;
return D_SUCCESS;
}
@@ -1597,36 +1602,41 @@ ds_device_read_inband (device_t device,
io_buf_ptr_inband_t data,
mach_msg_type_number_t *datalen)
{
+ /* The buffer is a fixed MIG in-band array; bound the request. */
+ if (bytes_wanted < 0 || bytes_wanted > IO_INBAND_MAX)
+ return D_INVALID_SIZE;
+ if (bytes_wanted == 0)
+ {
+ *datalen = 0;
+ return D_SUCCESS;
+ }
+
if (device == pseudo_console)
{
int avail;
-#if 0
- if (console_send_rights)
+ pthread_spin_lock (&readlock);
+ if (ioctl (0, FIONREAD, &avail) < 0)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
+ pthread_spin_unlock (&readlock);
+ return errno;
}
-#endif
-
- pthread_spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
if (avail)
{
*datalen = read (0, data, bytes_wanted);
- unlock_readlock ();
+ if (*datalen == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
+ pthread_spin_unlock (&readlock);
return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
}
else
{
kern_return_t err;
- unlock_readlock ();
- err = queue_read (DEV_READI, reply_port, reply_type, bytes_wanted);
- if (err)
- return err;
- return MIG_NO_REPLY;
+ pthread_spin_unlock (&readlock);
+ err = queue_read (DEV_READI, reply_port, reply_type,
+ (vm_size_t) bytes_wanted);
+ return err == D_SUCCESS ? MIG_NO_REPLY : err;
}
}
else if (device == pseudo_root)
@@ -1680,7 +1686,13 @@ ds_device_map (device_t device,
return D_IO_ERROR;
err = io_map (node, pager, &wr_memobj);
- if (!err && MACH_PORT_VALID (wr_memobj))
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), node);
+ *pager = MACH_PORT_NULL;
+ return D_IO_ERROR;
+ }
+ if (MACH_PORT_VALID (wr_memobj))
mach_port_deallocate (mach_task_self (), wr_memobj);
mach_port_deallocate (mach_task_self (), node);
@@ -1721,6 +1724,9 @@ ds_device_get_status (device_t device,
case DEV_GET_SIZE:
if (*statuslen < DEV_GET_SIZE_COUNT)
return D_INVALID_SIZE;
+ if (root_store->size > UINT32_MAX
+ || root_store->block_size > UINT32_MAX)
+ return D_INVALID_SIZE;
status[DEV_GET_SIZE_DEVICE_SIZE] = root_store->size;
status[DEV_GET_SIZE_RECORD_SIZE] = root_store->block_size;
*statuslen = DEV_GET_SIZE_COUNT;
@@ -1732,6 +1735,9 @@ ds_device_get_status (device_t device,
case DEV_GET_RECORDS:
if (*statuslen < DEV_GET_RECORDS_COUNT)
return D_INVALID_SIZE;
+ if (root_store->blocks > UINT32_MAX
+ || root_store->block_size > UINT32_MAX)
+ return D_INVALID_SIZE;
status[DEV_GET_RECORDS_DEVICE_RECORDS] = root_store->blocks;
status[DEV_GET_RECORDS_RECORD_SIZE] = root_store->block_size;
*statuslen = DEV_GET_RECORDS_COUNT;
@@ -1802,7 +1801,6 @@ kern_return_t
do_mach_notify_no_senders (mach_port_t notify,
mach_port_mscount_t mscount)
{
- ssize_t err;
static int no_console;
mach_port_t foo;
if (notify == pseudo_master_device_port)
@@ -1818,8 +1817,7 @@ do_mach_notify_no_senders (mach_port_t notify,
{
bye:
restore_termstate ();
- err = write (2, "bye\n", 4);
- assert_backtrace (err == 4);
+ write_diag ("bye\n", 4);
host_exit (0);
}
else
@@ -1835,6 +1836,7 @@ do_mach_notify_no_senders (mach_port_t notify,
if (foo != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), foo);
}
+ return 0;
}
return EOPNOTSUPP;
@@ -1853,10 +1849,6 @@ kern_return_t
do_mach_notify_dead_name (mach_port_t notify,
mach_port_t name)
{
-#if 0
- if (name == child_task && notify == bootport)
- host_exit (0);
-#endif
if (notify != dead_task_notification_port)
return EOPNOTSUPP;
task_died (name);
@@ -1876,15 +1867,6 @@ S_io_write (mach_port_t object,
if (object != pseudo_console)
return EOPNOTSUPP;
-#if 0
- if (console_send_rights)
- {
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
-#endif
-
*amtwritten = write (1, data, datalen);
return *amtwritten == -1 ? errno : 0;
}
@@ -1894,17 +1897,20 @@ S_io_read (mach_port_t object,
if (object != pseudo_console)
return EOPNOTSUPP;
-#if 0
- if (console_send_rights)
+ if (amount > CONSOLE_READ_MAX)
+ amount = CONSOLE_READ_MAX;
+ if (amount == 0)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
+ *datalen = 0;
+ return 0;
}
-#endif
pthread_spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
+ if (ioctl (0, FIONREAD, &avail) < 0)
+ {
+ pthread_spin_unlock (&readlock);
+ return errno;
+ }
if (avail)
{
data_t orig_data = *data;
@@ -1917,26 +1917,26 @@ S_io_read (mach_port_t object,
MAP_ANON, 0, 0);
if (new_data == MAP_FAILED)
{
- unlock_readlock();
+ pthread_spin_unlock (&readlock);
return errno;
}
*data = new_data;
}
*datalen = read (0, *data, amount);
+ if (*datalen == 0)
+ atomic_store_explicit (&stdin_eof, 1, memory_order_relaxed);
if (*datalen == -1 && *data != orig_data)
munmap (*data, amount);
- unlock_readlock ();
+ pthread_spin_unlock (&readlock);
return *datalen == -1 ? errno : 0;
}
else
{
kern_return_t err;
- unlock_readlock ();
+ pthread_spin_unlock (&readlock);
err = queue_read (IO_READ, reply_port, reply_type, amount);
- if (err)
- return err;
- return MIG_NO_REPLY;
+ return err == D_SUCCESS ? MIG_NO_REPLY : err;
}
}
--
2.43.0