2 * "$Id: select.c 6166 2006-12-29 20:35:18Z mike $"
4 * Select abstraction functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2006 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * cupsdAddSelect() - Add a file descriptor to the list.
27 * cupsdDoSelect() - Do a select-like operation.
28 * cupsdIsSelecting() - Determine whether we are monitoring a file
30 * cupsdRemoveSelect() - Remove a file descriptor from the list.
31 * cupsdStartSelect() - Initialize the file polling engine.
32 * cupsdStopSelect() - Shutdown the file polling engine.
33 * compare_fds() - Compare file descriptors.
34 * find_fd() - Find an existing file descriptor record.
38 * Include necessary headers...
44 # include <sys/epoll.h>
45 #elif defined(HAVE_KQUEUE)
46 # include <sys/event.h>
47 # include <sys/time.h>
48 #elif defined(HAVE_POLL)
49 # include <sys/poll.h>
51 # include <sys/time.h>
53 # include <sys/select.h>
54 #endif /* HAVE_EPOLL */
58 * Design Notes for Poll/Select API in CUPSD
59 * -----------------------------------------
63 * OS select poll epoll kqueue /dev/poll
64 * -------------- ------ ------ ------ ------ ---------
65 * AIX YES YES NO NO NO
66 * FreeBSD YES YES NO YES NO
67 * HP-UX YES YES NO NO NO
68 * IRIX YES YES NO NO NO
69 * Linux YES YES YES NO NO
70 * MacOS X YES YES NO YES NO
71 * NetBSD YES YES NO YES NO
72 * OpenBSD YES YES NO YES NO
73 * Solaris YES YES NO NO YES
74 * Tru64 YES YES NO NO NO
75 * Windows YES NO NO NO NO
80 * typedef void (*cupsd_selfunc_t)(void *data);
82 * void cupsdStartSelect(void);
83 * void cupsdStopSelect(void);
84 * void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
85 * cupsd_selfunc_t write_cb, void *data);
86 * void cupsdRemoveSelect(int fd);
87 * int cupsdDoSelect(int timeout);
90 * IMPLEMENTATION STRATEGY
93 * a. CUPS array of file descriptor to callback functions
95 * b. cupsdStartSelect() creates the array
96 * c. cupsdStopSelect() destroys the array and all elements.
97 * d. cupsdAddSelect() adds to the array and allocates a
98 * new callback element.
99 * e. cupsdRemoveSelect() removes from the array and frees
100 * the callback element.
101 * f. _cupsd_fd_t provides a reference-counted structure for
102 * tracking file descriptors that are monitored.
105 * a. Input/Output fd_set variables, copied to working
106 * copies and then used with select().
107 * b. Loop through CUPS array, using FD_ISSET and calling
108 * the read/write callbacks as needed.
109 * c. cupsdRemoveSelect() clears fd_set bit from main and
111 * d. cupsdStopSelect() frees all of the memory used by the
112 * CUPS array and fd_set's.
114 * 2. poll() - O(n log n)
115 * a. Regular array of pollfd, sorted the same as the CUPS
117 * b. Loop through pollfd array, call the corresponding
118 * read/write callbacks as needed.
119 * c. cupsdAddSelect() adds first to CUPS array and flags the
120 * pollfd array as invalid.
121 * d. cupsdDoSelect() rebuilds pollfd array as needed, calls
122 * poll(), then loops through the pollfd array looking up
124 * e. cupsdRemoveSelect() flags the pollfd array as invalid.
125 * f. cupsdStopSelect() frees all of the memory used by the
126 * CUPS array and pollfd array.
129 * a. cupsdStartSelect() creates epoll file descriptor using
130 * epoll_create() with the maximum fd count, and
131 * allocates an events buffer for the maximum fd count.
132 * b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
133 * (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
134 * event using the level-triggered semantics. The event
135 * user data field is a pointer to the new callback array
137 * c. cupsdDoSelect() uses epoll_wait() with the global event
138 * buffer allocated in cupsdStartSelect() and then loops
139 * through the events, using the user data field to find
140 * the callback record.
141 * d. cupsdStopSelect() closes the epoll file descriptor and
142 * frees all of the memory used by the event buffer.
145 * b. cupsdStartSelect() creates kqueue file descriptor
146 * using kqyeue() function and allocates a global event
148 * c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
149 * register the changes. The event user data field is a
150 * pointer to the new callback array element.
151 * d. cupsdDoSelect() uses kevent() to poll for events and
152 * loops through the events, using the user data field to
153 * find the callback record.
154 * e. cupsdStopSelect() closes the kqyeye() file descriptor
155 * and frees all of the memory used by the event buffer.
157 * 5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
158 * a. cupsdStartSelect() opens /dev/poll and allocates an
159 * array of pollfd structs; on failure to open /dev/poll,
160 * revert to poll() system call.
161 * b. cupsdAddSelect() writes a single pollfd struct to
162 * /dev/poll with the new file descriptor and the
163 * POLLIN/POLLOUT flags.
164 * c. cupsdRemoveSelect() writes a single pollfd struct to
165 * /dev/poll with the file descriptor and the POLLREMOVE
167 * d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
168 * events from /dev/poll and then loops through the
169 * returned pollfd array, looking up the file descriptors
171 * e. cupsdStopSelect() closes /dev/poll and frees the
176 * In tests using the "make test" target with option 0 (keep cupsd
177 * running) and the "testspeed" program with "-c 50 -r 1000", epoll()
178 * performed 5.5% slower select(), followed by kqueue() at 16% slower
179 * than select() and poll() at 18% slower than select(). Similar
180 * results were seen with twice the number of client connections.
182 * The epoll() and kqueue() performance is likely limited by the
183 * number of system calls used to add/modify/remove file
184 * descriptors dynamically. Further optimizations may be possible
185 * in the area of limiting use of cupsdAddSelect() and
186 * cupsdRemoveSelect(), however extreme care will be needed to avoid
187 * excess CPU usage and deadlock conditions.
189 * We may be able to improve the poll() implementation simply by
190 * keeping the pollfd array sync'd with the _cupsd_fd_t array, as that
191 * will eliminate the rebuilding of the array whenever there is a
192 * change and eliminate the fd array lookups in the inner loop of
195 * Since /dev/poll will never be able to use a shadow array, it may
196 * not make sense to implement support for it. ioctl() overhead will
197 * impact performance as well, so my guess would be that, for CUPS,
198 * /dev/poll will yield a net performance loss.
202 * Local structures...
205 typedef struct _cupsd_fd_s
207 int fd
, /* File descriptor */
209 cupsd_selfunc_t read_cb
, /* Read callback */
210 write_cb
; /* Write callback */
211 void *data
; /* Data pointer for callbacks */
219 static cups_array_t
*cupsd_fds
= NULL
;
222 static int cupsd_epoll_fd
= -1;
223 static struct epoll_event
*cupsd_epoll_events
= NULL
;
224 #elif defined(HAVE_KQUEUE)
225 static int cupsd_kqueue_fd
= -1,
226 cupsd_kqueue_changes
= 0;
227 static struct kevent
*cupsd_kqueue_events
= NULL
;
228 #elif defined(HAVE_POLL)
229 static int cupsd_alloc_pollfds
= 0,
230 cupsd_update_pollfds
= 0;
231 static struct pollfd
*cupsd_pollfds
= NULL
;
233 static fd_set cupsd_global_input
,
236 cupsd_current_output
;
237 #endif /* HAVE_EPOLL */
244 static int compare_fds(_cupsd_fd_t
*a
, _cupsd_fd_t
*b
);
245 static _cupsd_fd_t
*find_fd(int fd
);
246 #define release_fd(f) { \
248 if (!(f)->use) free((f));\
250 #define retain_fd(f) (f)->use++
254 * 'cupsdAddSelect()' - Add a file descriptor to the list.
257 int /* O - 1 on success, 0 on error */
258 cupsdAddSelect(int fd
, /* I - File descriptor */
259 cupsd_selfunc_t read_cb
, /* I - Read callback */
260 cupsd_selfunc_t write_cb
,/* I - Write callback */
261 void *data
) /* I - Data to pass to callback */
263 _cupsd_fd_t
*fdptr
; /* File descriptor record */
264 int added
; /* 1 if added, 0 if modified */
268 * Range check input...
271 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
272 "cupsdAddSelect: fd=%d, read_cb=%p, write_cb=%p, data=%p",
273 fd
, read_cb
, write_cb
, data
);
279 * See if this FD has already been added...
282 if ((fdptr
= find_fd(fd
)) == NULL
)
285 * No, add a new entry...
288 if ((fdptr
= calloc(1, sizeof(_cupsd_fd_t
))) == NULL
)
294 if (!cupsArrayAdd(cupsd_fds
, fdptr
))
296 cupsdLogMessage(CUPSD_LOG_EMERG
, "Unable to add fd %d to array!", fd
);
308 struct epoll_event event
; /* Event data */
314 event
.events
|= EPOLLIN
;
317 event
.events
|= EPOLLOUT
;
319 event
.data
.ptr
= fdptr
;
321 epoll_ctl(cupsd_epoll_fd
, added
? EPOLL_CTL_ADD
: EPOLL_CTL_MOD
, fd
,
325 #elif defined(HAVE_KQUEUE)
327 struct kevent event
; /* Event data */
328 struct timespec timeout
; /* Timeout value */
334 if (fdptr
->read_cb
!= read_cb
)
337 EV_SET(&event
, fd
, EVFILT_READ
, EV_ADD
, 0, 0, fdptr
);
339 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
341 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
343 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
344 "cupsdAddSelect: kevent() returned %s",
350 if (fdptr
->write_cb
!= write_cb
)
353 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_ADD
, 0, 0, fdptr
);
355 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
357 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
359 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
360 "cupsdAddSelect: kevent() returned %s",
367 #elif defined(HAVE_POLL)
368 cupsd_update_pollfds
= 1;
372 * Add or remove the file descriptor in the input and output sets
378 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
379 "cupsdAddSelect: Adding fd %d to input set...", fd
);
380 FD_SET(fd
, &cupsd_global_input
);
384 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
385 "cupsdAddSelect: Removing fd %d from input set...", fd
);
386 FD_CLR(fd
, &cupsd_global_input
);
387 FD_CLR(fd
, &cupsd_current_input
);
392 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
393 "cupsdAddSelect: Adding fd %d to output set...", fd
);
394 FD_SET(fd
, &cupsd_global_output
);
398 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
399 "cupsdAddSelect: Removing fd %d from output set...", fd
);
400 FD_CLR(fd
, &cupsd_global_output
);
401 FD_CLR(fd
, &cupsd_current_output
);
403 #endif /* HAVE_EPOLL */
406 * Save the (new) read and write callbacks...
409 fdptr
->read_cb
= read_cb
;
410 fdptr
->write_cb
= write_cb
;
418 * 'cupsdDoSelect()' - Do a select-like operation.
421 int /* O - Number of files or -1 on error */
422 cupsdDoSelect(long timeout
) /* I - Timeout in seconds */
424 int nfds
; /* Number of file descriptors */
425 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
427 int i
; /* Looping var */
428 struct epoll_event
*event
; /* Current event */
431 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
432 "cupsdDoSelect: polling %d fds for %ld seconds...",
433 cupsArrayCount(cupsd_fds
), timeout
);
435 if (timeout
>= 0 && timeout
< 86400)
436 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
,
439 nfds
= epoll_wait(cupsd_epoll_fd
, cupsd_epoll_events
, MaxFDs
, -1);
441 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: epoll() returned %d...",
444 for (i
= nfds
, event
= cupsd_epoll_events
; i
> 0; i
--, event
++)
446 fdptr
= (_cupsd_fd_t
*)event
->data
.ptr
;
450 if (fdptr
->read_cb
&& (event
->events
& (EPOLLIN
| EPOLLERR
| EPOLLHUP
)))
452 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
454 (*(fdptr
->read_cb
))(fdptr
->data
);
457 if (fdptr
->write_cb
&& (event
->events
& (EPOLLOUT
| EPOLLERR
| EPOLLHUP
)))
459 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
461 (*(fdptr
->write_cb
))(fdptr
->data
);
467 #elif defined(HAVE_KQUEUE)
468 int i
; /* Looping var */
469 struct kevent
*event
; /* Current event */
470 struct timespec ktimeout
; /* kevent() timeout */
473 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
474 "cupsdDoSelect: polling %d fds for %ld seconds...",
475 cupsArrayCount(cupsd_fds
), timeout
);
477 if (timeout
>= 0 && timeout
< 86400)
479 ktimeout
.tv_sec
= timeout
;
480 ktimeout
.tv_nsec
= 0;
482 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
,
486 nfds
= kevent(cupsd_kqueue_fd
, NULL
, 0, cupsd_kqueue_events
, MaxFDs
, NULL
);
488 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
489 "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...",
490 cupsd_kqueue_fd
, MaxFDs
, nfds
);
492 cupsd_kqueue_changes
= 0;
494 for (i
= nfds
, event
= cupsd_kqueue_events
; i
> 0; i
--, event
++)
496 fdptr
= (_cupsd_fd_t
*)event
->udata
;
498 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "event->filter=%d, event->ident=%d",
499 event
->filter
, (int)event
->ident
);
503 if (fdptr
->read_cb
&& event
->filter
== EVFILT_READ
)
505 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
507 (*(fdptr
->read_cb
))(fdptr
->data
);
510 if (fdptr
->write_cb
&& event
->filter
== EVFILT_WRITE
)
512 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
514 (*(fdptr
->write_cb
))(fdptr
->data
);
520 #elif defined(HAVE_POLL)
521 struct pollfd
*pfd
; /* Current pollfd structure */
522 int count
; /* Number of file descriptors */
525 count
= cupsArrayCount(cupsd_fds
);
527 if (cupsd_update_pollfds
)
530 * Update the cupsd_pollfds array to match the current FD array...
533 cupsd_update_pollfds
= 0;
535 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Updating pollfd array...");
538 * (Re)allocate memory as needed...
541 if (count
> cupsd_alloc_pollfds
)
543 int allocfds
= count
+ 16;
547 pfd
= realloc(cupsd_pollfds
, allocfds
* sizeof(struct pollfd
));
549 pfd
= malloc(allocfds
* sizeof(struct pollfd
));
553 cupsdLogMessage(CUPSD_LOG_EMERG
,
554 "Unable to allocate %d bytes for polling!",
555 (int)(allocfds
* sizeof(struct pollfd
)));
561 cupsd_alloc_pollfds
= allocfds
;
565 * Rebuild the array...
568 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
), pfd
= cupsd_pollfds
;
570 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
), pfd
++)
576 pfd
->events
|= POLLIN
;
579 pfd
->events
|= POLLOUT
;
583 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
584 "cupsdDoSelect: polling %d fds for %ld seconds...",
587 if (timeout
>= 0 && timeout
< 86400)
588 nfds
= poll(cupsd_pollfds
, count
, timeout
* 1000);
590 nfds
= poll(cupsd_pollfds
, count
, -1);
592 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: poll() returned %d...",
598 * Do callbacks for each file descriptor...
601 for (pfd
= cupsd_pollfds
; count
> 0; pfd
++, count
--)
603 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
604 "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
605 pfd
- cupsd_pollfds
, pfd
->fd
, pfd
->revents
);
610 if ((fdptr
= find_fd(pfd
->fd
)) == NULL
)
615 if (fdptr
->read_cb
&& (pfd
->revents
& (POLLIN
| POLLERR
| POLLHUP
)))
617 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
619 (*(fdptr
->read_cb
))(fdptr
->data
);
622 if (fdptr
->write_cb
&& (pfd
->revents
& (POLLOUT
| POLLERR
| POLLHUP
)))
624 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
626 (*(fdptr
->write_cb
))(fdptr
->data
);
634 struct timeval stimeout
; /* Timeout for select() */
635 int maxfd
; /* Maximum file descriptor */
639 * Figure out the highest file descriptor number...
642 if ((fdptr
= (_cupsd_fd_t
*)cupsArrayLast(cupsd_fds
)) == NULL
)
645 maxfd
= fdptr
->fd
+ 1;
651 cupsd_current_input
= cupsd_global_input
;
652 cupsd_current_output
= cupsd_global_output
;
654 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
655 "cupsdDoSelect: selecting %d fds for %ld seconds...",
658 if (timeout
>= 0 && timeout
< 86400)
660 stimeout
.tv_sec
= timeout
;
661 stimeout
.tv_usec
= 0;
663 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
667 nfds
= select(maxfd
, &cupsd_current_input
, &cupsd_current_output
, NULL
,
670 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: select() returned %d...",
676 * Do callbacks for each file descriptor...
679 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
681 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
685 if (fdptr
->read_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_input
))
687 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Read on fd %d...",
689 (*(fdptr
->read_cb
))(fdptr
->data
);
692 if (fdptr
->write_cb
&& FD_ISSET(fdptr
->fd
, &cupsd_current_output
))
694 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdDoSelect: Write on fd %d...",
696 (*(fdptr
->write_cb
))(fdptr
->data
);
703 #endif /* HAVE_EPOLL */
706 * Return the number of file descriptors handled...
714 * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
718 int /* O - 1 if selecting, 0 otherwise */
719 cupsdIsSelecting(int fd
) /* I - File descriptor */
721 return (find_fd(fd
) != NULL
);
726 * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
730 cupsdRemoveSelect(int fd
) /* I - File descriptor */
732 _cupsd_fd_t
*fdptr
; /* File descriptor record */
734 struct epoll_event event
; /* Event data */
735 #elif defined(HAVE_KQUEUE)
736 struct kevent event
; /* Event data */
737 struct timespec timeout
; /* Timeout value */
738 #elif defined(HAVE_POLL)
739 /* No variables for poll() */
740 #endif /* HAVE_EPOLL */
744 * Range check input...
747 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdRemoveSelect: fd=%d", fd
);
753 * Find the file descriptor...
756 if ((fdptr
= find_fd(fd
)) == NULL
)
760 epoll_ctl(cupsd_epoll_fd
, EPOLL_CTL_DEL
, fd
, &event
);
762 #elif defined(HAVE_KQUEUE)
768 EV_SET(&event
, fd
, EVFILT_READ
, EV_DELETE
, 0, 0, fdptr
);
770 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
772 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
773 "cupsdRemoveSelect: kevent() returned %s",
781 EV_SET(&event
, fd
, EVFILT_WRITE
, EV_DELETE
, 0, 0, fdptr
);
783 if (kevent(cupsd_kqueue_fd
, &event
, 1, NULL
, 0, &timeout
))
785 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
786 "cupsdRemoveSelect: kevent() returned %s",
793 #elif defined(HAVE_POLL)
795 * Update the pollfds array...
798 cupsd_update_pollfds
= 1;
801 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
802 "cupsdRemoveSelect: Removing fd %d from input and output "
804 FD_CLR(fd
, &cupsd_global_input
);
805 FD_CLR(fd
, &cupsd_global_output
);
806 FD_CLR(fd
, &cupsd_current_input
);
807 FD_CLR(fd
, &cupsd_current_output
);
808 #endif /* HAVE_EPOLL */
811 * Remove the file descriptor for from the FD array...
814 cupsArrayRemove(cupsd_fds
, fdptr
);
820 * 'cupsdStartSelect()' - Initialize the file polling engine.
824 cupsdStartSelect(void)
826 cupsd_fds
= cupsArrayNew((cups_array_func_t
)compare_fds
, NULL
);
829 cupsd_epoll_fd
= epoll_create(MaxFDs
);
830 cupsd_epoll_events
= calloc(MaxFDs
, sizeof(struct epoll_event
));
832 #elif defined(HAVE_KQUEUE)
833 cupsd_kqueue_fd
= kqueue();
834 cupsd_kqueue_changes
= 0;
835 cupsd_kqueue_events
= calloc(MaxFDs
, sizeof(struct kevent
));
837 #elif defined(HAVE_POLL)
838 cupsd_update_pollfds
= 0;
841 FD_ZERO(&cupsd_global_input
);
842 FD_ZERO(&cupsd_global_output
);
843 #endif /* HAVE_EPOLL */
848 * 'cupsdStopSelect()' - Shutdown the file polling engine.
852 cupsdStopSelect(void)
854 _cupsd_fd_t
*fdptr
; /* Current file descriptor */
857 for (fdptr
= (_cupsd_fd_t
*)cupsArrayFirst(cupsd_fds
);
859 fdptr
= (_cupsd_fd_t
*)cupsArrayNext(cupsd_fds
))
862 cupsArrayDelete(cupsd_fds
);
866 if (cupsd_epoll_events
)
868 free(cupsd_epoll_events
);
869 cupsd_epoll_events
= NULL
;
872 if (cupsd_epoll_fd
>= 0)
874 close(cupsd_epoll_fd
);
878 #elif defined(HAVE_KQUEUE)
879 if (cupsd_kqueue_events
)
881 free(cupsd_kqueue_events
);
882 cupsd_kqueue_events
= NULL
;
885 if (cupsd_kqueue_fd
>= 0)
887 close(cupsd_kqueue_fd
);
888 cupsd_kqueue_fd
= -1;
891 cupsd_kqueue_changes
= 0;
893 #elif defined(HAVE_POLL)
897 cupsd_pollfds
= NULL
;
898 cupsd_alloc_pollfds
= 0;
901 cupsd_update_pollfds
= 0;
904 FD_ZERO(&cupsd_global_input
);
905 FD_ZERO(&cupsd_global_output
);
906 #endif /* HAVE_EPOLL */
911 * 'compare_fds()' - Compare file descriptors.
914 static int /* O - Result of comparison */
915 compare_fds(_cupsd_fd_t
*a
, /* I - First file descriptor */
916 _cupsd_fd_t
*b
) /* I - Second file descriptor */
918 return (a
->fd
- b
->fd
);
923 * 'find_fd()' - Find an existing file descriptor record.
926 static _cupsd_fd_t
* /* O - FD record pointer or NULL */
927 find_fd(int fd
) /* I - File descriptor */
929 _cupsd_fd_t
*fdptr
, /* Matching record (if any) */
930 key
; /* Search key */
933 cupsArraySave(cupsd_fds
);
936 fdptr
= (_cupsd_fd_t
*)cupsArrayFind(cupsd_fds
, &key
);
938 cupsArrayRestore(cupsd_fds
);
945 * End of "$Id: select.c 6166 2006-12-29 20:35:18Z mike $".