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

View File

@ -505,13 +505,9 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
return notify_select_events(info, info->selected_events);
}
// add the info to the IO context
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);
// We need the FD to stay open while we're doing this, so no select()/
// deselect() will be called on it after it is closed.
atomic_add(&descriptor->open_count, 1);
locker.Unlock();
@ -527,9 +523,37 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
}
info->selected_events = selectedEvents;
// if nothing has been selected, we deselect immediately
if (selectedEvents == 0)
deselect_fd(fd, info, kernel);
// If any event has been selected, add the info to the IO context.
if (selectedEvents != 0) {
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;
}