From nobody Mon Apr 29 18:43:37 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.24 as permitted sender) client-ip=209.132.183.24; envelope-from=libvir-list-bounces@redhat.com; helo=mx3-phx2.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.24 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx3-phx2.redhat.com (mx3-phx2.redhat.com [209.132.183.24]) by mx.zohomail.com with SMTPS id 1487095829566877.5501648708772; Tue, 14 Feb 2017 10:10:29 -0800 (PST) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx3-phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v1EI6Fwk002259; Tue, 14 Feb 2017 13:06:15 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v1EI6Exf016233 for ; Tue, 14 Feb 2017 13:06:14 -0500 Received: from mx1.redhat.com (ext-mx05.extmail.prod.ext.phx2.redhat.com [10.5.110.29]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v1EI6E9P010200 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 14 Feb 2017 13:06:14 -0500 Received: from relay.sw.ru (mailhub.sw.ru [195.214.232.25]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1E9913A7691 for ; Tue, 14 Feb 2017 18:06:09 +0000 (UTC) Received: from localhost.localdomain (msk-vpn.virtuozzo.com [195.214.232.6]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id v1EI63DR028411; Tue, 14 Feb 2017 21:06:03 +0300 (MSK) From: Derbyshev Dmitriy To: libvir-list@redhat.com Date: Tue, 14 Feb 2017 21:04:20 +0300 Message-Id: <1487095461-12268-2-git-send-email-dderbyshev@virtuozzo.com> In-Reply-To: <1487095461-12268-1-git-send-email-dderbyshev@virtuozzo.com> References: <1487095461-12268-1-git-send-email-dderbyshev@virtuozzo.com> X-Greylist: Delayed for 100:34:54 by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 14 Feb 2017 18:06:10 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 14 Feb 2017 18:06:10 +0000 (UTC) for IP:'195.214.232.25' DOMAIN:'mailhub.sw.ru' HELO:'relay.sw.ru' FROM:'dderbyshev@virtuozzo.com' RCPT:'' X-RedHat-Spam-Score: 0.799 (BAYES_50, SPF_PASS) 195.214.232.25 mailhub.sw.ru 195.214.232.25 mailhub.sw.ru X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Scanned-By: MIMEDefang 2.78 on 10.5.110.29 X-loop: libvir-list@redhat.com Cc: redkoi@virtuozzo.com, Derbyshev Dmitry , den@virtuozzo.com, kneumoin@virtuozzo.com, mnestratov@virtuozzo.com, nshirokovskiy@virtuozzo.com Subject: [libvirt] [RFC v2 1/2] vireventpoll: isolate common code X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Derbyshev Dmitry To introduce new implementation (ex. with epoll) some code should be substituted. This patch divides vireventpoll into common and implementation-specific parts. --- src/Makefile.am | 4 +- src/util/vireventpoll.c | 700 ++----------------= ---- src/util/{vireventpoll.c =3D> vireventpollcommon.c} | 231 ++----- src/util/vireventpollinternal.h | 91 +++ 4 files changed, 209 insertions(+), 817 deletions(-) copy src/util/{vireventpoll.c =3D> vireventpollcommon.c} (78%) create mode 100644 src/util/vireventpollinternal.h diff --git a/src/Makefile.am b/src/Makefile.am index 2f32d41..f2643ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,7 +112,8 @@ UTIL_SOURCES =3D \ util/virendian.h \ util/virerror.c util/virerror.h \ util/virevent.c util/virevent.h \ - util/vireventpoll.c util/vireventpoll.h \ + util/vireventpollcommon.c util/vireventpoll.h \ + util/vireventpoll.c util/vireventpollinternal.h \ util/virfile.c util/virfile.h \ util/virfirewall.c util/virfirewall.h \ util/virfirewallpriv.h \ @@ -2376,6 +2377,7 @@ libvirt_setuid_rpc_client_la_SOURCES =3D \ util/virerror.c \ util/virevent.c \ util/vireventpoll.c \ + util/vireventpollcommon.c \ util/virfile.c \ util/virgettext.c \ util/virhash.c \ diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 81ecab4..e429e98 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -23,23 +23,12 @@ =20 #include =20 -#include -#include #include -#include -#include -#include -#include =20 -#include "virthread.h" +#include "viralloc.h" #include "virlog.h" #include "vireventpoll.h" -#include "viralloc.h" -#include "virutil.h" -#include "virfile.h" -#include "virerror.h" -#include "virprobe.h" -#include "virtime.h" +#include "vireventpollinternal.h" =20 #define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) =20 @@ -47,329 +36,26 @@ =20 VIR_LOG_INIT("util.eventpoll"); =20 -static int virEventPollInterruptLocked(void); - -/* State for a single file handle being monitored */ -struct virEventPollHandle { - int watch; - int fd; - int events; - virEventHandleCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* State for a single timer being generated */ -struct virEventPollTimeout { - int timer; - int frequency; - unsigned long long expiresAt; - virEventTimeoutCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* Allocate extra slots for virEventPollHandle/virEventPollTimeout - records in this multiple */ -#define EVENT_ALLOC_EXTENT 10 - -/* State for the main event loop */ -struct virEventPollLoop { - virMutex lock; - int running; - virThread leader; - int wakeupfd[2]; - size_t handlesCount; - size_t handlesAlloc; - struct virEventPollHandle *handles; - size_t timeoutsCount; - size_t timeoutsAlloc; - struct virEventPollTimeout *timeouts; -}; - -/* Only have one event loop */ -static struct virEventPollLoop eventLoop; - -/* Unique ID for the next FD watch to be registered */ -static int nextWatch =3D 1; - -/* Unique ID for the next timer to be registered */ -static int nextTimer =3D 1; - -/* - * Register a callback for monitoring file handle events. - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever append to existing list. - */ -int virEventPollAddHandle(int fd, int events, - virEventHandleCallback cb, - void *opaque, - virFreeCallback ff) +int virEventPollAddHandleInternal(int watch ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED, + int nativeevents ATTRIBUTE_UNUSED) { - int watch; - virMutexLock(&eventLoop.lock); - if (eventLoop.handlesCount =3D=3D eventLoop.handlesAlloc) { - EVENT_DEBUG("Used %zu handle slots, adding at least %d more", - eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); - if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc, - eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) { - virMutexUnlock(&eventLoop.lock); - return -1; - } - } - - watch =3D nextWatch++; - - eventLoop.handles[eventLoop.handlesCount].watch =3D watch; - eventLoop.handles[eventLoop.handlesCount].fd =3D fd; - eventLoop.handles[eventLoop.handlesCount].events =3D - virEventPollToNativeEvents(events= ); - eventLoop.handles[eventLoop.handlesCount].cb =3D cb; - eventLoop.handles[eventLoop.handlesCount].ff =3D ff; - eventLoop.handles[eventLoop.handlesCount].opaque =3D opaque; - eventLoop.handles[eventLoop.handlesCount].deleted =3D 0; - - eventLoop.handlesCount++; - virEventPollInterruptLocked(); - - PROBE(EVENT_POLL_ADD_HANDLE, - "watch=3D%d fd=3D%d events=3D%d cb=3D%p opaque=3D%p ff=3D%p", - watch, fd, events, cb, opaque, ff); - virMutexUnlock(&eventLoop.lock); - - return watch; -} - -void virEventPollUpdateHandle(int watch, int events) -{ - size_t i; - bool found =3D false; - PROBE(EVENT_POLL_UPDATE_HANDLE, - "watch=3D%d events=3D%d", - watch, events); - - if (watch <=3D 0) { - VIR_WARN("Ignoring invalid update watch %d", watch); - return; - } - - virMutexLock(&eventLoop.lock); - for (i =3D 0; i < eventLoop.handlesCount; i++) { - if (eventLoop.handles[i].watch =3D=3D watch) { - eventLoop.handles[i].events =3D - virEventPollToNativeEvents(events); - virEventPollInterruptLocked(); - found =3D true; - break; - } - } - virMutexUnlock(&eventLoop.lock); - - if (!found) - VIR_WARN("Got update for non-existent handle watch %d", watch); -} - -/* - * Unregister a callback from a file handle - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever set a flag in the existing list. - * Actual deletion will be done out-of-band - */ -int virEventPollRemoveHandle(int watch) -{ - size_t i; - PROBE(EVENT_POLL_REMOVE_HANDLE, - "watch=3D%d", - watch); - - if (watch <=3D 0) { - VIR_WARN("Ignoring invalid remove watch %d", watch); - return -1; - } - - virMutexLock(&eventLoop.lock); - for (i =3D 0; i < eventLoop.handlesCount; i++) { - if (eventLoop.handles[i].deleted) - continue; - - if (eventLoop.handles[i].watch =3D=3D watch) { - EVENT_DEBUG("mark delete %zu %d", i, eventLoop.handles[i].fd); - eventLoop.handles[i].deleted =3D 1; - virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return 0; - } - } - virMutexUnlock(&eventLoop.lock); - return -1; + return 0; } =20 - -/* - * Register a callback for a timer event - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever append to existing list. - */ -int virEventPollAddTimeout(int frequency, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff) +int virEventPollUpdateHandleInternal(int watch ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED, + int nativeevents ATTRIBUTE_UNUSED) { - unsigned long long now; - int ret; - - if (virTimeMillisNow(&now) < 0) - return -1; - - virMutexLock(&eventLoop.lock); - if (eventLoop.timeoutsCount =3D=3D eventLoop.timeoutsAlloc) { - EVENT_DEBUG("Used %zu timeout slots, adding at least %d more", - eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); - if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, - eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0)= { - virMutexUnlock(&eventLoop.lock); - return -1; - } - } - - eventLoop.timeouts[eventLoop.timeoutsCount].timer =3D nextTimer++; - eventLoop.timeouts[eventLoop.timeoutsCount].frequency =3D frequency; - eventLoop.timeouts[eventLoop.timeoutsCount].cb =3D cb; - eventLoop.timeouts[eventLoop.timeoutsCount].ff =3D ff; - eventLoop.timeouts[eventLoop.timeoutsCount].opaque =3D opaque; - eventLoop.timeouts[eventLoop.timeoutsCount].deleted =3D 0; - eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =3D - frequency >=3D 0 ? frequency + now : 0; - - eventLoop.timeoutsCount++; - ret =3D nextTimer-1; virEventPollInterruptLocked(); - - PROBE(EVENT_POLL_ADD_TIMEOUT, - "timer=3D%d frequency=3D%d cb=3D%p opaque=3D%p ff=3D%p", - ret, frequency, cb, opaque, ff); - virMutexUnlock(&eventLoop.lock); - return ret; -} - -void virEventPollUpdateTimeout(int timer, int frequency) -{ - unsigned long long now; - size_t i; - bool found =3D false; - PROBE(EVENT_POLL_UPDATE_TIMEOUT, - "timer=3D%d frequency=3D%d", - timer, frequency); - - if (timer <=3D 0) { - VIR_WARN("Ignoring invalid update timer %d", timer); - return; - } - - if (virTimeMillisNow(&now) < 0) - return; - - virMutexLock(&eventLoop.lock); - for (i =3D 0; i < eventLoop.timeoutsCount; i++) { - if (eventLoop.timeouts[i].timer =3D=3D timer) { - eventLoop.timeouts[i].frequency =3D frequency; - eventLoop.timeouts[i].expiresAt =3D - frequency >=3D 0 ? frequency + now : 0; - VIR_DEBUG("Set timer freq=3D%d expires=3D%llu", frequency, - eventLoop.timeouts[i].expiresAt); - virEventPollInterruptLocked(); - found =3D true; - break; - } - } - virMutexUnlock(&eventLoop.lock); - - if (!found) - VIR_WARN("Got update for non-existent timer %d", timer); -} - -/* - * Unregister a callback for a timer - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever set a flag in the existing list. - * Actual deletion will be done out-of-band - */ -int virEventPollRemoveTimeout(int timer) -{ - size_t i; - PROBE(EVENT_POLL_REMOVE_TIMEOUT, - "timer=3D%d", - timer); - - if (timer <=3D 0) { - VIR_WARN("Ignoring invalid remove timer %d", timer); - return -1; - } - - virMutexLock(&eventLoop.lock); - for (i =3D 0; i < eventLoop.timeoutsCount; i++) { - if (eventLoop.timeouts[i].deleted) - continue; - - if (eventLoop.timeouts[i].timer =3D=3D timer) { - eventLoop.timeouts[i].deleted =3D 1; - virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return 0; - } - } - virMutexUnlock(&eventLoop.lock); - return -1; + return 0; } =20 -/* Iterates over all registered timeouts and determine which - * will be the first to expire. - * @timeout: filled with expiry time of soonest timer, or -1 if - * no timeout is pending - * returns: 0 on success, -1 on error - */ -static int virEventPollCalculateTimeout(int *timeout) +int virEventPollRemoveHandleInternal(int watch ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED) { - unsigned long long then =3D 0; - size_t i; - EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount); - /* Figure out if we need a timeout */ - for (i =3D 0; i < eventLoop.timeoutsCount; i++) { - if (eventLoop.timeouts[i].deleted) - continue; - if (eventLoop.timeouts[i].frequency < 0) - continue; - - EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts= [i].expiresAt); - if (then =3D=3D 0 || - eventLoop.timeouts[i].expiresAt < then) - then =3D eventLoop.timeouts[i].expiresAt; - } - - /* Calculate how long we should wait for a timeout if needed */ - if (then > 0) { - unsigned long long now; - - if (virTimeMillisNow(&now) < 0) - return -1; - - EVENT_DEBUG("Schedule timeout then=3D%llu now=3D%llu", then, now); - if (then <=3D now) - *timeout =3D 0; - else - *timeout =3D ((then - now) > INT_MAX) ? INT_MAX : (then - now); - } else { - *timeout =3D -1; - } - - if (*timeout > -1) - EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout); - else - EVENT_DEBUG("%s", "No timeout is pending"); - + // virEventPollInterruptLocked() is called in common code. return 0; } =20 @@ -410,332 +96,14 @@ static struct pollfd *virEventPollMakePollFDs(int *nf= ds) { return fds; } =20 - -/* - * Iterate over all timers and determine if any have expired. - * Invoke the user supplied callback for each timer whose - * expiry time is met, and schedule the next timeout. Does - * not try to 'catch up' on time if the actual expiry time - * was later than the requested time. - * - * This method must cope with new timers being registered - * by a callback, and must skip any timers marked as deleted. - * - * Returns 0 upon success, -1 if an error occurred - */ -static int virEventPollDispatchTimeouts(void) -{ - unsigned long long now; - size_t i; - /* Save this now - it may be changed during dispatch */ - int ntimeouts =3D eventLoop.timeoutsCount; - VIR_DEBUG("Dispatch %d", ntimeouts); - - if (virTimeMillisNow(&now) < 0) - return -1; - - for (i =3D 0; i < ntimeouts; i++) { - if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequen= cy < 0) - continue; - - /* Add 20ms fuzz so we don't pointlessly spin doing - * <10ms sleeps, particularly on kernels with low HZ - * it is fine that a timer expires 20ms earlier than - * requested - */ - if (eventLoop.timeouts[i].expiresAt <=3D (now+20)) { - virEventTimeoutCallback cb =3D eventLoop.timeouts[i].cb; - int timer =3D eventLoop.timeouts[i].timer; - void *opaque =3D eventLoop.timeouts[i].opaque; - eventLoop.timeouts[i].expiresAt =3D - now + eventLoop.timeouts[i].frequency; - - PROBE(EVENT_POLL_DISPATCH_TIMEOUT, - "timer=3D%d", - timer); - virMutexUnlock(&eventLoop.lock); - (cb)(timer, opaque); - virMutexLock(&eventLoop.lock); - } - } - return 0; -} - - -/* Iterate over all file handles and dispatch any which - * have pending events listed in the poll() data. Invoke - * the user supplied callback for each handle which has - * pending events - * - * This method must cope with new handles being registered - * by a callback, and must skip any handles marked as deleted. - * - * Returns 0 upon success, -1 if an error occurred - */ -static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) -{ - size_t i, n; - VIR_DEBUG("Dispatch %d", nfds); - - /* NB, use nfds not eventLoop.handlesCount, because new - * fds might be added on end of list, and they're not - * in the fds array we've got */ - for (i =3D 0, n =3D 0; n < nfds && i < eventLoop.handlesCount; n++) { - while (i < eventLoop.handlesCount && - (eventLoop.handles[i].fd !=3D fds[n].fd || - eventLoop.handles[i].events =3D=3D 0)) { - i++; - } - if (i =3D=3D eventLoop.handlesCount) - break; - - VIR_DEBUG("i=3D%zu w=3D%d", i, eventLoop.handles[i].watch); - if (eventLoop.handles[i].deleted) { - EVENT_DEBUG("Skip deleted n=3D%zu w=3D%d f=3D%d", i, - eventLoop.handles[i].watch, eventLoop.handles[i].f= d); - continue; - } - - if (fds[n].revents) { - virEventHandleCallback cb =3D eventLoop.handles[i].cb; - int watch =3D eventLoop.handles[i].watch; - void *opaque =3D eventLoop.handles[i].opaque; - int hEvents =3D virEventPollFromNativeEvents(fds[n].revents); - PROBE(EVENT_POLL_DISPATCH_HANDLE, - "watch=3D%d events=3D%d", - watch, hEvents); - virMutexUnlock(&eventLoop.lock); - (cb)(watch, fds[n].fd, hEvents, opaque); - virMutexLock(&eventLoop.lock); - } - } - - return 0; -} - - -/* Used post dispatch to actually remove any timers that - * were previously marked as deleted. This asynchronous - * cleanup is needed to make dispatch re-entrant safe. - */ -static void virEventPollCleanupTimeouts(void) -{ - size_t i; - size_t gap; - VIR_DEBUG("Cleanup %zu", eventLoop.timeoutsCount); - - /* Remove deleted entries, shuffling down remaining - * entries as needed to form contiguous series - */ - for (i =3D 0; i < eventLoop.timeoutsCount;) { - if (!eventLoop.timeouts[i].deleted) { - i++; - continue; - } - - PROBE(EVENT_POLL_PURGE_TIMEOUT, - "timer=3D%d", - eventLoop.timeouts[i].timer); - if (eventLoop.timeouts[i].ff) { - virFreeCallback ff =3D eventLoop.timeouts[i].ff; - void *opaque =3D eventLoop.timeouts[i].opaque; - virMutexUnlock(&eventLoop.lock); - ff(opaque); - virMutexLock(&eventLoop.lock); - } - - if ((i+1) < eventLoop.timeoutsCount) { - memmove(eventLoop.timeouts+i, - eventLoop.timeouts+i+1, - sizeof(struct virEventPollTimeout)*(eventLoop.timeouts= Count - -(i+1))); - } - eventLoop.timeoutsCount--; - } - - /* Release some memory if we've got a big chunk free */ - gap =3D eventLoop.timeoutsAlloc - eventLoop.timeoutsCount; - if (eventLoop.timeoutsCount =3D=3D 0 || - (gap > eventLoop.timeoutsCount && gap > EVENT_ALLOC_EXTENT)) { - EVENT_DEBUG("Found %zu out of %zu timeout slots used, releasing %z= u", - eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, gap); - VIR_SHRINK_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, gap); - } -} - -/* Used post dispatch to actually remove any handles that - * were previously marked as deleted. This asynchronous - * cleanup is needed to make dispatch re-entrant safe. - */ -static void virEventPollCleanupHandles(void) -{ - size_t i; - size_t gap; - VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount); - - /* Remove deleted entries, shuffling down remaining - * entries as needed to form contiguous series - */ - for (i =3D 0; i < eventLoop.handlesCount;) { - if (!eventLoop.handles[i].deleted) { - i++; - continue; - } - - PROBE(EVENT_POLL_PURGE_HANDLE, - "watch=3D%d", - eventLoop.handles[i].watch); - if (eventLoop.handles[i].ff) { - virFreeCallback ff =3D eventLoop.handles[i].ff; - void *opaque =3D eventLoop.handles[i].opaque; - virMutexUnlock(&eventLoop.lock); - ff(opaque); - virMutexLock(&eventLoop.lock); - } - - if ((i+1) < eventLoop.handlesCount) { - memmove(eventLoop.handles+i, - eventLoop.handles+i+1, - sizeof(struct virEventPollHandle)*(eventLoop.handlesCo= unt - -(i+1))); - } - eventLoop.handlesCount--; - } - - /* Release some memory if we've got a big chunk free */ - gap =3D eventLoop.handlesAlloc - eventLoop.handlesCount; - if (eventLoop.handlesCount =3D=3D 0 || - (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) { - EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %z= u", - eventLoop.handlesCount, eventLoop.handlesAlloc, gap); - VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap); - } -} - -/* - * Run a single iteration of the event loop, blocking until - * at least one file handle has an event, or a timer expires - */ -int virEventPollRunOnce(void) +int virEventPollInitInternal(void) { - struct pollfd *fds =3D NULL; - int ret, timeout, nfds; - - virMutexLock(&eventLoop.lock); - eventLoop.running =3D 1; - virThreadSelf(&eventLoop.leader); - - virEventPollCleanupTimeouts(); - virEventPollCleanupHandles(); - - if (!(fds =3D virEventPollMakePollFDs(&nfds)) || - virEventPollCalculateTimeout(&timeout) < 0) - goto error; - - virMutexUnlock(&eventLoop.lock); - - retry: - PROBE(EVENT_POLL_RUN, - "nhandles=3D%d timeout=3D%d", - nfds, timeout); - ret =3D poll(fds, nfds, timeout); - if (ret < 0) { - EVENT_DEBUG("Poll got error event %d", errno); - if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) - goto retry; - virReportSystemError(errno, "%s", - _("Unable to poll on file handles")); - goto error_unlocked; - } - EVENT_DEBUG("Poll got %d event(s)", ret); - - virMutexLock(&eventLoop.lock); - if (virEventPollDispatchTimeouts() < 0) - goto error; - - if (ret > 0 && - virEventPollDispatchHandles(nfds, fds) < 0) - goto error; - - virEventPollCleanupTimeouts(); - virEventPollCleanupHandles(); - - eventLoop.running =3D 0; - virMutexUnlock(&eventLoop.lock); - VIR_FREE(fds); - return 0; - - error: - virMutexUnlock(&eventLoop.lock); - error_unlocked: - VIR_FREE(fds); - return -1; -} - - -static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED, - int fd, - int events ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - char c; - virMutexLock(&eventLoop.lock); - ignore_value(saferead(fd, &c, sizeof(c))); - virMutexUnlock(&eventLoop.lock); -} - -int virEventPollInit(void) -{ - if (virMutexInit(&eventLoop.lock) < 0) { - virReportSystemError(errno, "%s", - _("Unable to initialize mutex")); - return -1; - } - - if (pipe2(eventLoop.wakeupfd, O_CLOEXEC | O_NONBLOCK) < 0) { - virReportSystemError(errno, "%s", - _("Unable to setup wakeup pipe")); - return -1; - } - - if (virEventPollAddHandle(eventLoop.wakeupfd[0], - VIR_EVENT_HANDLE_READABLE, - virEventPollHandleWakeup, NULL, NULL) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to add handle %d to event loop"), - eventLoop.wakeupfd[0]); - VIR_FORCE_CLOSE(eventLoop.wakeupfd[0]); - VIR_FORCE_CLOSE(eventLoop.wakeupfd[1]); - return -1; - } - return 0; } =20 -static int virEventPollInterruptLocked(void) +void virEventPollDeinitInternal(void) { - char c =3D '\0'; - - if (!eventLoop.running || - virThreadIsSelf(&eventLoop.leader)) { - VIR_DEBUG("Skip interrupt, %d %llu", eventLoop.running, - virThreadID(&eventLoop.leader)); - return 0; - } - - VIR_DEBUG("Interrupting"); - if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) !=3D sizeof(c)) - return -1; - return 0; -} - -int virEventPollInterrupt(void) -{ - int ret; - virMutexLock(&eventLoop.lock); - ret =3D virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return ret; + return; } =20 int @@ -769,3 +137,39 @@ virEventPollFromNativeEvents(int events) ret |=3D VIR_EVENT_HANDLE_HANGUP; return ret; } + +int virEventPollWait(int timeout, void **opaque) +{ + int ret, nfds; + struct pollfd *fds =3D NULL; + + if (!(fds =3D virEventPollMakePollFDs(&nfds))) + return -1; + *opaque =3D fds; + + retry: + ret =3D poll(fds, nfds, timeout); + if (ret < 0) { + EVENT_DEBUG("Poll got error event %d", errno); + if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) + goto retry; + virReportSystemError(errno, "%s", + _("Unable to poll on file handles")); + } + return nfds; +} + +void virEventPollOpaqueFree(void *opaque) +{ + VIR_FREE(opaque); +} + +int VirWokenFD(void *opaque, size_t n) +{ + return ((struct pollfd *)opaque)[n].fd; +} + +int VirWokenEvents(void *opaque, size_t n) +{ + return ((struct pollfd *)opaque)[n].revents; +} diff --git a/src/util/vireventpoll.c b/src/util/vireventpollcommon.c similarity index 78% copy from src/util/vireventpoll.c copy to src/util/vireventpollcommon.c index 81ecab4..6a3a372 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpollcommon.c @@ -25,7 +25,6 @@ =20 #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include "virthread.h" #include "virlog.h" #include "vireventpoll.h" +#include "vireventpollinternal.h" #include "viralloc.h" #include "virutil.h" #include "virfile.h" @@ -47,56 +47,9 @@ =20 VIR_LOG_INIT("util.eventpoll"); =20 -static int virEventPollInterruptLocked(void); - -/* State for a single file handle being monitored */ -struct virEventPollHandle { - int watch; - int fd; - int events; - virEventHandleCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* State for a single timer being generated */ -struct virEventPollTimeout { - int timer; - int frequency; - unsigned long long expiresAt; - virEventTimeoutCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* Allocate extra slots for virEventPollHandle/virEventPollTimeout - records in this multiple */ -#define EVENT_ALLOC_EXTENT 10 - -/* State for the main event loop */ -struct virEventPollLoop { - virMutex lock; - int running; - virThread leader; - int wakeupfd[2]; - size_t handlesCount; - size_t handlesAlloc; - struct virEventPollHandle *handles; - size_t timeoutsCount; - size_t timeoutsAlloc; - struct virEventPollTimeout *timeouts; -}; - -/* Only have one event loop */ -static struct virEventPollLoop eventLoop; - -/* Unique ID for the next FD watch to be registered */ -static int nextWatch =3D 1; - -/* Unique ID for the next timer to be registered */ -static int nextTimer =3D 1; +struct virEventPollLoop eventLoop; +int nextWatch =3D 1; +int nextTimer =3D 1; =20 /* * Register a callback for monitoring file handle events. @@ -109,6 +62,7 @@ int virEventPollAddHandle(int fd, int events, virFreeCallback ff) { int watch; + int native =3D virEventPollToNativeEvents(events); virMutexLock(&eventLoop.lock); if (eventLoop.handlesCount =3D=3D eventLoop.handlesAlloc) { EVENT_DEBUG("Used %zu handle slots, adding at least %d more", @@ -124,8 +78,7 @@ int virEventPollAddHandle(int fd, int events, =20 eventLoop.handles[eventLoop.handlesCount].watch =3D watch; eventLoop.handles[eventLoop.handlesCount].fd =3D fd; - eventLoop.handles[eventLoop.handlesCount].events =3D - virEventPollToNativeEvents(events= ); + eventLoop.handles[eventLoop.handlesCount].events =3D native; eventLoop.handles[eventLoop.handlesCount].cb =3D cb; eventLoop.handles[eventLoop.handlesCount].ff =3D ff; eventLoop.handles[eventLoop.handlesCount].opaque =3D opaque; @@ -133,7 +86,10 @@ int virEventPollAddHandle(int fd, int events, =20 eventLoop.handlesCount++; =20 - virEventPollInterruptLocked(); + if (virEventPollAddHandleInternal(watch, fd, native) < 0) { + virMutexUnlock(&eventLoop.lock); + return -1; + } =20 PROBE(EVENT_POLL_ADD_HANDLE, "watch=3D%d fd=3D%d events=3D%d cb=3D%p opaque=3D%p ff=3D%p", @@ -147,6 +103,7 @@ void virEventPollUpdateHandle(int watch, int events) { size_t i; bool found =3D false; + int native =3D virEventPollToNativeEvents(events); PROBE(EVENT_POLL_UPDATE_HANDLE, "watch=3D%d events=3D%d", watch, events); @@ -159,17 +116,21 @@ void virEventPollUpdateHandle(int watch, int events) virMutexLock(&eventLoop.lock); for (i =3D 0; i < eventLoop.handlesCount; i++) { if (eventLoop.handles[i].watch =3D=3D watch) { - eventLoop.handles[i].events =3D - virEventPollToNativeEvents(events); - virEventPollInterruptLocked(); + eventLoop.handles[i].events =3D native; found =3D true; break; } } - virMutexUnlock(&eventLoop.lock); =20 - if (!found) + if (!found) { VIR_WARN("Got update for non-existent handle watch %d", watch); + } + else if (virEventPollUpdateHandleInternal(watch, + eventLoop.handles[i].fd, native) = < 0) { + VIR_WARN("Update for existing handle watch %d failed", watch); + } + + virMutexUnlock(&eventLoop.lock); } =20 /* @@ -196,15 +157,25 @@ int virEventPollRemoveHandle(int watch) continue; =20 if (eventLoop.handles[i].watch =3D=3D watch) { - EVENT_DEBUG("mark delete %zu %d", i, eventLoop.handles[i].fd); - eventLoop.handles[i].deleted =3D 1; - virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return 0; + break; } } + + if (i =3D=3D eventLoop.handlesCount) { + virMutexUnlock(&eventLoop.lock); + return -1; + } + + if (virEventPollRemoveHandleInternal(watch, eventLoop.handles[i].fd) <= 0) { + virMutexUnlock(&eventLoop.lock); + return -1; + } + + EVENT_DEBUG("mark delete %zu %d", i, eventLoop.handles[i].fd); + eventLoop.handles[i].deleted =3D 1; + virEventPollInterruptLocked(); virMutexUnlock(&eventLoop.lock); - return -1; + return 0; } =20 =20 @@ -374,44 +345,6 @@ static int virEventPollCalculateTimeout(int *timeout) } =20 /* - * Allocate a pollfd array containing data for all registered - * file handles. The caller must free the returned data struct - * returns: the pollfd array, or NULL on error - */ -static struct pollfd *virEventPollMakePollFDs(int *nfds) { - struct pollfd *fds; - size_t i; - - *nfds =3D 0; - for (i =3D 0; i < eventLoop.handlesCount; i++) { - if (eventLoop.handles[i].events && !eventLoop.handles[i].deleted) - (*nfds)++; - } - - /* Setup the poll file handle data structs */ - if (VIR_ALLOC_N(fds, *nfds) < 0) - return NULL; - - *nfds =3D 0; - for (i =3D 0; i < eventLoop.handlesCount; i++) { - EVENT_DEBUG("Prepare n=3D%zu w=3D%d, f=3D%d e=3D%d d=3D%d", i, - eventLoop.handles[i].watch, - eventLoop.handles[i].fd, - eventLoop.handles[i].events, - eventLoop.handles[i].deleted); - if (!eventLoop.handles[i].events || eventLoop.handles[i].deleted) - continue; - fds[*nfds].fd =3D eventLoop.handles[i].fd; - fds[*nfds].events =3D eventLoop.handles[i].events; - fds[*nfds].revents =3D 0; - (*nfds)++; - } - - return fds; -} - - -/* * Iterate over all timers and determine if any have expired. * Invoke the user supplied callback for each timer whose * expiry time is met, and schedule the next timeout. Does @@ -472,7 +405,7 @@ static int virEventPollDispatchTimeouts(void) * * Returns 0 upon success, -1 if an error occurred */ -static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) +static int virEventPollDispatchHandles(int nfds, void *opaque) { size_t i, n; VIR_DEBUG("Dispatch %d", nfds); @@ -480,14 +413,14 @@ static int virEventPollDispatchHandles(int nfds, stru= ct pollfd *fds) /* NB, use nfds not eventLoop.handlesCount, because new * fds might be added on end of list, and they're not * in the fds array we've got */ - for (i =3D 0, n =3D 0; n < nfds && i < eventLoop.handlesCount; n++) { - while (i < eventLoop.handlesCount && - (eventLoop.handles[i].fd !=3D fds[n].fd || - eventLoop.handles[i].events =3D=3D 0)) { - i++; + for (n =3D 0; n < nfds; n++) { + for (i =3D 0; i < eventLoop.handlesCount && + (eventLoop.handles[i].fd !=3D VirWokenFD(opaque, n) || + eventLoop.handles[i].events =3D=3D 0) ; i++) { + ; } if (i =3D=3D eventLoop.handlesCount) - break; + continue; =20 VIR_DEBUG("i=3D%zu w=3D%d", i, eventLoop.handles[i].watch); if (eventLoop.handles[i].deleted) { @@ -496,16 +429,16 @@ static int virEventPollDispatchHandles(int nfds, stru= ct pollfd *fds) continue; } =20 - if (fds[n].revents) { + if (VirWokenEvents(opaque, n)) { + int hEvents =3D virEventPollFromNativeEvents(VirWokenEvents(op= aque, n)); virEventHandleCallback cb =3D eventLoop.handles[i].cb; int watch =3D eventLoop.handles[i].watch; - void *opaque =3D eventLoop.handles[i].opaque; - int hEvents =3D virEventPollFromNativeEvents(fds[n].revents); + void *cbopaque =3D eventLoop.handles[i].opaque; PROBE(EVENT_POLL_DISPATCH_HANDLE, "watch=3D%d events=3D%d", watch, hEvents); virMutexUnlock(&eventLoop.lock); - (cb)(watch, fds[n].fd, hEvents, opaque); + (cb)(watch, VirWokenFD(opaque, n), hEvents, cbopaque); virMutexLock(&eventLoop.lock); } } @@ -618,8 +551,8 @@ static void virEventPollCleanupHandles(void) */ int virEventPollRunOnce(void) { - struct pollfd *fds =3D NULL; - int ret, timeout, nfds; + int nfds, timeout; + void *opaque =3D NULL; =20 virMutexLock(&eventLoop.lock); eventLoop.running =3D 1; @@ -628,33 +561,20 @@ int virEventPollRunOnce(void) virEventPollCleanupTimeouts(); virEventPollCleanupHandles(); =20 - if (!(fds =3D virEventPollMakePollFDs(&nfds)) || - virEventPollCalculateTimeout(&timeout) < 0) + if (virEventPollCalculateTimeout(&timeout) < 0) goto error; =20 virMutexUnlock(&eventLoop.lock); =20 - retry: - PROBE(EVENT_POLL_RUN, - "nhandles=3D%d timeout=3D%d", - nfds, timeout); - ret =3D poll(fds, nfds, timeout); - if (ret < 0) { - EVENT_DEBUG("Poll got error event %d", errno); - if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) - goto retry; - virReportSystemError(errno, "%s", - _("Unable to poll on file handles")); + if ((nfds =3D virEventPollWait(timeout, &opaque)) < 0) goto error_unlocked; - } - EVENT_DEBUG("Poll got %d event(s)", ret); + EVENT_DEBUG("Poll got %d event(s)", nfds); =20 virMutexLock(&eventLoop.lock); if (virEventPollDispatchTimeouts() < 0) goto error; =20 - if (ret > 0 && - virEventPollDispatchHandles(nfds, fds) < 0) + if (nfds > 0 && virEventPollDispatchHandles(nfds, opaque) < 0) goto error; =20 virEventPollCleanupTimeouts(); @@ -662,13 +582,13 @@ int virEventPollRunOnce(void) =20 eventLoop.running =3D 0; virMutexUnlock(&eventLoop.lock); - VIR_FREE(fds); + virEventPollOpaqueFree(opaque); return 0; =20 error: virMutexUnlock(&eventLoop.lock); error_unlocked: - VIR_FREE(fds); + virEventPollOpaqueFree(opaque); return -1; } =20 @@ -698,6 +618,12 @@ int virEventPollInit(void) return -1; } =20 + if (virEventPollInitInternal() < 0) { + VIR_FORCE_CLOSE(eventLoop.wakeupfd[0]); + VIR_FORCE_CLOSE(eventLoop.wakeupfd[1]); + return -1; + } + if (virEventPollAddHandle(eventLoop.wakeupfd[0], VIR_EVENT_HANDLE_READABLE, virEventPollHandleWakeup, NULL, NULL) < 0) { @@ -706,13 +632,14 @@ int virEventPollInit(void) eventLoop.wakeupfd[0]); VIR_FORCE_CLOSE(eventLoop.wakeupfd[0]); VIR_FORCE_CLOSE(eventLoop.wakeupfd[1]); + virEventPollDeinitInternal(); return -1; } =20 return 0; } =20 -static int virEventPollInterruptLocked(void) +int virEventPollInterruptLocked(void) { char c =3D '\0'; =20 @@ -737,35 +664,3 @@ int virEventPollInterrupt(void) virMutexUnlock(&eventLoop.lock); return ret; } - -int -virEventPollToNativeEvents(int events) -{ - int ret =3D 0; - if (events & VIR_EVENT_HANDLE_READABLE) - ret |=3D POLLIN; - if (events & VIR_EVENT_HANDLE_WRITABLE) - ret |=3D POLLOUT; - if (events & VIR_EVENT_HANDLE_ERROR) - ret |=3D POLLERR; - if (events & VIR_EVENT_HANDLE_HANGUP) - ret |=3D POLLHUP; - return ret; -} - -int -virEventPollFromNativeEvents(int events) -{ - int ret =3D 0; - if (events & POLLIN) - ret |=3D VIR_EVENT_HANDLE_READABLE; - if (events & POLLOUT) - ret |=3D VIR_EVENT_HANDLE_WRITABLE; - if (events & POLLERR) - ret |=3D VIR_EVENT_HANDLE_ERROR; - if (events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't d= istinguish */ - ret |=3D VIR_EVENT_HANDLE_ERROR; - if (events & POLLHUP) - ret |=3D VIR_EVENT_HANDLE_HANGUP; - return ret; -} diff --git a/src/util/vireventpollinternal.h b/src/util/vireventpollinterna= l.h new file mode 100644 index 0000000..19d2fd9 --- /dev/null +++ b/src/util/vireventpollinternal.h @@ -0,0 +1,91 @@ +/* + * vireventpoll.h: Poll based event loop for monitoring file handles + * + * Copyright (C) 2007 Daniel P. Berrange + * Copyright (C) 2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#ifndef __VIR_EVENT_POLL_INTERNAL_H__ +# define __VIR_EVENT_POLL_INTERNAL_H__ + +# include "internal.h" +#include "virthread.h" + +int virEventPollInterruptLocked(void); + +/* State for a single file handle being monitored */ +struct virEventPollHandle { + int watch; + int fd; + int events; + virEventHandleCallback cb; + virFreeCallback ff; + void *opaque; + int deleted; +}; + +/* State for a single timer being generated */ +struct virEventPollTimeout { + int timer; + int frequency; + unsigned long long expiresAt; + virEventTimeoutCallback cb; + virFreeCallback ff; + void *opaque; + int deleted; +}; + +/* Allocate extra slots for virEventPollHandle/virEventPollTimeout + records in this multiple */ +#define EVENT_ALLOC_EXTENT 10 + +/* State for the main event loop */ +struct virEventPollLoop { + virMutex lock; + int running; + virThread leader; + int wakeupfd[2]; + size_t handlesCount; + size_t handlesAlloc; + struct virEventPollHandle *handles; + size_t timeoutsCount; + size_t timeoutsAlloc; + struct virEventPollTimeout *timeouts; +}; + +/* Only have one event loop */ +extern struct virEventPollLoop eventLoop; + +/* Unique ID for the next FD watch to be registered */ +extern int nextWatch; + +/* Unique ID for the next timer to be registered */ +extern int nextTimer; + +int virEventPollAddHandleInternal(int watch, int fd, int nativeevents); +int virEventPollUpdateHandleInternal(int watch, int fd, int nativeevents); +int virEventPollRemoveHandleInternal(int watch, int fd); +int virEventPollInitInternal(void); +void virEventPollDeinitInternal(void); +int virEventPollWait(int timeout, void **opaque); +void virEventPollOpaqueFree(void *opaque); +int VirWokenFD(void *opaque, size_t n); +int VirWokenEvents(void *opaque, size_t n); + +#endif /* __VIR_EVENT_POLL_INTERNAL_H__ */ --=20 1.9.5.msysgit.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Mon Apr 29 18:43:37 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.24 as permitted sender) client-ip=209.132.183.24; envelope-from=libvir-list-bounces@redhat.com; helo=mx3-phx2.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.24 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx3-phx2.redhat.com (mx3-phx2.redhat.com [209.132.183.24]) by mx.zohomail.com with SMTPS id 1487095816543470.82725640687613; Tue, 14 Feb 2017 10:10:16 -0800 (PST) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx3-phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v1EI6CMe002245; Tue, 14 Feb 2017 13:06:12 -0500 Received: from smtp.corp.redhat.com (int-mx16.intmail.prod.int.phx2.redhat.com [10.5.11.28]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v1EI6BY0016209 for ; Tue, 14 Feb 2017 13:06:11 -0500 Received: by smtp.corp.redhat.com (Postfix) id 3E62A6E902; Tue, 14 Feb 2017 18:06:11 +0000 (UTC) Received: from mx1.redhat.com (ext-mx02.extmail.prod.ext.phx2.redhat.com [10.5.110.26]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 371366E7A9 for ; Tue, 14 Feb 2017 18:06:11 +0000 (UTC) Received: from relay.sw.ru (mailhub.sw.ru [195.214.232.25]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E2EC47E9F8 for ; Tue, 14 Feb 2017 18:06:08 +0000 (UTC) Received: from localhost.localdomain (msk-vpn.virtuozzo.com [195.214.232.6]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id v1EI63DS028411; Tue, 14 Feb 2017 21:06:03 +0300 (MSK) From: Derbyshev Dmitriy To: libvir-list@redhat.com Date: Tue, 14 Feb 2017 21:04:21 +0300 Message-Id: <1487095461-12268-3-git-send-email-dderbyshev@virtuozzo.com> In-Reply-To: <1487095461-12268-1-git-send-email-dderbyshev@virtuozzo.com> References: <1487095461-12268-1-git-send-email-dderbyshev@virtuozzo.com> X-Greylist: Delayed for 100:34:54 by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 14 Feb 2017 18:06:09 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 14 Feb 2017 18:06:09 +0000 (UTC) for IP:'195.214.232.25' DOMAIN:'mailhub.sw.ru' HELO:'relay.sw.ru' FROM:'dderbyshev@virtuozzo.com' RCPT:'' X-RedHat-Spam-Score: 0.799 (BAYES_50, SPF_PASS) 195.214.232.25 mailhub.sw.ru 195.214.232.25 mailhub.sw.ru X-Scanned-By: MIMEDefang 2.78 on 10.5.110.26 X-Scanned-By: MIMEDefang 2.74 on 10.5.11.28 X-loop: libvir-list@redhat.com Cc: redkoi@virtuozzo.com, Derbyshev Dmitry , den@virtuozzo.com, kneumoin@virtuozzo.com, mnestratov@virtuozzo.com, nshirokovskiy@virtuozzo.com Subject: [libvirt] [RFC v2 2/2] vireventpoll implimentation using epoll X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Derbyshev Dmitry This makes it possible to avoid allocations in virEventPollMakePollFDs, as well as generally reduces time spent in kernel if handles remain the same, which should generally be true. --- configure.ac | 28 ++++ src/Makefile.am | 10 +- src/util/vireventepoll.c | 201 +++++++++++++++++++= ++++ tests/commanddata/{test14.log =3D> test3epoll.log} | 2 + tests/commandtest.c | 4 + 5 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 src/util/vireventepoll.c copy tests/commanddata/{test14.log =3D> test3epoll.log} (94%) diff --git a/configure.ac b/configure.ac index a995a05..9a6a810 100644 --- a/configure.ac +++ b/configure.ac @@ -877,6 +877,34 @@ AC_DEFINE_UNQUOTED([isbase64],[libvirt_gl_isbase64],[H= ack to avoid symbol clash] AC_DEFINE_UNQUOTED([base64_encode],[libvirt_gl_base64_encode],[Hack to avo= id symbol clash]) AC_DEFINE_UNQUOTED([base64_encode_alloc],[libvirt_gl_base64_encode_alloc],= [Hack to avoid symbol clash]) =20 +AC_ARG_ENABLE([epoll], + [AS_HELP_STRING([--enable-epoll],[use epoll(4) on Linux])], + [enable_epoll=3D$enableval], [enable_epoll=3Dauto]) +if test x$enable_epoll =3D xno; then + have_linux_epoll=3Dno +else + AC_MSG_CHECKING([for Linux epoll(4)]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [ + #ifndef __linux__ + #error This is not Linux + #endif + #include + ], + [epoll_create1 (EPOLL_CLOEXEC);])], + [have_linux_epoll=3Dyes], + [have_linux_epoll=3Dno]) + AC_MSG_RESULT([$have_linux_epoll]) +fi +if test x$enable_epoll,$have_linux_epoll =3D xyes,no; then + AC_MSG_ERROR([epoll support explicitly enabled but not available]) +fi +if test "x$have_linux_epoll" =3D xyes; then + AC_DEFINE_UNQUOTED([HAVE_LINUX_EPOLL], 1, [whether epoll is supported]) +fi + +AM_CONDITIONAL([HAVE_LINUX_EPOLL], [test "x$have_linux_epoll" =3D xyes]) + AC_CONFIG_FILES([run], [chmod +x,-w run]) AC_CONFIG_FILES([\ diff --git a/src/Makefile.am b/src/Makefile.am index f2643ea..9ad39cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,6 +89,12 @@ augeas_DATA =3D augeastestdir =3D $(datadir)/augeas/lenses/tests augeastest_DATA =3D =20 +if HAVE_LINUX_EPOLL +poll_src=3Dutil/vireventepoll.c +else !HAVE_LINUX_EPOLL +poll_src=3Dutil/vireventpoll.c +endif !HAVE_LINUX_EPOLL + # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES =3D \ @@ -113,7 +119,7 @@ UTIL_SOURCES =3D \ util/virerror.c util/virerror.h \ util/virevent.c util/virevent.h \ util/vireventpollcommon.c util/vireventpoll.h \ - util/vireventpoll.c util/vireventpollinternal.h \ + $(poll_src) util/vireventpollinternal.h \ util/virfile.c util/virfile.h \ util/virfirewall.c util/virfirewall.h \ util/virfirewallpriv.h \ @@ -2376,7 +2382,7 @@ libvirt_setuid_rpc_client_la_SOURCES =3D \ util/virdbus.c \ util/virerror.c \ util/virevent.c \ - util/vireventpoll.c \ + $(poll_src) \ util/vireventpollcommon.c \ util/virfile.c \ util/virgettext.c \ diff --git a/src/util/vireventepoll.c b/src/util/vireventepoll.c new file mode 100644 index 0000000..5e2a0f5 --- /dev/null +++ b/src/util/vireventepoll.c @@ -0,0 +1,201 @@ +/* + * vireventpoll.c: Poll based event loop for monitoring file handles + * + * Copyright (C) 2007, 2010-2014 Red Hat, Inc. + * Copyright (C) 2007 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel P. Berrange + */ + +#include + +#include + +#include "virfile.h" +#include "virlog.h" +#include "vireventpoll.h" +#include "vireventpollinternal.h" + +#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) + +#define VIR_FROM_THIS VIR_FROM_EVENT + +VIR_LOG_INIT("util.eventpoll"); + +/* Maximum number of events that are returned by epoll in virEventPollRunO= nce */ +#define MAX_POLL_EVENTS_AT_ONCE 10 + +int epollfd; + +int virEventPollAddHandleInternal(int watch ATTRIBUTE_UNUSED, + int fd, + int nativeevents) +{ + size_t i; + struct epoll_event ev; + ev.events =3D nativeevents; + ev.data.fd =3D fd; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) { + if (errno =3D=3D EEXIST) { + for (i =3D 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd =3D=3D fd && + !eventLoop.handles[i].deleted) { + ev.events |=3D eventLoop.handles[i].events; + } + } + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + } + else { + return -1; + } + } + return 0; +} + +int virEventPollUpdateHandleInternal(int watch, int fd, int nativeevents) +{ + struct epoll_event ev; + size_t i; + + ev.events =3D nativeevents; + ev.data.fd =3D fd; + for (i =3D 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd =3D=3D fd && + !eventLoop.handles[i].deleted && + eventLoop.handles[i].watch !=3D watch) { + ev.events |=3D eventLoop.handles[i].events; + } + } + + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + return 0; +} + +int virEventPollRemoveHandleInternal(int watch, int fd) +{ + + struct epoll_event ev; + size_t i; + + ev.events =3D 0; + ev.data.fd =3D fd; + for (i =3D 0; i < eventLoop.handlesCount; i++) { + if (eventLoop.handles[i].fd =3D=3D fd && + !eventLoop.handles[i].deleted && + eventLoop.handles[i].watch !=3D watch) { + ev.events |=3D eventLoop.handles[i].events; + } + } + + if (ev.events) { + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + } + else { + if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev) < 0) { + return -1; + } + } + + return 0; +} + +int virEventPollInitInternal(void) +{ + epollfd =3D epoll_create1(0); + if (epollfd < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to initialize epoll")); + return -1; + } + return 0; +} + +void virEventPollDeinitInternal(void) +{ + VIR_FORCE_CLOSE(epollfd); +} + +int +virEventPollToNativeEvents(int events) +{ + int ret =3D 0; + if (events & VIR_EVENT_HANDLE_READABLE) + ret |=3D EPOLLIN; + if (events & VIR_EVENT_HANDLE_WRITABLE) + ret |=3D EPOLLOUT; + if (events & VIR_EVENT_HANDLE_ERROR) + ret |=3D EPOLLERR; + if (events & VIR_EVENT_HANDLE_HANGUP) + ret |=3D EPOLLHUP; + return ret; +} + +int +virEventPollFromNativeEvents(int events) +{ + int ret =3D 0; + if (events & EPOLLIN) + ret |=3D VIR_EVENT_HANDLE_READABLE; + if (events & EPOLLOUT) + ret |=3D VIR_EVENT_HANDLE_WRITABLE; + if (events & EPOLLERR) + ret |=3D VIR_EVENT_HANDLE_ERROR; + if (events & EPOLLHUP) + ret |=3D VIR_EVENT_HANDLE_HANGUP; + return ret; +} + +struct epoll_event events[MAX_POLL_EVENTS_AT_ONCE]; + +int virEventPollWait(int timeout, void **opaque) +{ + int ret; + *opaque =3D events; + + retry: + ret =3D epoll_wait(epollfd, events, + MAX_POLL_EVENTS_AT_ONCE, timeout); + if (ret < 0) { + EVENT_DEBUG("Poll got error event %d", errno); + if (errno =3D=3D EINTR || errno =3D=3D EAGAIN) + goto retry; + virReportSystemError(errno, "%s", + _("Unable to poll on file handles")); + } + return ret; +} + +void virEventPollOpaqueFree(void *opaque ATTRIBUTE_UNUSED) +{ + return; +} + +int VirWokenFD(void *opaque, size_t n) +{ + return ((struct epoll_event *)opaque)[n].data.fd; +} + +int VirWokenEvents(void *opaque, size_t n) +{ + return ((struct epoll_event *)opaque)[n].events; +} diff --git a/tests/commanddata/test14.log b/tests/commanddata/test3epoll.log similarity index 94% copy from tests/commanddata/test14.log copy to tests/commanddata/test3epoll.log index 703e6da..e4619b3 100644 --- a/tests/commanddata/test14.log +++ b/tests/commanddata/test3epoll.log @@ -8,6 +8,8 @@ ENV:USER=3Dtest FD:0 FD:1 FD:2 +FD:6 +FD:8 DAEMON:no CWD:/tmp UMASK:0022 diff --git a/tests/commandtest.c b/tests/commandtest.c index 7bf5447..6b23659 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -227,7 +227,11 @@ static int test3(const void *unused ATTRIBUTE_UNUSED) goto cleanup; } =20 +#ifdef HAVE_LINUX_EPOLL + ret =3D checkoutput("test3epoll", NULL); +#else ret =3D checkoutput("test3", NULL); +#endif =20 cleanup: virCommandFree(cmd); --=20 1.9.5.msysgit.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list