1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #ifndef _SYS_POLL_IMPL_H 28 #define _SYS_POLL_IMPL_H 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Caching Poll Subsystem: 34 * 35 * Each kernel thread (1), if engaged in poll system call, has a reference to 36 * a pollstate_t (2), which contains relevant flags and locks. The pollstate_t 37 * contains a pointer to a pcache_t (3), which caches the state of previous 38 * calls to poll. A bitmap (4) is stored inside the poll cache, where each 39 * bit represents a file descriptor. The bits are set if the corresponding 40 * device has a polled event pending. Only fds with their bit set will be 41 * examined on the next poll invocation. The pollstate_t also contains a list 42 * of fd sets (5), which are represented by the pollcacheset_t type. These 43 * structures keep track of the pollfd_t arrays (6) passed in from userland. 44 * Each polled file descriptor has a corresponding polldat_t which can be 45 * chained onto a device's pollhead, and these are kept in a hash table (7) 46 * inside the pcache_t. The hash table allows efficient conversion of a 47 * given fd to its corresponding polldat_t. 48 * 49 * (1) (2) 50 * +-----------+ +-------------+ 51 * | kthread_t |--->| pollstate_t |-->+-------------+ (6) 52 * +-----------+ +-------------+(5)| pcacheset_t |->[_][_][_][_] pollfd_t 53 * | +-------------+ 54 * | | pcacheset_t |->[_][_][_][_] pollfd_t 55 * (1a) | +-------------+ 56 * +---------------+ | 57 * | /dev/poll tbl | | 58 * +-v-------------+ | 59 * | | 60 * +------------------+ | 61 * (7) (3) V v 62 * polldat hash +-------------+ (4) bitmap representing fd space 63 * [_][_][_][_]<----| |--->000010010010001010101010101010110 64 * | | | | | pollcache_t | 65 * . v . . | | 66 * [polldat_t] +-------------+ 67 * | 68 * [polldat_t] 69 * | 70 * v 71 * NULL 72 * 73 * 74 * Both poll system call and /dev/poll use the pollcache_t structure 75 * definition and the routines managing the structure. But poll(2) and 76 * /dev/poll have their own copy of the structures. The /dev/poll driver 77 * table (1a) contains an array of pointers, each pointing at a pcache_t 78 * struct (3). A device minor number is used as an device table index. 79 * 80 */ 81 #include <sys/poll.h> 82 83 #if defined(_KERNEL) || defined(_KMEMUSER) 84 85 #include <sys/thread.h> 86 #include <sys/file.h> 87 88 #ifdef __cplusplus 89 extern "C" { 90 #endif 91 92 /* 93 * description of pollcacheset structure 94 */ 95 typedef struct pollcacheset { 96 uintptr_t pcs_usradr; /* usr pollfd array address */ 97 pollfd_t *pcs_pollfd; /* cached poll lists */ 98 size_t pcs_nfds; /* number of poll fd in cached list */ 99 ulong_t pcs_count; /* for LU replacement policy */ 100 } pollcacheset_t; 101 102 #define POLLFDSETS 2 103 104 /* 105 * State information kept by each polling thread 106 */ 107 typedef struct pollstate { 108 pollfd_t *ps_pollfd; /* hold the current poll list */ 109 size_t ps_nfds; /* size of ps_pollfd */ 110 kmutex_t ps_lock; /* mutex for sleep/wakeup */ 111 struct pollcache *ps_pcache; /* cached poll fd set */ 112 pollcacheset_t *ps_pcacheset; /* cached poll lists */ 113 int ps_nsets; /* no. of cached poll sets */ 114 pollfd_t *ps_dpbuf; /* return pollfd buf used by devpoll */ 115 size_t ps_dpbufsize; /* size of ps_dpbuf */ 116 } pollstate_t; 117 118 /* 119 * poll cache size defines 120 */ 121 #define POLLCHUNKSHIFT 8 /* hash table increment size is 256 */ 122 #define POLLHASHCHUNKSZ (1 << POLLCHUNKSHIFT) 123 #define POLLHASHINC 2 /* poll hash table growth factor */ 124 #define POLLHASHTHRESHOLD 2 /* poll hash list length threshold */ 125 #define POLLHASH(x, y) ((y) % (x)) /* poll hash function */ 126 127 /* 128 * poll.c assumes the POLLMAPCHUNK is power of 2 129 */ 130 #define POLLMAPCHUNK 2048 /* bitmap inc -- each for 2K of polled fd's */ 131 132 /* 133 * used to refrence from watched fd back to the fd position in cached 134 * poll list for quick revents update. 135 */ 136 typedef struct xref { 137 ssize_t xf_position; /* xref fd position in poll fd list */ 138 short xf_refcnt; /* ref cnt of same fd in poll list */ 139 } xref_t; 140 141 #define POLLPOSINVAL (-1L) /* xf_position is invalid */ 142 #define POLLPOSTRANS (-2L) /* xf_position is transient state */ 143 144 /* 145 * polldat is an entry for a cached poll fd. A polldat struct can be in 146 * poll cache table as well as on pollhead ph_list, which is used by 147 * pollwakeup to wake up a sleeping poller. There should be one polldat 148 * per polled fd hanging off pollstate struct. 149 */ 150 typedef struct polldat { 151 int pd_fd; /* cached poll fd */ 152 int pd_events; /* union of all polled events */ 153 file_t *pd_fp; /* used to detect fd reuse */ 154 pollhead_t *pd_php; /* used to undo poll registration */ 155 kthread_t *pd_thread; /* used for waking up a sleep thrd */ 156 struct pollcache *pd_pcache; /* a ptr to the pollcache of this fd */ 157 struct polldat *pd_next; /* next on pollhead's ph_list */ 158 struct polldat *pd_hashnext; /* next on pollhead's ph_list */ 159 int pd_count; /* total count from all ref'ed sets */ 160 int pd_nsets; /* num of xref sets, used by poll(2) */ 161 xref_t *pd_ref; /* ptr to xref info, 1 for each set */ 162 struct port_kevent *pd_portev; /* associated port event struct */ 163 } polldat_t; 164 165 /* 166 * One cache for each thread that polls. Points to a bitmap (used by pollwakeup) 167 * and a hash table of polldats. 168 * The offset of pc_lock field must be kept in sync with the pc_lock offset 169 * of port_fdcache_t, both structs implement pc_lock with offset 0 (see also 170 * pollrelock()). 171 */ 172 typedef struct pollcache { 173 kmutex_t pc_lock; /* lock to protect pollcache */ 174 ulong_t *pc_bitmap; /* point to poll fd bitmap */ 175 polldat_t **pc_hash; /* points to a hash table of ptrs */ 176 int pc_mapend; /* the largest fd encountered so far */ 177 int pc_mapsize; /* the size of current map */ 178 int pc_hashsize; /* the size of current hash table */ 179 int pc_fdcount; /* track how many fd's are hashed */ 180 int pc_flag; /* see pc_flag define below */ 181 int pc_busy; /* can only exit when its 0 */ 182 kmutex_t pc_no_exit; /* protects pc_busy*, can't be nested */ 183 kcondvar_t pc_busy_cv; /* cv to wait on if ps_busy != 0 */ 184 kcondvar_t pc_cv; /* cv to wait on if needed */ 185 pid_t pc_pid; /* for check acc rights, devpoll only */ 186 int pc_mapstart; /* where search start, devpoll only */ 187 } pollcache_t; 188 189 /* pc_flag */ 190 #define T_POLLWAKE 0x02 /* pollwakeup() occurred */ 191 192 #if defined(_KERNEL) 193 /* 194 * Internal routines. 195 */ 196 extern void pollnotify(pollcache_t *, int); 197 198 /* 199 * public poll head interfaces (see poll.h): 200 * 201 * pollhead_clean clean up all polldats on a pollhead list 202 */ 203 extern void pollhead_clean(pollhead_t *); 204 205 /* 206 * private poll head interfaces: 207 * 208 * pollhead_insert adds a polldat to a pollhead list 209 * pollhead_delete removes a polldat from a pollhead list 210 */ 211 extern void pollhead_insert(pollhead_t *, polldat_t *); 212 extern void pollhead_delete(pollhead_t *, polldat_t *); 213 214 /* 215 * poll state interfaces: 216 * 217 * pollstate_create creates per-thread pollstate 218 * pollstate_destroy cleans up per-thread pollstate 219 */ 220 extern pollstate_t *pollstate_create(void); 221 extern void pollstate_destroy(pollstate_t *); 222 223 /* 224 * public pcache interfaces: 225 * 226 * pcache_alloc allocate a poll cache skeleton 227 * pcache_create creates all poll cache supporting data struct 228 * pcache_insert cache a poll fd, calls pcache_insert_fd 229 * pcache_lookup given an fd list, returns a cookie 230 * pcache_poll polls the cache for fd's having events on them 231 * pcache_clean clean up all the pollhead and fpollinfo reference 232 * pcache_destroy destroys the pcache 233 */ 234 extern pollcache_t *pcache_alloc(); 235 extern void pcache_create(pollcache_t *, nfds_t); 236 extern int pcache_insert(pollstate_t *, file_t *, pollfd_t *, int *, ssize_t, 237 int); 238 extern int pcache_poll(pollfd_t *, pollstate_t *, nfds_t, int *, int); 239 extern void pcache_clean(pollcache_t *); 240 extern void pcache_destroy(pollcache_t *); 241 242 /* 243 * private pcache interfaces: 244 * 245 * pcache_lookup_fd lookup an fd, returns a polldat 246 * pcache_alloc_fd allocates and returns a polldat 247 * pcache_insert_fd insert an fd into pcache (called by pcache_insert) 248 * pcache_delete_fd insert an fd into pcache (called by pcacheset_delete_fd) 249 * pcache_grow_hashtbl grows the pollcache hash table and rehash 250 * pcache_grow_map grows the pollcache bitmap 251 * pcache_update_xref update cross ref (from polldat back to cacheset) info 252 * pcache_clean_entry cleanup an entry in pcache and more... 253 */ 254 extern polldat_t *pcache_lookup_fd(pollcache_t *, int); 255 extern polldat_t *pcache_alloc_fd(int); 256 extern void pcache_insert_fd(pollcache_t *, polldat_t *, nfds_t); 257 extern int pcache_delete_fd(pollstate_t *, int, size_t, int, uint_t); 258 extern void pcache_grow_hashtbl(pollcache_t *, nfds_t); 259 extern void pcache_grow_map(pollcache_t *, int); 260 extern void pcache_update_xref(pollcache_t *, int, ssize_t, int); 261 extern void pcache_clean_entry(pollstate_t *, int); 262 263 /* 264 * pcacheset interfaces: 265 * 266 * pcacheset_create creates new pcachesets (easier for dynamic pcachesets) 267 * pcacheset_destroy destroys a pcacheset 268 * pcacheset_cache_list caches and polls a new poll list 269 * pcacheset_remove_list removes (usually a partial) cached poll list 270 * pcacheset_resolve resolves extant pcacheset and fd list 271 * pcacheset_cmp compares a pcacheset with an fd list 272 * pcacheset_invalidate invalidate entries in pcachesets 273 * pcacheset_reset_count resets the usage counter of pcachesets 274 * pcacheset_replace selects a poll cacheset for replacement 275 */ 276 extern pollcacheset_t *pcacheset_create(int); 277 extern void pcacheset_destroy(pollcacheset_t *, int); 278 extern int pcacheset_cache_list(pollstate_t *, pollfd_t *, int *, int); 279 extern void pcacheset_remove_list(pollstate_t *, pollfd_t *, int, int, int, 280 int); 281 extern int pcacheset_resolve(pollstate_t *, nfds_t, int *, int); 282 extern int pcacheset_cmp(pollfd_t *, pollfd_t *, pollfd_t *, int); 283 extern void pcacheset_invalidate(pollstate_t *, polldat_t *); 284 extern void pcacheset_reset_count(pollstate_t *, int); 285 extern int pcacheset_replace(pollstate_t *); 286 287 #endif /* defined(_KERNEL) */ 288 289 #ifdef __cplusplus 290 } 291 #endif 292 293 #endif /* defined(_KERNEL) || defined(_KMEMUSER) */ 294 295 #endif /* _SYS_POLL_IMPL_H */ 296