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:
@@ -374,11 +374,11 @@ remove_fd(struct io_context* context, int fd)
|
|||||||
disconnected = (descriptor->open_mode & O_DISCONNECTED);
|
disconnected = (descriptor->open_mode & O_DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&context->io_mutex);
|
|
||||||
|
|
||||||
if (selectInfos != NULL)
|
if (selectInfos != NULL)
|
||||||
deselect_select_infos(descriptor, selectInfos, true);
|
deselect_select_infos(descriptor, selectInfos, true);
|
||||||
|
|
||||||
|
mutex_unlock(&context->io_mutex);
|
||||||
|
|
||||||
return disconnected ? NULL : descriptor;
|
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
|
// Check for identity, note that it cannot be made above
|
||||||
// because we always want to return an error on invalid
|
// because we always want to return an error on invalid
|
||||||
// handles
|
// handles
|
||||||
select_info* selectInfos = NULL;
|
|
||||||
if (oldfd != newfd) {
|
if (oldfd != newfd) {
|
||||||
// Now do the work
|
// Now do the work
|
||||||
TFD(Dup2FD(context, oldfd, newfd));
|
TFD(Dup2FD(context, oldfd, newfd));
|
||||||
|
|
||||||
evicted = context->fds[newfd];
|
evicted = context->fds[newfd];
|
||||||
selectInfos = context->select_infos[newfd];
|
select_info* selectInfos = context->select_infos[newfd];
|
||||||
context->select_infos[newfd] = NULL;
|
context->select_infos[newfd] = NULL;
|
||||||
atomic_add(&context->fds[oldfd]->ref_count, 1);
|
atomic_add(&context->fds[oldfd]->ref_count, 1);
|
||||||
atomic_add(&context->fds[oldfd]->open_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)
|
if (evicted == NULL)
|
||||||
context->num_used_fds++;
|
context->num_used_fds++;
|
||||||
|
|
||||||
|
deselect_select_infos(evicted, selectInfos, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_set_close_on_exec(context, newfd, false);
|
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
|
// Say bye bye to the evicted fd
|
||||||
if (evicted) {
|
if (evicted) {
|
||||||
deselect_select_infos(evicted, selectInfos, true);
|
|
||||||
close_fd(context, evicted);
|
close_fd(context, evicted);
|
||||||
put_fd(evicted);
|
put_fd(evicted);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user