Commit 1c834fdf authored by Manuel Stoeckl's avatar Manuel Stoeckl
Browse files

Add deletion framework for file descriptors

When shadow_fd structs _that are owned by known protocol objects_
have their reference count drop to zero, they are deleted.

Newly created shadow_fd's begin with a reference count of 1,
which is reduced when the translated fd to sent to the
display/application/other waypipe socket end. This ensures
that the object is not deleted early, even if the compositor
e.g. wl_display.delete_id's the fd owning object before receiving
it.
parent fc9fecef
......@@ -141,6 +141,7 @@ static int run_client_child(int chanfd, const char *socket_path)
if (waylen > 0) {
ssize_t wc = iovec_write(dispfd, waymsg, waylen,
fds, nids);
decref_transferred_fds(&fdtransmap, nids, fds);
free(tmpbuf);
if (wc == -1) {
wp_log(WP_ERROR,
......@@ -199,6 +200,7 @@ static int run_client_child(int chanfd, const char *socket_path)
size_t msglen;
pack_pipe_message(&msglen, &msg, nfds, ids, ntransfers,
transfers);
decref_transferred_rids(&fdtransmap, nfds, ids);
wp_log(WP_DEBUG,
"Packed message size (%d fds, %d blobs): %ld\n",
nfds, ntransfers, msglen);
......
......@@ -87,6 +87,15 @@ static void event_wl_display_delete_id(
if (obj) {
listset_remove(&context->mt->objects, obj);
// object specific cleanup goes here
if (obj->owned_buffer) {
/* We only dereference now, because the object is not
* truly deleted (and its linked buffers inaccessible)
* until the compositor says so. (Technically, for
* waypipe server (application-side), we could drop the
* refcount at a given object's "destroy".) */
shadow_decref(context->map, obj->owned_buffer);
obj->owned_buffer = NULL;
}
free(obj);
}
}
......@@ -166,8 +175,6 @@ static void request_wl_buffer_destroy(
{
struct context *context = get_context(client, resource);
// User requests surface destruction
// TODO: free backing store?
(void)context;
}
void request_wl_surface_attach(struct wl_client *client,
......@@ -188,11 +195,7 @@ void request_wl_surface_attach(struct wl_client *client,
return;
}
if (context->obj->owned_buffer) {
context->obj->owned_buffer->refcount--;
if (context->obj->owned_buffer->refcount == 0) {
wp_log(WP_ERROR,
"TODO: unhandled shadow refcount zero\n");
}
shadow_decref(context->map, context->obj->owned_buffer);
}
context->obj->owned_buffer = bufobj->owned_buffer;
context->obj->owned_buffer->refcount++;
......@@ -219,7 +222,6 @@ static void request_wl_surface_destroy(
struct wl_client *client, struct wl_resource *resource)
{
struct context *context = get_context(client, resource);
// User requests surface destruction
(void)context;
}
static void request_wl_surface_damage(struct wl_client *client,
......
......@@ -124,6 +124,7 @@ static int run_server_child(int chanfd, int appfd)
if (waymsg) {
ssize_t wc = iovec_write(appfd, waymsg, waylen,
fds, nids);
decref_transferred_fds(&fdtransmap, nids, fds);
free(tmpbuf);
if (wc == -1) {
wp_log(WP_ERROR,
......@@ -185,6 +186,7 @@ static int run_server_child(int chanfd, int appfd)
size_t msglen;
pack_pipe_message(&msglen, &msg, nfds, ids, ntransfers,
transfers);
decref_transferred_rids(&fdtransmap, nfds, ids);
wp_log(WP_DEBUG,
"Packed message size (%d fds, %d blobs): %ld\n",
nfds, ntransfers, msglen);
......
......@@ -204,33 +204,36 @@ ssize_t iovec_write(int conn, const char *buf, size_t buflen, const int *fds,
return ret;
}
static void destroy_unlinked_sfd(struct shadow_fd *shadow)
{
close(shadow->fd_local);
if (shadow->type == FDC_FILE) {
munmap(shadow->file_mem_local, shadow->file_size);
free(shadow->file_mem_mirror);
free(shadow->file_diff_buffer);
if (shadow->file_shm_buf_name[0]) {
shm_unlink(shadow->file_shm_buf_name);
}
} else if (fdcat_ispipe(shadow->type)) {
close(shadow->pipe_fd);
if (shadow->pipe_fd != shadow->fd_local) {
close(shadow->fd_local);
}
free(shadow->pipe_recv.data);
free(shadow->pipe_send.data);
}
free(shadow);
}
void cleanup_translation_map(struct fd_translation_map *map)
{
struct shadow_fd *cur = map->list;
map->list = NULL;
while (cur) {
struct shadow_fd *shadow = cur;
close(shadow->fd_local);
if (shadow->type == FDC_FILE) {
munmap(shadow->file_mem_local, shadow->file_size);
free(shadow->file_mem_mirror);
free(shadow->file_diff_buffer);
if (shadow->file_shm_buf_name[0]) {
shm_unlink(shadow->file_shm_buf_name);
}
} else if (fdcat_ispipe(shadow->type)) {
close(shadow->pipe_fd);
if (shadow->pipe_fd != shadow->fd_local) {
close(shadow->fd_local);
}
free(shadow->pipe_recv.data);
free(shadow->pipe_send.data);
}
cur = shadow->next;
shadow->next = NULL;
free(shadow);
destroy_unlinked_sfd(shadow);
}
}
static int translate_fd(struct fd_translation_map *map, int fd)
......@@ -256,6 +259,9 @@ static int translate_fd(struct fd_translation_map *map, int fd)
// File changes must be propagated
shadow->is_dirty = true;
shadow->has_owner = false;
/* Start object reference at one; will be decremented once RID is sent
*/
shadow->refcount = 1;
wp_log(WP_DEBUG, "Creating new shadow buffer for local fd %d\n", fd);
......@@ -334,6 +340,15 @@ struct shadow_fd *get_shadow_for_local_fd(
}
return NULL;
}
struct shadow_fd *get_shadow_for_rid(struct fd_translation_map *map, int rid)
{
for (struct shadow_fd *cur = map->list; cur; cur = cur->next) {
if (cur->remote_id == rid) {
return cur;
}
}
return NULL;
}
/** Construct a very simple binary diff format, designed to be fast for small
* changes in big files, and entire-file changes in essentially random files.
......@@ -719,6 +734,10 @@ static void apply_update(
shadow->fd_local = -1;
shadow->type = transf->type;
shadow->is_dirty = false;
/* Start the object reference at one, so that, if it is owned by
* some known protocol object, it can not be deleted until the fd
* has at least be transferred over the Wayland connection */
shadow->refcount = 1;
if (shadow->type == FDC_FILE) {
shadow->file_mem_local = NULL;
shadow->file_size = transf->size;
......@@ -856,6 +875,43 @@ void wait_on_children(struct kstack **children, int options)
}
}
}
bool shadow_decref(struct fd_translation_map *map, struct shadow_fd *sfd)
{
sfd->refcount--;
if (sfd->refcount == 0 && sfd->has_owner) {
for (struct shadow_fd *cur = map->list, *prev = NULL; cur;
prev = cur, cur = cur->next) {
if (cur == sfd) {
if (!prev) {
map->list = cur->next;
} else {
prev->next = cur->next;
}
break;
}
}
destroy_unlinked_sfd(sfd);
return true;
}
return false;
}
void decref_transferred_fds(struct fd_translation_map *map, int nfds, int fds[])
{
for (int i = 0; i < nfds; i++) {
struct shadow_fd *sfd = get_shadow_for_local_fd(map, fds[i]);
shadow_decref(map, sfd);
}
}
void decref_transferred_rids(
struct fd_translation_map *map, int nids, int ids[])
{
for (int i = 0; i < nids; i++) {
struct shadow_fd *sfd = get_shadow_for_rid(map, ids[i]);
shadow_decref(map, sfd);
}
}
int count_npipes(const struct fd_translation_map *map)
{
......@@ -1029,6 +1085,11 @@ void parse_and_prune_messages(struct message_tracker *mt,
from_client, &data[pos], *data_len - pos,
&consumed_bytes, &fds[fdpos], *fds_len - fdpos,
&consumed_fds, &effect_unknown);
if (consumed_bytes == 0) {
wp_log(WP_ERROR,
"Message consumed zero bytes, probable parsing error\n");
return;
}
if (consumed_fds > 0 && !keep) {
wp_log(WP_ERROR,
"Dropping a message with send fds -- unimplemented\n");
......
......@@ -177,8 +177,20 @@ void close_local_pipe_ends(struct fd_translation_map *map);
/** If a pipe is remotely closed, but not locally closed, then close it too */
void close_rclosed_pipes(struct fd_translation_map *map);
/** Get the shadow structure matching lfd, if one exists, else NULL */
struct shadow_fd *get_shadow_for_local_fd(
struct fd_translation_map *map, int lfd);
struct shadow_fd *get_shadow_for_rid(struct fd_translation_map *map, int rid);
/** Reduce the reference count for a surface which is owned. The surface
* should not be used by the caller after this point. Returns true if pointer
* deleted. */
bool shadow_decref(struct fd_translation_map *map, struct shadow_fd *);
/** Decrease reference count for all objects in the given list, deleting
* iff they are owned by protocol objects and have refcount zero */
void decref_transferred_fds(
struct fd_translation_map *map, int nfds, int fds[]);
void decref_transferred_rids(
struct fd_translation_map *map, int nids, int ids[]);
struct kstack {
struct kstack *nxt;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment