2 * Copyright © 2016 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 #include <dix-config.h>
28 #include <X11/Xproto.h>
30 #include "os/xserver_poll.h"
32 #include "misc.h" /* for typedef of pointer */
36 #if !HAVE_OSPOLL && defined(HAVE_POLLSET_CREATE)
37 #include <sys/pollset.h>
42 #if !HAVE_OSPOLL && defined(HAVE_PORT_CREATE)
49 #if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1)
50 #include <sys/epoll.h>
56 #include "xserver_poll.h"
63 // pollset-based implementation (as seen on AIX)
68 enum ospoll_trigger trigger
;
69 void (*callback
)(int fd
, int xevents
, void *data
);
84 /* epoll-based implementation */
88 enum ospoll_trigger trigger
;
89 void (*callback
)(int fd
, int xevents
, void *data
);
91 struct xorg_list deleted
;
96 struct ospollfd
**fds
;
99 struct xorg_list deleted
;
106 /* poll-based implementation */
109 enum ospoll_trigger trigger
;
110 void (*callback
)(int fd
, int revents
, void *data
);
116 struct ospollfd
*osfds
;
124 /* Binary search for the specified file descriptor
126 * Returns position if found
127 * Returns -position - 1 if not found
131 ospoll_find(struct ospoll
*ospoll
, int fd
)
134 int hi
= ospoll
->num
- 1;
137 int m
= (lo
+ hi
) >> 1;
139 int t
= ospoll
->fds
[m
]->fd
;
142 int t
= ospoll
->fds
[m
].fd
;
157 ospoll_clean_deleted(struct ospoll
*ospoll
)
159 struct ospollfd
*osfd
, *tmp
;
161 xorg_list_for_each_entry_safe(osfd
, tmp
, &ospoll
->deleted
, deleted
) {
162 xorg_list_del(&osfd
->deleted
);
168 /* Insert an element into an array
170 * base: base address of array
171 * num: number of elements in the array before the insert
172 * size: size of each element
173 * pos: position to insert at
176 array_insert(void *base
, size_t num
, size_t size
, size_t pos
)
180 memmove(b
+ (pos
+1) * size
,
185 /* Delete an element from an array
187 * base: base address of array
188 * num: number of elements in the array before the delete
189 * size: size of each element
190 * pos: position to delete from
193 array_delete(void *base
, size_t num
, size_t size
, size_t pos
)
197 memmove(b
+ pos
* size
, b
+ (pos
+ 1) * size
,
198 (num
- pos
- 1) * size
);
206 struct ospoll
*ospoll
= calloc(1, sizeof (struct ospoll
));
208 ospoll
->ps
= pollset_create(-1);
209 if (ospoll
->ps
< 0) {
216 struct ospoll
*ospoll
= calloc(1, sizeof (struct ospoll
));
218 ospoll
->epoll_fd
= port_create();
219 if (ospoll
->epoll_fd
< 0) {
223 xorg_list_init(&ospoll
->deleted
);
227 struct ospoll
*ospoll
= calloc(1, sizeof (struct ospoll
));
229 ospoll
->epoll_fd
= epoll_create1(EPOLL_CLOEXEC
);
230 if (ospoll
->epoll_fd
< 0) {
234 xorg_list_init(&ospoll
->deleted
);
238 return calloc(1, sizeof (struct ospoll
));
243 ospoll_destroy(struct ospoll
*ospoll
)
247 assert (ospoll
->num
== 0);
248 pollset_destroy(ospoll
->ps
);
255 assert (ospoll
->num
== 0);
256 close(ospoll
->epoll_fd
);
257 ospoll_clean_deleted(ospoll
);
264 assert (ospoll
->num
== 0);
266 free (ospoll
->osfds
);
273 ospoll_add(struct ospoll
*ospoll
, int fd
,
274 enum ospoll_trigger trigger
,
275 void (*callback
)(int fd
, int xevents
, void *data
),
278 int pos
= ospoll_find(ospoll
, fd
);
281 if (ospoll
->num
== ospoll
->size
) {
282 struct ospollfd
*new_fds
;
283 int new_size
= ospoll
->size
? ospoll
->size
* 2 : MAXCLIENTS
* 2;
285 new_fds
= reallocarray(ospoll
->fds
, new_size
, sizeof (ospoll
->fds
[0]));
288 ospoll
->fds
= new_fds
;
289 ospoll
->size
= new_size
;
292 array_insert(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
295 ospoll
->fds
[pos
].fd
= fd
;
296 ospoll
->fds
[pos
].xevents
= 0;
297 ospoll
->fds
[pos
].revents
= 0;
299 ospoll
->fds
[pos
].trigger
= trigger
;
300 ospoll
->fds
[pos
].callback
= callback
;
301 ospoll
->fds
[pos
].data
= data
;
304 struct ospollfd
*osfd
;
307 osfd
= calloc(1, sizeof (struct ospollfd
));
311 if (ospoll
->num
>= ospoll
->size
) {
312 struct ospollfd
**new_fds
;
313 int new_size
= ospoll
->size
? ospoll
->size
* 2 : MAXCLIENTS
* 2;
315 new_fds
= reallocarray(ospoll
->fds
, new_size
, sizeof (ospoll
->fds
[0]));
320 ospoll
->fds
= new_fds
;
321 ospoll
->size
= new_size
;
328 array_insert(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
329 ospoll
->fds
[pos
] = osfd
;
332 osfd
= ospoll
->fds
[pos
];
335 osfd
->callback
= callback
;
336 osfd
->trigger
= trigger
;
339 struct ospollfd
*osfd
;
343 struct epoll_event ev
;
345 osfd
= calloc(1, sizeof (struct ospollfd
));
349 if (ospoll
->num
>= ospoll
->size
) {
350 struct ospollfd
**new_fds
;
351 int new_size
= ospoll
->size
? ospoll
->size
* 2 : MAXCLIENTS
* 2;
353 new_fds
= reallocarray(ospoll
->fds
, new_size
, sizeof (ospoll
->fds
[0]));
358 ospoll
->fds
= new_fds
;
359 ospoll
->size
= new_size
;
364 if (trigger
== ospoll_trigger_edge
)
365 ev
.events
|= EPOLLET
;
366 if (epoll_ctl(ospoll
->epoll_fd
, EPOLL_CTL_ADD
, fd
, &ev
) == -1) {
374 array_insert(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
375 ospoll
->fds
[pos
] = osfd
;
378 osfd
= ospoll
->fds
[pos
];
381 osfd
->callback
= callback
;
382 osfd
->trigger
= trigger
;
386 if (ospoll
->num
== ospoll
->size
) {
387 struct pollfd
*new_fds
;
388 struct ospollfd
*new_osfds
;
389 int new_size
= ospoll
->size
? ospoll
->size
* 2 : MAXCLIENTS
* 2;
391 new_fds
= reallocarray(ospoll
->fds
, new_size
, sizeof (ospoll
->fds
[0]));
394 ospoll
->fds
= new_fds
;
395 new_osfds
= reallocarray(ospoll
->osfds
, new_size
, sizeof (ospoll
->osfds
[0]));
398 ospoll
->osfds
= new_osfds
;
399 ospoll
->size
= new_size
;
402 array_insert(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
403 array_insert(ospoll
->osfds
, ospoll
->num
, sizeof (ospoll
->osfds
[0]), pos
);
405 ospoll
->changed
= TRUE
;
407 ospoll
->fds
[pos
].fd
= fd
;
408 ospoll
->fds
[pos
].events
= 0;
409 ospoll
->fds
[pos
].revents
= 0;
410 ospoll
->osfds
[pos
].revents
= 0;
412 ospoll
->osfds
[pos
].trigger
= trigger
;
413 ospoll
->osfds
[pos
].callback
= callback
;
414 ospoll
->osfds
[pos
].data
= data
;
420 ospoll_remove(struct ospoll
*ospoll
, int fd
)
422 int pos
= ospoll_find(ospoll
, fd
);
424 pos
= ospoll_find(ospoll
, fd
);
427 struct ospollfd
*osfd
= &ospoll
->fds
[pos
];
428 struct poll_ctl ctl
= { .cmd
= PS_DELETE
, .fd
= fd
};
429 pollset_ctl(ospoll
->ps
, &ctl
, 1);
431 array_delete(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
435 struct ospollfd
*osfd
= ospoll
->fds
[pos
];
436 port_dissociate(ospoll
->epoll_fd
, PORT_SOURCE_FD
, fd
);
438 array_delete(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
440 osfd
->callback
= NULL
;
442 xorg_list_add(&osfd
->deleted
, &ospoll
->deleted
);
445 struct ospollfd
*osfd
= ospoll
->fds
[pos
];
446 struct epoll_event ev
;
449 (void) epoll_ctl(ospoll
->epoll_fd
, EPOLL_CTL_DEL
, fd
, &ev
);
451 array_delete(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
453 osfd
->callback
= NULL
;
455 xorg_list_add(&osfd
->deleted
, &ospoll
->deleted
);
458 array_delete(ospoll
->fds
, ospoll
->num
, sizeof (ospoll
->fds
[0]), pos
);
459 array_delete(ospoll
->osfds
, ospoll
->num
, sizeof (ospoll
->osfds
[0]), pos
);
461 ospoll
->changed
= TRUE
;
468 epoll_mod(struct ospoll
*ospoll
, struct ospollfd
*osfd
)
471 if (osfd
->xevents
& X_NOTIFY_READ
)
473 if (osfd
->xevents
& X_NOTIFY_WRITE
)
475 port_associate(ospoll
->epoll_fd
, PORT_SOURCE_FD
, osfd
->fd
, events
, osfd
);
481 epoll_mod(struct ospoll
*ospoll
, struct ospollfd
*osfd
)
483 struct epoll_event ev
;
485 if (osfd
->xevents
& X_NOTIFY_READ
)
486 ev
.events
|= EPOLLIN
;
487 if (osfd
->xevents
& X_NOTIFY_WRITE
)
488 ev
.events
|= EPOLLOUT
;
489 if (osfd
->trigger
== ospoll_trigger_edge
)
490 ev
.events
|= EPOLLET
;
492 (void) epoll_ctl(ospoll
->epoll_fd
, EPOLL_CTL_MOD
, osfd
->fd
, &ev
);
497 ospoll_listen(struct ospoll
*ospoll
, int fd
, int xevents
)
499 int pos
= ospoll_find(ospoll
, fd
);
503 struct poll_ctl ctl
= { .cmd
= PS_MOD
, .fd
= fd
};
504 if (xevents
& X_NOTIFY_READ
) {
505 ctl
.events
|= POLLIN
;
506 ospoll
->fds
[pos
].revents
&= ~POLLIN
;
508 if (xevents
& X_NOTIFY_WRITE
) {
509 ctl
.events
|= POLLOUT
;
510 ospoll
->fds
[pos
].revents
&= ~POLLOUT
;
512 pollset_ctl(ospoll
->ps
, &ctl
, 1);
513 ospoll
->fds
[pos
].xevents
|= xevents
;
516 struct ospollfd
*osfd
= ospoll
->fds
[pos
];
517 osfd
->xevents
|= xevents
;
518 epoll_mod(ospoll
, osfd
);
521 if (xevents
& X_NOTIFY_READ
) {
522 ospoll
->fds
[pos
].events
|= POLLIN
;
523 ospoll
->osfds
[pos
].revents
&= ~POLLIN
;
525 if (xevents
& X_NOTIFY_WRITE
) {
526 ospoll
->fds
[pos
].events
|= POLLOUT
;
527 ospoll
->osfds
[pos
].revents
&= ~POLLOUT
;
534 ospoll_mute(struct ospoll
*ospoll
, int fd
, int xevents
)
536 int pos
= ospoll_find(ospoll
, fd
);
540 struct ospollfd
*osfd
= &ospoll
->fds
[pos
];
541 osfd
->xevents
&= ~xevents
;
542 struct poll_ctl ctl
= { .cmd
= PS_DELETE
, .fd
= fd
};
543 pollset_ctl(ospoll
->ps
, &ctl
, 1);
546 if (osfd
->xevents
& X_NOTIFY_READ
) {
547 ctl
.events
|= POLLIN
;
549 if (osfd
->xevents
& X_NOTIFY_WRITE
) {
550 ctl
.events
|= POLLOUT
;
552 pollset_ctl(ospoll
->ps
, &ctl
, 1);
556 struct ospollfd
*osfd
= ospoll
->fds
[pos
];
557 osfd
->xevents
&= ~xevents
;
558 epoll_mod(ospoll
, osfd
);
561 if (xevents
& X_NOTIFY_READ
)
562 ospoll
->fds
[pos
].events
&= ~POLLIN
;
563 if (xevents
& X_NOTIFY_WRITE
)
564 ospoll
->fds
[pos
].events
&= ~POLLOUT
;
571 ospoll_wait(struct ospoll
*ospoll
, int timeout
)
575 #define MAX_EVENTS 256
576 struct pollfd events
[MAX_EVENTS
];
578 nready
= pollset_poll(ospoll
->ps
, events
, MAX_EVENTS
, timeout
);
579 for (int i
= 0; i
< nready
; i
++) {
580 struct pollfd
*ev
= &events
[i
];
581 int pos
= ospoll_find(ospoll
, ev
->fd
);
582 struct ospollfd
*osfd
= &ospoll
->fds
[pos
];
583 short revents
= ev
->revents
;
584 short oldevents
= osfd
->revents
;
586 osfd
->revents
= (revents
& (POLLIN
|POLLOUT
));
587 if (osfd
->trigger
== ospoll_trigger_edge
)
588 revents
&= ~oldevents
;
591 if (revents
& POLLIN
)
592 xevents
|= X_NOTIFY_READ
;
593 if (revents
& POLLOUT
)
594 xevents
|= X_NOTIFY_WRITE
;
595 if (revents
& (~(POLLIN
|POLLOUT
)))
596 xevents
|= X_NOTIFY_ERROR
;
597 osfd
->callback(osfd
->fd
, xevents
, osfd
->data
);
602 #define MAX_EVENTS 256
603 port_event_t events
[MAX_EVENTS
];
605 timespec_t port_timeout
= {
606 .tv_sec
= timeout
/ 1000,
607 .tv_nsec
= (timeout
% 1000) * 1000000
611 if (port_getn(ospoll
->epoll_fd
, events
, MAX_EVENTS
, &nget
, &port_timeout
)
615 for (int i
= 0; i
< nready
; i
++) {
616 port_event_t
*ev
= &events
[i
];
617 struct ospollfd
*osfd
= ev
->portev_user
;
618 uint32_t revents
= ev
->portev_events
;
621 if (revents
& POLLIN
)
622 xevents
|= X_NOTIFY_READ
;
623 if (revents
& POLLOUT
)
624 xevents
|= X_NOTIFY_WRITE
;
625 if (revents
& (~(POLLIN
|POLLOUT
)))
626 xevents
|= X_NOTIFY_ERROR
;
629 osfd
->callback(osfd
->fd
, xevents
, osfd
->data
);
631 if (osfd
->trigger
== ospoll_trigger_level
&&
632 !xorg_list_is_empty(&osfd
->deleted
)) {
633 epoll_mod(ospoll
, osfd
);
636 ospoll_clean_deleted(ospoll
);
639 #define MAX_EVENTS 256
640 struct epoll_event events
[MAX_EVENTS
];
643 nready
= epoll_wait(ospoll
->epoll_fd
, events
, MAX_EVENTS
, timeout
);
644 for (i
= 0; i
< nready
; i
++) {
645 struct epoll_event
*ev
= &events
[i
];
646 struct ospollfd
*osfd
= ev
->data
.ptr
;
647 uint32_t revents
= ev
->events
;
650 if (revents
& EPOLLIN
)
651 xevents
|= X_NOTIFY_READ
;
652 if (revents
& EPOLLOUT
)
653 xevents
|= X_NOTIFY_WRITE
;
654 if (revents
& (~(EPOLLIN
|EPOLLOUT
)))
655 xevents
|= X_NOTIFY_ERROR
;
658 osfd
->callback(osfd
->fd
, xevents
, osfd
->data
);
660 ospoll_clean_deleted(ospoll
);
663 nready
= xserver_poll(ospoll
->fds
, ospoll
->num
, timeout
);
664 ospoll
->changed
= FALSE
;
667 for (f
= 0; f
< ospoll
->num
; f
++) {
668 short revents
= ospoll
->fds
[f
].revents
;
669 short oldevents
= ospoll
->osfds
[f
].revents
;
671 ospoll
->osfds
[f
].revents
= (revents
& (POLLIN
|POLLOUT
));
672 if (ospoll
->osfds
[f
].trigger
== ospoll_trigger_edge
)
673 revents
&= ~oldevents
;
676 if (revents
& POLLIN
)
677 xevents
|= X_NOTIFY_READ
;
678 if (revents
& POLLOUT
)
679 xevents
|= X_NOTIFY_WRITE
;
680 if (revents
& (~(POLLIN
|POLLOUT
)))
681 xevents
|= X_NOTIFY_ERROR
;
682 ospoll
->osfds
[f
].callback(ospoll
->fds
[f
].fd
, xevents
,
683 ospoll
->osfds
[f
].data
);
685 /* Check to see if the arrays have changed, and just go back
698 ospoll_reset_events(struct ospoll
*ospoll
, int fd
)
701 int pos
= ospoll_find(ospoll
, fd
);
706 ospoll
->fds
[pos
].revents
= 0;
709 int pos
= ospoll_find(ospoll
, fd
);
714 epoll_mod(ospoll
, ospoll
->fds
[pos
]);
717 int pos
= ospoll_find(ospoll
, fd
);
722 ospoll
->osfds
[pos
].revents
= 0;
727 ospoll_data(struct ospoll
*ospoll
, int fd
)
729 int pos
= ospoll_find(ospoll
, fd
);
734 return ospoll
->fds
[pos
].data
;
737 return ospoll
->fds
[pos
]->data
;
740 return ospoll
->osfds
[pos
].data
;