kqueue: Implement EV_RECEIPT.
Tested with a modified FreeBSD test. Also fix EVFILT_READ + EVFILT_WRITE failing to select only returning one error, and not two as it's supposed to.
This commit is contained in:
@@ -91,6 +91,7 @@ struct kevent {
|
|||||||
/* flags */
|
/* flags */
|
||||||
#define EV_ONESHOT 0x0010 /* only report one occurrence */
|
#define EV_ONESHOT 0x0010 /* only report one occurrence */
|
||||||
#define EV_CLEAR 0x0020 /* clear event state after reporting */
|
#define EV_CLEAR 0x0020 /* clear event state after reporting */
|
||||||
|
#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
|
||||||
|
|
||||||
/* returned values */
|
/* returned values */
|
||||||
#define EV_EOF 0x8000 /* EOF detected */
|
#define EV_EOF 0x8000 /* EOF detected */
|
||||||
|
|||||||
+51
-6
@@ -48,9 +48,11 @@ kevent(int kq,
|
|||||||
const struct timespec *tspec)
|
const struct timespec *tspec)
|
||||||
{
|
{
|
||||||
BStackOrHeapArray<event_wait_info, 16> waitInfos(max_c(nchanges, nevents));
|
BStackOrHeapArray<event_wait_info, 16> waitInfos(max_c(nchanges, nevents));
|
||||||
|
BStackOrHeapArray<int32, 16> requestedEvents(nchanges);
|
||||||
|
|
||||||
event_wait_info* waitInfo = waitInfos;
|
event_wait_info* waitInfo = waitInfos;
|
||||||
int changedInfos = 0;
|
int32* requestedEvent = requestedEvents;
|
||||||
|
int changedInfos = 0, receiptCount = 0;
|
||||||
|
|
||||||
for (int i = 0; i < nchanges; i++) {
|
for (int i = 0; i < nchanges; i++) {
|
||||||
waitInfo->object = changelist[i].ident;
|
waitInfo->object = changelist[i].ident;
|
||||||
@@ -147,30 +149,72 @@ kevent(int kq,
|
|||||||
if (waitInfo->events != 0)
|
if (waitInfo->events != 0)
|
||||||
waitInfo->events |= behavior;
|
waitInfo->events |= behavior;
|
||||||
|
|
||||||
|
*requestedEvent = waitInfo->events;
|
||||||
|
|
||||||
|
if ((changelist[i].flags & EV_RECEIPT) != 0) {
|
||||||
|
receiptCount++;
|
||||||
|
|
||||||
|
// Use sign bit to indicate EV_RECEIPT.
|
||||||
|
*requestedEvent |= (1 << 31);
|
||||||
|
}
|
||||||
|
|
||||||
changedInfos++;
|
changedInfos++;
|
||||||
waitInfo++;
|
waitInfo++;
|
||||||
|
requestedEvent++;
|
||||||
|
|
||||||
|
if (receiptCount >= nevents)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (changedInfos != 0) {
|
if (changedInfos != 0) {
|
||||||
status_t status = _kern_event_queue_select(kq, waitInfos, changedInfos);
|
status_t status = _kern_event_queue_select(kq, waitInfos, changedInfos);
|
||||||
if (status != B_OK) {
|
if (status != B_OK && nchanges == 1 && nevents == 0) {
|
||||||
if (nchanges == 1 && nevents == 0) {
|
|
||||||
// Special case: return the lone error directly.
|
// Special case: return the lone error directly.
|
||||||
__set_errno(waitInfos[0].events);
|
__set_errno(waitInfos[0].events);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report problems as error events.
|
// Report problems (or successes, if EV_RECEIPT is set) as error events.
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
for (int i = 0; i < changedInfos; i++) {
|
for (int i = 0; i < changedInfos; i++) {
|
||||||
if (waitInfos[i].events > 0)
|
int64_t data = waitInfos[i].events;
|
||||||
|
if (data > 0) {
|
||||||
|
if (requestedEvents[i] > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Always generate an "error" event for EV_RECEIPT.
|
||||||
|
data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (nevents == 0) {
|
if (nevents == 0) {
|
||||||
errors = -1;
|
errors = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
short filter = filter_from_info(waitInfos[i]);
|
short filter = filter_from_info(waitInfos[i]);
|
||||||
int64_t data = waitInfos[i].events;
|
if ((requestedEvents[i] & (B_EVENT_READ | B_EVENT_WRITE))
|
||||||
|
== (B_EVENT_READ | B_EVENT_WRITE)) {
|
||||||
|
// We need to generate two errors for this case.
|
||||||
|
filter = EVFILT_READ;
|
||||||
|
int64_t readData = data;
|
||||||
|
if (data == 0 && (waitInfos[i].events & B_EVENT_READ) == 0)
|
||||||
|
readData = -1;
|
||||||
|
|
||||||
|
EV_SET(eventlist, waitInfos[i].object,
|
||||||
|
filter, EV_ERROR, 0, readData, waitInfos[i].user_data);
|
||||||
|
eventlist++;
|
||||||
|
nevents--;
|
||||||
|
errors++;
|
||||||
|
|
||||||
|
filter = EVFILT_WRITE;
|
||||||
|
if (data == 0 && (waitInfos[i].events & B_EVENT_WRITE) == 0)
|
||||||
|
data = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nevents == 0) {
|
||||||
|
errors = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
EV_SET(eventlist, waitInfos[i].object,
|
EV_SET(eventlist, waitInfos[i].object,
|
||||||
filter, EV_ERROR, 0, data, waitInfos[i].user_data);
|
filter, EV_ERROR, 0, data, waitInfos[i].user_data);
|
||||||
eventlist++;
|
eventlist++;
|
||||||
@@ -180,6 +224,7 @@ kevent(int kq,
|
|||||||
|
|
||||||
if (errors > 0)
|
if (errors > 0)
|
||||||
return errors;
|
return errors;
|
||||||
|
if (status != B_OK) {
|
||||||
__set_errno(status);
|
__set_errno(status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user