Fixed a race condition between select_fd() and close(). Since

select_fd() first added the select info to the IO context and then
called select() on the descriptor, a close() called at the same time
could already deselect the events and close the descriptor before
select_fd() was done with select(). select_fd() does now keep an own
open reference while selecting the events and add the select info
afterwards to the IO context (if the FD is still current).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25266 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-04-29 23:54:35 +00:00
parent e9488bd9e6
commit 9981c81f8b
+34 -10
View File
@@ -505,13 +505,9 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
return notify_select_events(info, info->selected_events); return notify_select_events(info, info->selected_events);
} }
// add the info to the IO context // We need the FD to stay open while we're doing this, so no select()/
info->next = context->select_infos[fd]; // deselect() will be called on it after it is closed.
context->select_infos[fd] = info; atomic_add(&descriptor->open_count, 1);
// as long as the info is in the list, we keep a reference to the sync
// object
atomic_add(&info->sync->ref_count, 1);
locker.Unlock(); locker.Unlock();
@@ -527,9 +523,37 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
} }
info->selected_events = selectedEvents; info->selected_events = selectedEvents;
// if nothing has been selected, we deselect immediately // If any event has been selected, add the info to the IO context.
if (selectedEvents == 0) if (selectedEvents != 0) {
deselect_fd(fd, info, kernel); locker.Lock();
if (context->fds[fd] != descriptor) {
// Someone close()d the index in the meantime. deselect() all
// events.
info->next = NULL;
deselect_select_infos(descriptor, info);
// Release our open reference of the descriptor.
close_fd(descriptor);
return B_FILE_ERROR;
}
// The FD index hasn't changed, so we add the select info to the table.
info->next = context->select_infos[fd];
context->select_infos[fd] = info;
// As long as the info is in the list, we keep a reference to the sync
// object.
atomic_add(&info->sync->ref_count, 1);
// Finally release our open reference. It is safe just to decrement,
// since as long as the descriptor is associated with the slot,
// someone else still has it open.
atomic_add(&descriptor->open_count, -1);
} else {
// Release our open reference.
close_fd(descriptor);
}
return B_OK; return B_OK;
} }