… | |
… | |
2070 | C<ev_async_sent> calls). |
2070 | C<ev_async_sent> calls). |
2071 | |
2071 | |
2072 | Unlike C<ev_signal> watchers, C<ev_async> works with any event loop, not |
2072 | Unlike C<ev_signal> watchers, C<ev_async> works with any event loop, not |
2073 | just the default loop. |
2073 | just the default loop. |
2074 | |
2074 | |
|
|
2075 | =head3 Queueing |
|
|
2076 | |
|
|
2077 | C<ev_async> does not support queueing of data in any way. The reason |
|
|
2078 | is that the author does not know of a simple (or any) algorithm for a |
|
|
2079 | multiple-writer-single-reader queue that works in all cases and doesn't |
|
|
2080 | need elaborate support such as pthreads. |
|
|
2081 | |
|
|
2082 | That means that if you want to queue data, you have to provide your own |
|
|
2083 | queue. And here is how you would implement locking: |
|
|
2084 | |
|
|
2085 | =over 4 |
|
|
2086 | |
|
|
2087 | =item queueing from a signal handler context |
|
|
2088 | |
|
|
2089 | To implement race-free queueing, you simply add to the queue in the signal |
|
|
2090 | handler but you block the signal handler in the watcher callback. Here is an example that does that for |
|
|
2091 | some fictitiuous SIGUSR1 handler: |
|
|
2092 | |
|
|
2093 | static ev_async mysig; |
|
|
2094 | |
|
|
2095 | static void |
|
|
2096 | sigusr1_handler (void) |
|
|
2097 | { |
|
|
2098 | sometype data; |
|
|
2099 | |
|
|
2100 | // no locking etc. |
|
|
2101 | queue_put (data); |
|
|
2102 | ev_async_send (DEFAULT_LOOP, &mysig); |
|
|
2103 | } |
|
|
2104 | |
|
|
2105 | static void |
|
|
2106 | mysig_cb (EV_P_ ev_async *w, int revents) |
|
|
2107 | { |
|
|
2108 | sometype data; |
|
|
2109 | sigset_t block, prev; |
|
|
2110 | |
|
|
2111 | sigemptyset (&block); |
|
|
2112 | sigaddset (&block, SIGUSR1); |
|
|
2113 | sigprocmask (SIG_BLOCK, &block, &prev); |
|
|
2114 | |
|
|
2115 | while (queue_get (&data)) |
|
|
2116 | process (data); |
|
|
2117 | |
|
|
2118 | if (sigismember (&prev, SIGUSR1) |
|
|
2119 | sigprocmask (SIG_UNBLOCK, &block, 0); |
|
|
2120 | } |
|
|
2121 | |
|
|
2122 | (Note: pthreads in theory requires you to use C<pthread_setmask> |
|
|
2123 | instead of C<sigprocmask> when you use threads, but libev doesn't do it |
|
|
2124 | either...). |
|
|
2125 | |
|
|
2126 | =item queueing from a thread context |
|
|
2127 | |
|
|
2128 | The strategy for threads is different, as you cannot (easily) block |
|
|
2129 | threads but you can easily preempt them, so to queue safely you need to |
|
|
2130 | emply a traditional mutex lock, such as in this pthread example: |
|
|
2131 | |
|
|
2132 | static ev_async mysig; |
|
|
2133 | static pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; |
|
|
2134 | |
|
|
2135 | static void |
|
|
2136 | otherthread (void) |
|
|
2137 | { |
|
|
2138 | // only need to lock the actual queueing operation |
|
|
2139 | pthread_mutex_lock (&mymutex); |
|
|
2140 | queue_put (data); |
|
|
2141 | pthread_mutex_unlock (&mymutex); |
|
|
2142 | |
|
|
2143 | ev_async_send (DEFAULT_LOOP, &mysig); |
|
|
2144 | } |
|
|
2145 | |
|
|
2146 | static void |
|
|
2147 | mysig_cb (EV_P_ ev_async *w, int revents) |
|
|
2148 | { |
|
|
2149 | pthread_mutex_lock (&mymutex); |
|
|
2150 | |
|
|
2151 | while (queue_get (&data)) |
|
|
2152 | process (data); |
|
|
2153 | |
|
|
2154 | pthread_mutex_unlock (&mymutex); |
|
|
2155 | } |
|
|
2156 | |
|
|
2157 | =back |
|
|
2158 | |
|
|
2159 | |
2075 | =head3 Watcher-Specific Functions and Data Members |
2160 | =head3 Watcher-Specific Functions and Data Members |
2076 | |
2161 | |
2077 | =over 4 |
2162 | =over 4 |
2078 | |
2163 | |
2079 | =item ev_async_init (ev_async *, callback) |
2164 | =item ev_async_init (ev_async *, callback) |