kernel/fd: deselect_select_infos must be called with io_mutex held.

When the select/deselect API consumers invoke deselect(), they
expect that when this function returns, no further references to
the select_infos will remain and they can be safely deleted.

In order for that to be true, we cannot remove the select_infos from
the list in one step and deselect them in another; we must do both
without releasing the lock in the middle.

Should hopefully fix a rare KDL seen while testing .NET and
the new event_queue.
This commit is contained in:
Augustin Cavalier 2023-08-03 17:04:55 -04:00
parent 904e9f5512
commit 363e0cdf69

View File

@ -374,11 +374,11 @@ remove_fd(struct io_context* context, int fd)
disconnected = (descriptor->open_mode & O_DISCONNECTED);
}
mutex_unlock(&context->io_mutex);
if (selectInfos != NULL)
deselect_select_infos(descriptor, selectInfos, true);
mutex_unlock(&context->io_mutex);
return disconnected ? NULL : descriptor;
}
@ -446,13 +446,12 @@ dup2_fd(int oldfd, int newfd, bool kernel)
// Check for identity, note that it cannot be made above
// because we always want to return an error on invalid
// handles
select_info* selectInfos = NULL;
if (oldfd != newfd) {
// Now do the work
TFD(Dup2FD(context, oldfd, newfd));
evicted = context->fds[newfd];
selectInfos = context->select_infos[newfd];
select_info* selectInfos = context->select_infos[newfd];
context->select_infos[newfd] = NULL;
atomic_add(&context->fds[oldfd]->ref_count, 1);
atomic_add(&context->fds[oldfd]->open_count, 1);
@ -460,6 +459,8 @@ dup2_fd(int oldfd, int newfd, bool kernel)
if (evicted == NULL)
context->num_used_fds++;
deselect_select_infos(evicted, selectInfos, true);
}
fd_set_close_on_exec(context, newfd, false);
@ -468,7 +469,6 @@ dup2_fd(int oldfd, int newfd, bool kernel)
// Say bye bye to the evicted fd
if (evicted) {
deselect_select_infos(evicted, selectInfos, true);
close_fd(context, evicted);
put_fd(evicted);
}