Path: blob/main/crypto/krb5/src/util/verto/ev_select.c
34907 views
/*1* libev select fd activity backend2*3* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without modifica-7* tion, are permitted provided that the following conditions are met:8*9* 1. Redistributions of source code must retain the above copyright notice,10* this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED17* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-18* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO19* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-20* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,21* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;22* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,23* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-24* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED25* OF THE POSSIBILITY OF SUCH DAMAGE.26*27* Alternatively, the contents of this file may be used under the terms of28* the GNU General Public License ("GPL") version 2 or any later version,29* in which case the provisions of the GPL are applicable instead of30* the above. If you wish to allow the use of your version of this file31* only under the terms of the GPL and not to allow others to use your32* version of this file under the BSD license, indicate your decision33* by deleting the provisions above and replace them with the notice34* and other provisions required by the GPL. If you do not delete the35* provisions above, a recipient may use your version of this file under36* either the BSD or the GPL.37*/3839#ifndef _WIN3240/* for unix systems */41# include <inttypes.h>42# ifndef __hpux43/* for REAL unix systems */44# include <sys/select.h>45# endif46#endif4748#ifndef EV_SELECT_USE_FD_SET49# ifdef NFDBITS50# define EV_SELECT_USE_FD_SET 051# else52# define EV_SELECT_USE_FD_SET 153# endif54#endif5556#if EV_SELECT_IS_WINSOCKET57# undef EV_SELECT_USE_FD_SET58# define EV_SELECT_USE_FD_SET 159# undef NFDBITS60# define NFDBITS 061#endif6263#if !EV_SELECT_USE_FD_SET64# define NFDBYTES (NFDBITS / 8)65#endif6667#include <string.h>6869static void70select_modify (EV_P_ int fd, int oev, int nev)71{72if (oev == nev)73return;7475{76#if EV_SELECT_USE_FD_SET7778#if EV_SELECT_IS_WINSOCKET79SOCKET handle = anfds [fd].handle;80#else81int handle = fd;82#endif8384assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));8586/* FD_SET is broken on windows (it adds the fd to a set twice or more,87* which eventually leads to overflows). Need to call it only on changes.88*/89#if EV_SELECT_IS_WINSOCKET90if ((oev ^ nev) & EV_READ)91#endif92if (nev & EV_READ)93FD_SET (handle, (fd_set *)vec_ri);94else95FD_CLR (handle, (fd_set *)vec_ri);9697#if EV_SELECT_IS_WINSOCKET98if ((oev ^ nev) & EV_WRITE)99#endif100if (nev & EV_WRITE)101FD_SET (handle, (fd_set *)vec_wi);102else103FD_CLR (handle, (fd_set *)vec_wi);104105#else106107int word = fd / NFDBITS;108fd_mask mask = 1UL << (fd % NFDBITS);109110if (expect_false (vec_max <= word))111{112int new_max = word + 1;113114vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);115vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */116vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);117vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */118#ifdef _WIN32119vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */120#endif121122for (; vec_max < new_max; ++vec_max)123((fd_mask *)vec_ri) [vec_max] =124((fd_mask *)vec_wi) [vec_max] = 0;125}126127((fd_mask *)vec_ri) [word] |= mask;128if (!(nev & EV_READ))129((fd_mask *)vec_ri) [word] &= ~mask;130131((fd_mask *)vec_wi) [word] |= mask;132if (!(nev & EV_WRITE))133((fd_mask *)vec_wi) [word] &= ~mask;134#endif135}136}137138static void139select_poll (EV_P_ ev_tstamp timeout)140{141struct timeval tv;142int res;143int fd_setsize;144145EV_RELEASE_CB;146EV_TV_SET (tv, timeout);147148#if EV_SELECT_USE_FD_SET149fd_setsize = sizeof (fd_set);150#else151fd_setsize = vec_max * NFDBYTES;152#endif153154memcpy (vec_ro, vec_ri, fd_setsize);155memcpy (vec_wo, vec_wi, fd_setsize);156157#ifdef _WIN32158/* pass in the write set as except set.159* the idea behind this is to work around a windows bug that causes160* errors to be reported as an exception and not by setting161* the writable bit. this is so uncontrollably lame.162*/163memcpy (vec_eo, vec_wi, fd_setsize);164res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);165#elif EV_SELECT_USE_FD_SET166fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;167res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);168#else169res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);170#endif171EV_ACQUIRE_CB;172173if (expect_false (res < 0))174{175#if EV_SELECT_IS_WINSOCKET176errno = WSAGetLastError ();177#endif178#ifdef WSABASEERR179/* on windows, select returns incompatible error codes, fix this */180if (errno >= WSABASEERR && errno < WSABASEERR + 1000)181if (errno == WSAENOTSOCK)182errno = EBADF;183else184errno -= WSABASEERR;185#endif186187#ifdef _WIN32188/* select on windows erroneously returns EINVAL when no fd sets have been189* provided (this is documented). what microsoft doesn't tell you that this bug190* exists even when the fd sets _are_ provided, so we have to check for this bug191* here and emulate by sleeping manually.192* we also get EINVAL when the timeout is invalid, but we ignore this case here193* and assume that EINVAL always means: you have to wait manually.194*/195if (errno == EINVAL)196{197if (timeout)198{199unsigned long ms = timeout * 1e3;200Sleep (ms ? ms : 1);201}202203return;204}205#endif206207if (errno == EBADF)208fd_ebadf (EV_A);209else if (errno == ENOMEM && !syserr_cb)210fd_enomem (EV_A);211else if (errno != EINTR)212ev_syserr ("(libev) select");213214return;215}216217#if EV_SELECT_USE_FD_SET218219{220int fd;221222for (fd = 0; fd < anfdmax; ++fd)223if (anfds [fd].events)224{225int events = 0;226#if EV_SELECT_IS_WINSOCKET227SOCKET handle = anfds [fd].handle;228#else229int handle = fd;230#endif231232if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;233if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;234#ifdef _WIN32235if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;236#endif237238if (expect_true (events))239fd_event (EV_A_ fd, events);240}241}242243#else244245{246int word, bit;247for (word = vec_max; word--; )248{249fd_mask word_r = ((fd_mask *)vec_ro) [word];250fd_mask word_w = ((fd_mask *)vec_wo) [word];251#ifdef _WIN32252word_w |= ((fd_mask *)vec_eo) [word];253#endif254255if (word_r || word_w)256for (bit = NFDBITS; bit--; )257{258fd_mask mask = 1UL << bit;259int events = 0;260261events |= word_r & mask ? EV_READ : 0;262events |= word_w & mask ? EV_WRITE : 0;263264if (expect_true (events))265fd_event (EV_A_ word * NFDBITS + bit, events);266}267}268}269270#endif271}272273int inline_size274select_init (EV_P_ int flags)275{276backend_mintime = 1e-6;277backend_modify = select_modify;278backend_poll = select_poll;279280#if EV_SELECT_USE_FD_SET281vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);282vec_ro = ev_malloc (sizeof (fd_set));283vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);284vec_wo = ev_malloc (sizeof (fd_set));285#ifdef _WIN32286vec_eo = ev_malloc (sizeof (fd_set));287#endif288#else289vec_max = 0;290vec_ri = 0;291vec_ro = 0;292vec_wi = 0;293vec_wo = 0;294#ifdef _WIN32295vec_eo = 0;296#endif297#endif298299return EVBACKEND_SELECT;300}301302void inline_size303select_destroy (EV_P)304{305ev_free (vec_ri);306ev_free (vec_ro);307ev_free (vec_wi);308ev_free (vec_wo);309#ifdef _WIN32310ev_free (vec_eo);311#endif312}313314315316