mirror of
				https://github.com/openvswitch/ovs
				synced 2025-10-29 15:28:56 +00:00 
			
		
		
		
	poll-loop: Make poll loop data structures per-thread.
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
		
							
								
								
									
										108
									
								
								lib/poll-loop.c
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								lib/poll-loop.c
									
									
									
									
									
								
							| @@ -25,6 +25,7 @@ | ||||
| #include "dynamic-string.h" | ||||
| #include "fatal-signal.h" | ||||
| #include "list.h" | ||||
| #include "ovs-thread.h" | ||||
| #include "socket-util.h" | ||||
| #include "timeval.h" | ||||
| #include "vlog.h" | ||||
| @@ -39,25 +40,20 @@ VLOG_DEFINE_THIS_MODULE(poll_loop); | ||||
| COVERAGE_DEFINE(poll_fd_wait); | ||||
| COVERAGE_DEFINE(poll_zero_timeout); | ||||
|  | ||||
| /* An event that will wake the following call to poll_block(). */ | ||||
| struct poll_waiter { | ||||
|     const char *where;          /* Where the waiter was created. */ | ||||
| struct poll_loop { | ||||
|     /* All active poll waiters. */ | ||||
|     struct pollfd *pollfds;     /* Events to pass to poll(). */ | ||||
|     const char **where;         /* Where each pollfd was created. */ | ||||
|     size_t n_waiters;           /* Number of elems in 'where' and 'pollfds'. */ | ||||
|     size_t allocated_waiters;   /* Allocated elems in 'where' and 'pollfds'. */ | ||||
|  | ||||
|     /* Time at which to wake up the next call to poll_block(), LLONG_MIN to | ||||
|      * wake up immediately, or LLONG_MAX to wait forever. */ | ||||
|     long long int timeout_when; /* In msecs as returned by time_msec(). */ | ||||
|     const char *timeout_where;  /* Where 'timeout_when' was set. */ | ||||
| }; | ||||
|  | ||||
| /* All active poll waiters. */ | ||||
| static struct poll_waiter *waiters; | ||||
| static struct pollfd *pollfds; | ||||
| static size_t n_waiters, allocated_waiters; | ||||
|  | ||||
| /* Time at which to wake up the next call to poll_block(), in milliseconds as | ||||
|  * returned by time_msec(), LLONG_MIN to wake up immediately, or LLONG_MAX to | ||||
|  * wait forever. */ | ||||
| static long long int timeout_when = LLONG_MAX; | ||||
|  | ||||
| /* Location where waiter created. */ | ||||
| static const char *timeout_where; | ||||
|  | ||||
| static void new_waiter(int fd, short int events, const char *where); | ||||
| static struct poll_loop *poll_loop(void); | ||||
|  | ||||
| /* Registers 'fd' as waiting for the specified 'events' (which should be POLLIN | ||||
|  * or POLLOUT or POLLIN | POLLOUT).  The following call to poll_block() will | ||||
| @@ -72,8 +68,21 @@ static void new_waiter(int fd, short int events, const char *where); | ||||
| void | ||||
| poll_fd_wait(int fd, short int events, const char *where) | ||||
| { | ||||
|     struct poll_loop *loop = poll_loop(); | ||||
|  | ||||
|     COVERAGE_INC(poll_fd_wait); | ||||
|     new_waiter(fd, events, where); | ||||
|     if (loop->n_waiters >= loop->allocated_waiters) { | ||||
|         loop->where = x2nrealloc(loop->where, &loop->allocated_waiters, | ||||
|                                  sizeof *loop->where); | ||||
|         loop->pollfds = xrealloc(loop->pollfds, | ||||
|                                  (loop->allocated_waiters | ||||
|                                   * sizeof *loop->pollfds)); | ||||
|     } | ||||
|  | ||||
|     loop->where[loop->n_waiters] = where; | ||||
|     loop->pollfds[loop->n_waiters].fd = fd; | ||||
|     loop->pollfds[loop->n_waiters].events = events; | ||||
|     loop->n_waiters++; | ||||
| } | ||||
|  | ||||
| /* Causes the following call to poll_block() to block for no more than 'msec' | ||||
| @@ -120,9 +129,10 @@ poll_timer_wait(long long int msec, const char *where) | ||||
| void | ||||
| poll_timer_wait_until(long long int when, const char *where) | ||||
| { | ||||
|     if (when < timeout_when) { | ||||
|         timeout_when = when; | ||||
|         timeout_where = where; | ||||
|     struct poll_loop *loop = poll_loop(); | ||||
|     if (when < loop->timeout_when) { | ||||
|         loop->timeout_when = when; | ||||
|         loop->timeout_where = where; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -204,6 +214,7 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout) | ||||
| void | ||||
| poll_block(void) | ||||
| { | ||||
|     struct poll_loop *loop = poll_loop(); | ||||
|     int elapsed; | ||||
|     int retval; | ||||
|  | ||||
| @@ -211,45 +222,62 @@ poll_block(void) | ||||
|      * poll_block. */ | ||||
|     fatal_signal_wait(); | ||||
|  | ||||
|     if (timeout_when == LLONG_MIN) { | ||||
|     if (loop->timeout_when == LLONG_MIN) { | ||||
|         COVERAGE_INC(poll_zero_timeout); | ||||
|     } | ||||
|     retval = time_poll(pollfds, n_waiters, timeout_when, &elapsed); | ||||
|  | ||||
|     retval = time_poll(loop->pollfds, loop->n_waiters, | ||||
|                        loop->timeout_when, &elapsed); | ||||
|     if (retval < 0) { | ||||
|         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | ||||
|         VLOG_ERR_RL(&rl, "poll: %s", ovs_strerror(-retval)); | ||||
|     } else if (!retval) { | ||||
|         log_wakeup(timeout_where, NULL, elapsed); | ||||
|         log_wakeup(loop->timeout_where, NULL, elapsed); | ||||
|     } else if (get_cpu_usage() > 50 || VLOG_IS_DBG_ENABLED()) { | ||||
|         size_t i; | ||||
|  | ||||
|         for (i = 0; i < n_waiters; i++) { | ||||
|             if (pollfds[i].revents) { | ||||
|                 log_wakeup(waiters[i].where, &pollfds[i], 0); | ||||
|         for (i = 0; i < loop->n_waiters; i++) { | ||||
|             if (loop->pollfds[i].revents) { | ||||
|                 log_wakeup(loop->where[i], &loop->pollfds[i], 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     timeout_when = LLONG_MAX; | ||||
|     timeout_where = NULL; | ||||
|     n_waiters = 0; | ||||
|     loop->timeout_when = LLONG_MAX; | ||||
|     loop->timeout_where = NULL; | ||||
|     loop->n_waiters = 0; | ||||
|  | ||||
|     /* Handle any pending signals before doing anything else. */ | ||||
|     fatal_signal_run(); | ||||
| } | ||||
|  | ||||
| /* Creates a new poll_waiter for 'fd' and 'events', recording 'where' as the | ||||
|  * location where the event was registered. */ | ||||
| static void | ||||
| new_waiter(int fd, short int events, const char *where) | ||||
| free_poll_loop(void *loop_) | ||||
| { | ||||
|     if (n_waiters >= allocated_waiters) { | ||||
|         waiters = x2nrealloc(waiters, &allocated_waiters, sizeof *waiters); | ||||
|         pollfds = xrealloc(pollfds, allocated_waiters * sizeof *pollfds); | ||||
|     struct poll_loop *loop = loop_; | ||||
|  | ||||
|     free(loop->pollfds); | ||||
|     free(loop->where); | ||||
|     free(loop); | ||||
| } | ||||
|  | ||||
|     waiters[n_waiters].where = where; | ||||
|     pollfds[n_waiters].fd = fd; | ||||
|     pollfds[n_waiters].events = events; | ||||
|     n_waiters++; | ||||
| static struct poll_loop * | ||||
| poll_loop(void) | ||||
| { | ||||
|     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; | ||||
|     static pthread_key_t key; | ||||
|     struct poll_loop *loop; | ||||
|  | ||||
|     if (ovsthread_once_start(&once)) { | ||||
|         xpthread_key_create(&key, free_poll_loop); | ||||
|         ovsthread_once_done(&once); | ||||
|     } | ||||
|  | ||||
|     loop = pthread_getspecific(key); | ||||
|     if (!loop) { | ||||
|         loop = xzalloc(sizeof *loop); | ||||
|         pthread_setspecific(key, loop); | ||||
|     } | ||||
|     return loop; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. | ||||
|  * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
| @@ -16,14 +16,20 @@ | ||||
|  | ||||
| /* High-level wrapper around the "poll" system call. | ||||
|  * | ||||
|  * Intended usage is for the program's main loop to go about its business | ||||
|  * The intended usage is for each thread's main loop to go about its business | ||||
|  * servicing whatever events it needs to.  Then, when it runs out of immediate | ||||
|  * tasks, it calls each subordinate module's "wait" function, which in turn | ||||
|  * calls one (or more) of the functions poll_fd_wait(), poll_immediate_wake(), | ||||
|  * and poll_timer_wait() to register to be awakened when the appropriate event | ||||
|  * occurs.  Then the main loop calls poll_block(), which blocks until one of | ||||
|  * the registered events happens. */ | ||||
|  | ||||
|  * the registered events happens. | ||||
|  * | ||||
|  * | ||||
|  * Thread-safety | ||||
|  * ============= | ||||
|  * | ||||
|  * The poll set is per-thread, so all functions in this module are thread-safe. | ||||
|  */ | ||||
| #ifndef POLL_LOOP_H | ||||
| #define POLL_LOOP_H 1 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user