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:
parent
e9488bd9e6
commit
9981c81f8b
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user