21 |
|
|
22 |
#include <stddef.h> |
#include <stddef.h> |
23 |
#include <errno.h> |
#include <errno.h> |
|
#include <fcntl.h> |
|
24 |
#include <unistd.h> |
#include <unistd.h> |
25 |
#include <wchar.h> |
#include <wchar.h> |
26 |
#include <iconv.h> |
#include <iconv.h> |
29 |
#include <assert.h> |
#include <assert.h> |
30 |
#include <error.h> |
#include <error.h> |
31 |
|
|
|
#include <sys/io.h> |
|
|
#include <sys/fcntl.h> |
|
|
#include <sys/mman.h> |
|
32 |
#include <cthreads.h> |
#include <cthreads.h> |
33 |
|
|
34 |
#include <hurd.h> |
#include <hurd.h> |
35 |
#include <hurd/pager.h> |
#include <hurd/ports.h> |
36 |
#include <hurd/console.h> |
#include <hurd/console.h> |
37 |
|
|
38 |
#ifndef __STDC_ISO_10646__ |
#ifndef __STDC_ISO_10646__ |
40 |
#endif |
#endif |
41 |
|
|
42 |
#include "display.h" |
#include "display.h" |
43 |
|
#include "pager.h" |
44 |
|
|
45 |
|
|
46 |
struct changes |
struct changes |
138 |
}; |
}; |
139 |
typedef struct attr *attr_t; |
typedef struct attr *attr_t; |
140 |
|
|
|
struct user_pager_info |
|
|
{ |
|
|
size_t memobj_npages; |
|
|
vm_address_t memobj_pages[0]; |
|
|
}; |
|
|
|
|
141 |
/* Pending directory and file modification requests. */ |
/* Pending directory and file modification requests. */ |
142 |
struct modreq |
struct modreq |
143 |
{ |
{ |
184 |
|
|
185 |
struct cons_display *user; |
struct cons_display *user; |
186 |
|
|
187 |
struct pager *pager; |
/* The pager for the USER member. */ |
188 |
memory_object_t memobj; |
struct user_pager user_pager; |
189 |
|
|
190 |
/* A list of ports to send file change notifications to. */ |
/* A list of ports to send file change notifications to. */ |
191 |
struct modreq *filemod_reqs; |
struct modreq *filemod_reqs; |
196 |
}; |
}; |
197 |
|
|
198 |
|
|
|
/* We need a separate bucket for the pager ports. */ |
|
|
struct port_bucket *pager_bucket; |
|
|
|
|
|
mach_port_t |
|
|
display_get_filemap (display_t display, vm_prot_t prot) |
|
|
{ |
|
|
error_t err; |
|
|
|
|
|
/* Add a reference for each call, the caller will deallocate it. */ |
|
|
err = mach_port_mod_refs (mach_task_self (), display->memobj, |
|
|
MACH_PORT_RIGHT_SEND, +1); |
|
|
assert_perror (err); |
|
|
|
|
|
return display->memobj; |
|
|
} |
|
|
|
|
|
/* Implement the pager_clear_user_data callback from the pager library. */ |
|
|
void |
|
|
pager_clear_user_data (struct user_pager_info *upi) |
|
|
{ |
|
|
int idx; |
|
|
|
|
|
for (idx = 0; idx < upi->memobj_npages; idx++) |
|
|
if (upi->memobj_pages[idx]) |
|
|
vm_deallocate (mach_task_self (), upi->memobj_pages[idx], vm_page_size); |
|
|
free (upi); |
|
|
} |
|
|
|
|
|
error_t |
|
|
pager_read_page (struct user_pager_info *upi, vm_offset_t page, |
|
|
vm_address_t *buf, int *writelock) |
|
|
{ |
|
|
/* XXX clients should get a read only object. */ |
|
|
*writelock = 0; |
|
|
|
|
|
if (upi->memobj_pages[page / vm_page_size] != (vm_address_t) NULL) |
|
|
{ |
|
|
*buf = upi->memobj_pages[page / vm_page_size]; |
|
|
upi->memobj_pages[page / vm_page_size] = (vm_address_t) NULL; |
|
|
} |
|
|
else |
|
|
*buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, |
|
|
MAP_ANON, 0, 0); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
error_t |
|
|
pager_write_page (struct user_pager_info *upi, vm_offset_t page, |
|
|
vm_address_t buf) |
|
|
{ |
|
|
assert (upi->memobj_pages[page / vm_page_size] == (vm_address_t) NULL); |
|
|
upi->memobj_pages[page / vm_page_size] = buf; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
error_t |
|
|
pager_unlock_page (struct user_pager_info *pager, |
|
|
vm_offset_t address) |
|
|
{ |
|
|
assert (!"unlocking requested on unlocked page"); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/* Tell how big the file is. */ |
|
|
error_t |
|
|
pager_report_extent (struct user_pager_info *upi, |
|
|
vm_address_t *offset, |
|
|
vm_size_t *size) |
|
|
{ |
|
|
*offset = 0; |
|
|
*size = upi->memobj_npages * vm_page_size; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void |
|
|
pager_dropweak (struct user_pager_info *upi) |
|
|
{ |
|
|
} |
|
|
|
|
|
/* A top-level function for the paging thread that just services paging |
|
|
requests. */ |
|
|
static void |
|
|
service_paging_requests (any_t arg) |
|
|
{ |
|
|
struct port_bucket *pager_bucket = arg; |
|
|
for (;;) |
|
|
ports_manage_port_operations_multithread (pager_bucket, |
|
|
pager_demuxer, |
|
|
1000 * 60 * 2, |
|
|
1000 * 60 * 10, 0); |
|
|
} |
|
|
|
|
|
|
|
199 |
/* The bucket and class for notification messages. */ |
/* The bucket and class for notification messages. */ |
200 |
static struct port_bucket *notify_bucket; |
static struct port_bucket *notify_bucket; |
201 |
static struct port_class *notify_class; |
static struct port_class *notify_class; |
772 |
} |
} |
773 |
} |
} |
774 |
|
|
775 |
|
|
776 |
static error_t |
static error_t |
777 |
user_create (display_t display, uint32_t width, uint32_t height, |
user_create (display_t display, uint32_t width, uint32_t height, |
778 |
uint32_t lines, wchar_t chr, conchar_attr_t attr) |
uint32_t lines, wchar_t chr, conchar_attr_t attr) |
779 |
{ |
{ |
780 |
error_t err; |
error_t err; |
781 |
struct cons_display *user; |
struct cons_display *user; |
782 |
struct user_pager_info *upi; |
int npages = (round_page (sizeof (struct cons_display) + sizeof (conchar_t) |
783 |
|
* width * lines)) / vm_page_size; |
|
int npages = (round_page (sizeof (struct cons_display) + |
|
|
sizeof (conchar_t) * width * lines)) / vm_page_size; |
|
|
|
|
|
upi = calloc (1, sizeof (struct user_pager_info) |
|
|
+ sizeof (vm_address_t) * npages); |
|
|
if (!upi) |
|
|
return MACH_PORT_NULL; |
|
|
upi->memobj_npages = npages; |
|
|
/* 1 & MOCD correct? */ |
|
|
display->pager = pager_create (upi, pager_bucket, |
|
|
1, MEMORY_OBJECT_COPY_DELAY); |
|
|
if (display->pager == 0) |
|
|
{ |
|
|
free (upi); |
|
|
return errno; |
|
|
} |
|
|
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) npages * vm_page_size, |
|
|
(vm_address_t) 0, |
|
|
1 /* ! (flags & MAP_FIXED) */, |
|
|
display->memobj, 0 /* (vm_offset_t) offset */, |
|
|
0 /* ! (flags & MAP_SHARED) */, |
|
|
VM_PROT_READ | VM_PROT_WRITE, |
|
|
VM_PROT_READ | VM_PROT_WRITE, |
|
|
VM_INHERIT_NONE); |
|
784 |
|
|
785 |
|
err = user_pager_create (&display->user_pager, npages, &display->user); |
786 |
if (err) |
if (err) |
787 |
{ |
return err; |
788 |
/* UPI will be cleaned up by libpager. */ |
|
789 |
mach_port_deallocate (mach_task_self (), display->memobj); |
user = display->user; |
|
return err; |
|
|
} |
|
|
|
|
790 |
user->magic = CONS_MAGIC; |
user->magic = CONS_MAGIC; |
791 |
user->version = CONS_VERSION_MAJ << 16 | CONS_VERSION_AGE; |
user->version = CONS_VERSION_MAJ << 16 | CONS_VERSION_AGE; |
792 |
user->changes.buffer = offsetof (struct cons_display, changes._buffer) |
user->changes.buffer = offsetof (struct cons_display, changes._buffer) |
803 |
user->cursor.status = CONS_CURSOR_NORMAL; |
user->cursor.status = CONS_CURSOR_NORMAL; |
804 |
conchar_memset (user->_matrix, chr, attr, |
conchar_memset (user->_matrix, chr, attr, |
805 |
user->screen.width * user->screen.lines); |
user->screen.width * user->screen.lines); |
|
|
|
|
display->user = user; |
|
806 |
return 0; |
return 0; |
807 |
} |
} |
808 |
|
|
809 |
static void |
static void |
810 |
user_destroy (display_t display) |
user_destroy (display_t display) |
811 |
{ |
{ |
812 |
/* The pager will be deallocated by libpager. */ |
user_pager_destroy (&display->user_pager, display->user); |
|
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); |
|
813 |
} |
} |
814 |
|
|
815 |
|
|
1782 |
void |
void |
1783 |
display_init (void) |
display_init (void) |
1784 |
{ |
{ |
1785 |
/* Create the pager bucket, and start to serve paging requests. */ |
user_pager_init (); |
|
pager_bucket = ports_create_bucket (); |
|
|
if (! pager_bucket) |
|
|
error (5, errno, "Cannot create pager bucket"); |
|
|
|
|
|
/* Make a thread to service paging requests. */ |
|
|
cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests, |
|
|
(any_t) pager_bucket)); |
|
1786 |
|
|
1787 |
/* Create the notify bucket, and start to serve notifications. */ |
/* Create the notify bucket, and start to serve notifications. */ |
1788 |
notify_bucket = ports_create_bucket (); |
notify_bucket = ports_create_bucket (); |
2103 |
display->output.size = 0; |
display->output.size = 0; |
2104 |
mutex_unlock (&display->lock); |
mutex_unlock (&display->lock); |
2105 |
} |
} |
2106 |
|
|
2107 |
|
|
2108 |
|
mach_port_t |
2109 |
|
display_get_filemap (display_t display, vm_prot_t prot) |
2110 |
|
{ |
2111 |
|
mach_port_t memobj; |
2112 |
|
mutex_lock (&display->lock); |
2113 |
|
memobj = user_pager_get_filemap (&display->user_pager, prot); |
2114 |
|
mutex_unlock (&display->lock); |
2115 |
|
return memobj; |
2116 |
|
} |