summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--console/ChangeLog25
-rw-r--r--console/console.c27
-rw-r--r--console/display.c160
3 files changed, 187 insertions, 25 deletions
diff --git a/console/ChangeLog b/console/ChangeLog
index 865f8cfd..a538f6c4 100644
--- a/console/ChangeLog
+++ b/console/ChangeLog
@@ -1,3 +1,28 @@
+2002-09-22 Marcus Brinkmann <marcus@gnu.org>
+
+ * console.c: Include <mach.h>.
+ (netfs_S_dir_notice_changes): New variable PREQ. Clean out the
+ dead wood, eh, dead name notifications from the CONS->dirmod_req
+ list.
+ * display.c (struct user_pager_info): Drop members DISPLAY and P.
+ (struct display): Remove member UPI and add member PAGER.
+ (pager_report_extent): Remove local variable DISPLAY, use UPI
+ directly.
+ (user_create): New variable UPI to hold the user pager info.
+ Modify the code to match new struct organization.
+ (user_destroy): Unmap the user data.
+ (display_notice_changes): Request dead-name notifications.
+ (free_modreqs): Cancel dead-name notification request before
+ deallocation send right.
+ (display_notice_filechange): Likewise.
+ (do_mach_notify_msg_accepted): Likewise.
+ (display_destroy): Take DISPLAY->lock while operating. Reset the
+ filemod_reqs and filemod_reqs_pending members of DISPLAY to NULL.
+ (do_mach_notify_port_deleted): Add comment.
+ (do_mach_notify_dead_name): Implement.
+ (do_mach_notify_no_senders): Implement by delegating to libports.
+ (do_mach_notify_send_once): Don't fail.
+
2002-09-18 Marcus Brinkmann <marcus@gnu.org>
* hurd.ti: Enable <kb2> and <kmouse>, fix the comments.
diff --git a/console/console.c b/console/console.c
index 48567e1f..2969f8f8 100644
--- a/console/console.c
+++ b/console/console.c
@@ -35,6 +35,7 @@
#include <version.h>
+#include <mach.h>
#include <hurd/netfs.h>
#include <hurd/ioctl_types.h>
/* We include console.h for the color numbers. */
@@ -1239,6 +1240,7 @@ netfs_S_dir_notice_changes (struct protid *cred, mach_port_t notify)
{
error_t err;
cons_t cons;
+ struct modreq **preq;
struct modreq *req;
if (!cred)
@@ -1249,6 +1251,31 @@ netfs_S_dir_notice_changes (struct protid *cred, mach_port_t notify)
return EOPNOTSUPP;
mutex_lock (&cons->lock);
+ /* We have to prevent that we accumulate dead-names in the
+ notification list. They are cleaned up in cons_notice_dirchange,
+ but that is not called often enough, so we also clean them up
+ here. This way, the maximum of dead-names will never exceed the
+ prior maximum of active clients. The better way would be to
+ request dead-name notifications, XXX. */
+ preq = &cons->dirmod_reqs;
+
+ while (*preq)
+ {
+ mach_port_type_t type;
+ req = *preq;
+
+ err = mach_port_type (mach_task_self (), req->port, &type);
+ if (!err && type == MACH_PORT_TYPE_DEAD_NAME)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ else
+ preq = &req->next;
+ }
+
err = dir_changed (notify, cons->dirmod_tick, DIR_CHANGED_NULL, "");
if (err)
{
diff --git a/console/display.c b/console/display.c
index fd257fe7..8d75976c 100644
--- a/console/display.c
+++ b/console/display.c
@@ -143,8 +143,6 @@ typedef struct attr *attr_t;
struct user_pager_info
{
- display_t display;
- struct pager *p;
size_t memobj_npages;
vm_address_t memobj_pages[0];
};
@@ -195,7 +193,7 @@ struct display
struct cons_display *user;
- struct user_pager_info *upi;
+ struct pager *pager;
memory_object_t memobj;
/* A list of ports to send file change notifications to. */
@@ -276,9 +274,8 @@ pager_report_extent (struct user_pager_info *upi,
vm_address_t *offset,
vm_size_t *size)
{
- display_t display = upi->display;
*offset = 0;
- *size = display->upi->memobj_npages * vm_page_size;
+ *size = upi->memobj_npages * vm_page_size;
return 0;
}
@@ -405,22 +402,87 @@ free_modreqs (struct modreq *mr)
struct modreq *tmp;
for (; mr; mr = tmp)
{
+ mach_port_t old;
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), mr->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ mach_port_deallocate (mach_task_self (), old);
+
+ /* Deallocate the user's port. */
mach_port_deallocate (mach_task_self (), mr->port);
tmp = mr->next;
free (mr);
}
}
-void do_mach_notify_port_deleted (void) { assert (0); }
+/* A port deleted notification is generated when we deallocate the
+ user's notify port before it is dead. */
+error_t
+do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
+{
+ /* As we cancel the dead-name notification before deallocating the
+ port, this should not happen. */
+ assert (0);
+}
+
+/* We request dead name notifications for the user ports. */
+error_t
+do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_name)
+{
+ struct notify *notify_port = ports_lookup_port (notify_bucket,
+ notify, notify_class);
+ struct display *display;
+ struct modreq **preq;
+ struct modreq *req;
+
+ if (!notify_port)
+ return EOPNOTSUPP;
+
+ display = notify_port->display;
+ mutex_lock (&display->lock);
+
+ /* Find request in pending queue. */
+ preq = &display->filemod_reqs_pending;
+ while (*preq && (*preq)->port != dead_name)
+ preq = &(*preq)->next;
+ if (! *preq)
+ {
+ /* Find request in queue. */
+ preq = &display->filemod_reqs;
+ while (*preq && (*preq)->port != dead_name)
+ preq = &(*preq)->next;
+ }
+
+ if (*preq)
+ {
+ req = *preq;
+ *preq = req->next;
+
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ mutex_unlock (&display->lock);
+
+ /* Drop gratuitous extra reference that the notification creates. */
+ mach_port_deallocate (mach_task_self (), dead_name);
+
+ return 0;
+}
+
void do_mach_notify_port_destroyed (void) { assert (0); }
-void do_mach_notify_no_senders (void) { assert (0); }
-void do_mach_notify_dead_name (void) { assert (0); }
+
+error_t
+do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t count)
+{
+ return ports_do_mach_notify_no_senders (port, count);
+}
kern_return_t
do_mach_notify_send_once (mach_port_t notify)
{
- /* XXX Not sure when this is called. */
- assert (0);
+ return 0;
}
kern_return_t
@@ -473,8 +535,17 @@ do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t send)
notify);
if (err && err != MACH_SEND_WILL_NOTIFY)
{
+ mach_port_t old;
*preq = req->next;
mutex_unlock (&display->lock);
+
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), req->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ mach_port_deallocate (mach_task_self (), old);
+
mach_port_deallocate (mach_task_self (), req->port);
free (req);
ports_port_deref (notify_port);
@@ -516,20 +587,40 @@ display_notice_changes (display_t display, mach_port_t notify)
{
error_t err;
struct modreq *req;
+ mach_port_t notify_port;
+ mach_port_t old;
mutex_lock (&display->lock);
- err = nowait_file_changed (notify, 0, FILE_CHANGED_NULL, 0, 0, MACH_PORT_NULL);
+ err = nowait_file_changed (notify, 0, FILE_CHANGED_NULL, 0, 0,
+ MACH_PORT_NULL);
if (err)
{
mutex_unlock (&display->lock);
return err;
}
+
req = malloc (sizeof (struct modreq));
if (!req)
{
mutex_unlock (&display->lock);
return errno;
}
+
+ notify_port = ports_get_right (display->notify_port);
+
+ /* Request dead-name notification for the user's port. */
+ err = mach_port_request_notification (mach_task_self (), notify,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ if (err)
+ {
+ free (req);
+ mutex_unlock (&display->lock);
+ return err;
+ }
+ assert (old == MACH_PORT_NULL);
+
req->port = notify;
req->pending = 0;
req->next = display->filemod_reqs;
@@ -571,6 +662,13 @@ display_notice_filechange (display_t display)
}
else
{
+ mach_port_t old;
+
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), req->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL, 0, &old);
+ mach_port_deallocate (mach_task_self (), old);
mach_port_deallocate (mach_task_self (), req->port);
free (req);
}
@@ -782,33 +880,33 @@ user_create (display_t display, uint32_t width, uint32_t height,
{
error_t err;
struct cons_display *user;
+ struct user_pager_info *upi;
int npages = (round_page (sizeof (struct cons_display) +
sizeof (conchar_t) * width * lines)) / vm_page_size;
- display->upi = calloc (1, sizeof (struct user_pager_info)
- + sizeof (vm_address_t) * npages);
- if (!display->upi)
+ upi = calloc (1, sizeof (struct user_pager_info)
+ + sizeof (vm_address_t) * npages);
+ if (!upi)
return MACH_PORT_NULL;
- display->upi->display = display;
- display->upi->memobj_npages = npages;
+ upi->memobj_npages = npages;
/* 1 & MOCD correct? */
- display->upi->p = pager_create (display->upi, pager_bucket,
- 1, MEMORY_OBJECT_COPY_DELAY);
- if (display->upi->p == 0)
+ display->pager = pager_create (upi, pager_bucket,
+ 1, MEMORY_OBJECT_COPY_DELAY);
+ if (display->pager == 0)
{
- free (display->upi);
+ free (upi);
return errno;
}
- display->memobj = pager_get_port (display->upi->p);
- ports_port_deref (display->upi->p);
+ display->memobj = pager_get_port (display->pager);
+ ports_port_deref (display->pager);
mach_port_insert_right (mach_task_self (), display->memobj, display->memobj,
MACH_MSG_TYPE_MAKE_SEND);
err = vm_map (mach_task_self (),
(vm_address_t *) &user,
- (vm_size_t) display->upi->memobj_npages * vm_page_size,
+ (vm_size_t) npages * vm_page_size,
(vm_address_t) 0,
1 /* ! (flags & MAP_FIXED) */,
display->memobj, 0 /* (vm_offset_t) offset */,
@@ -816,6 +914,7 @@ user_create (display_t display, uint32_t width, uint32_t height,
VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE,
VM_INHERIT_NONE);
+
if (err)
{
/* UPI will be cleaned up by libpager. */
@@ -848,6 +947,8 @@ static void
user_destroy (display_t display)
{
/* The pager will be deallocated by libpager. */
+ vm_deallocate (mach_task_self (), (vm_offset_t) display->user,
+ pager_get_upi (display->pager)->memobj_npages * vm_page_size);
mach_port_deallocate (mach_task_self (), display->memobj);
}
@@ -1899,13 +2000,22 @@ display_create (display_t *r_display, const char *encoding,
void
display_destroy (display_t display)
{
+ mutex_lock (&display->lock);
if (display->filemod_reqs_pending)
- free_modreqs (display->filemod_reqs_pending);
+ {
+ free_modreqs (display->filemod_reqs_pending);
+ display->filemod_reqs_pending = NULL;
+ }
if (display->filemod_reqs)
- free_modreqs (display->filemod_reqs);
+ {
+ free_modreqs (display->filemod_reqs);
+ display->filemod_reqs = NULL;
+ }
ports_destroy_right (display->notify_port);
output_deinit (&display->output);
user_destroy (display);
+ mutex_unlock (&display->lock);
+
/* We can not free the display structure here, because it might
still be needed by pending modification requests when msg
accepted notifications are handled. So we have to wait until all