All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
as_event.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2017 Aerospike, Inc.
3  *
4  * Portions may be licensed to Aerospike, Inc. under one or more contributor
5  * license agreements.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8  * use this file except in compliance with the License. You may obtain a copy of
9  * the License at http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 #pragma once
18 
19 #include <aerospike/as_queue.h>
20 #include <pthread.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 
25 /**
26  * @defgroup async_events Event Framework Abstraction
27  *
28  * Generic asynchronous events abstraction. Designed to support multiple event libraries.
29  * Only one library is supported per build.
30  */
31 #define AS_EVENT_LIB_DEFINED (defined(AS_USE_LIBEV) || defined(AS_USE_LIBUV) || defined(AS_USE_LIBEVENT))
32 
33 #if defined(AS_USE_LIBEV)
34 #include <ev.h>
35 #elif defined(AS_USE_LIBUV)
36 #include <uv.h>
37 #elif defined(AS_USE_LIBEVENT)
38 #include <event2/event_struct.h>
39 #else
40 #endif
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 /******************************************************************************
47  * TYPES
48  *****************************************************************************/
49 
50 /**
51  * Generic asynchronous event loop abstraction. There is one event loop per thread.
52  * Event loops can be created by the client, or be referenced to externally created event loops.
53  *
54  * @ingroup async_events
55  */
56 typedef struct as_event_loop {
57 #if defined(AS_USE_LIBEV)
58  struct ev_loop* loop;
59  struct ev_async wakeup;
60 #elif defined(AS_USE_LIBUV)
61  uv_loop_t* loop;
62  uv_async_t* wakeup;
63 #elif defined(AS_USE_LIBEVENT)
64  struct event_base* loop;
65  struct event wakeup;
66 #else
67  void* loop;
68 #endif
69 
71  pthread_mutex_t lock;
74  pthread_t thread;
75  uint32_t index;
76  // Count of consecutive errors occurring before event loop registration.
77  // Used to prevent deep recursion.
78  uint32_t errors;
81 
82 /******************************************************************************
83  * GLOBAL VARIABLES
84  *****************************************************************************/
85 
88 extern uint32_t as_event_loop_size;
89 
90 /******************************************************************************
91  * PUBLIC FUNCTIONS
92  *****************************************************************************/
93 
94 /**
95  * Create new event loops. This method should only be called when asynchronous client commands
96  * will be used and the calling program itself is not asynchronous. If this method is used,
97  * it must be called before aerospike_connect().
98  *
99  * @param capacity Number of event loops to create.
100  * @return Event loop array.
101  *
102  * @ingroup async_events
103  */
105 as_event_create_loops(uint32_t capacity);
106 
107 /**
108  * Set the number of externally created event loops. This method should be called when the
109  * calling program wants to share event loops with the client. This reduces resource usage and
110  * can increase performance.
111  *
112  * This method is used in conjunction with as_event_set_external_loop() to fully define the
113  * the external loop to the client and obtain a reference the client's event loop abstraction.
114  *
115  * ~~~~~~~~~~{.c}
116  * struct {
117  * pthread_t thread;
118  * struct ev_loop* loop;
119  * as_event_loop* as_loop;
120  * } my_loop;
121  *
122  * static void* my_loop_worker_thread(void* udata) {
123  * struct my_loop* myloop = udata;
124  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
125  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
126  * ev_loop(myloop->loop, 0);
127  * ev_loop_destroy(myloop->loop);
128  * return NULL;
129  * }
130  *
131  * int capacity = 8;
132  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
133  * as_event_set_external_loop_capacity(capacity);
134  *
135  * for (int i = 0; i < capacity; i++) {
136  * struct my_loop* myloop = &loops[i];
137  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
138  * }
139  * ~~~~~~~~~~
140  *
141  * @param capacity Number of externally created event loops.
142  * @return True if all external loops were initialized.
143  *
144  * @ingroup async_events
145  */
146 bool
147 as_event_set_external_loop_capacity(uint32_t capacity);
148 
149 /**
150  * Register an external event loop with the client. This method should be called when the
151  * calling program wants to share event loops with the client. This reduces resource usage and
152  * can increase performance.
153  *
154  * This method must be called in the same thread as the event loop that is being registered.
155  *
156  * This method is used in conjunction with as_event_set_external_loop_capacity() to fully define
157  * the external loop to the client and obtain a reference the client's event loop abstraction.
158  *
159  * ~~~~~~~~~~{.c}
160  * struct {
161  * pthread_t thread;
162  * struct ev_loop* loop;
163  * as_event_loop* as_loop;
164  * } my_loop;
165  *
166  * static void* my_loop_worker_thread(void* udata) {
167  * struct my_loop* myloop = udata;
168  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
169  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
170  * ev_loop(myloop->loop, 0);
171  * ev_loop_destroy(myloop->loop);
172  * return NULL;
173  * }
174  *
175  * int capacity = 8;
176  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
177  * as_event_set_external_loop_capacity(capacity);
178  *
179  * for (int i = 0; i < capacity; i++) {
180  * struct my_loop* myloop = &loops[i];
181  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
182  * }
183  * ~~~~~~~~~~
184  *
185  * @param loop External event loop.
186  * @return Client's generic event loop abstraction that is used in client async commands.
187  * Returns NULL if external loop capacity would be exceeded.
188  *
189  * @ingroup async_events
190  */
193 
194 /**
195  * Find client's event loop abstraction given the external event loop.
196  *
197  * @param loop External event loop.
198  * @return Client's generic event loop abstraction that is used in client async commands.
199  * Returns NULL if loop not found.
200  *
201  * @ingroup async_events
202  */
204 as_event_loop_find(void* loop);
205 
206 /**
207  * Retrieve event loop by array index.
208  *
209  * @param index Event loop array index.
210  * @return Client's generic event loop abstraction that is used in client async commands.
211  *
212  * @ingroup async_events
213  */
214 static inline as_event_loop*
216 {
217  return index < as_event_loop_size ? &as_event_loops[index] : NULL;
218 }
219 
220 /**
221  * Retrieve a random event loop using round robin distribution.
222  *
223  * @return Client's generic event loop abstraction that is used in client async commands.
224  *
225  * @ingroup async_events
226  */
227 static inline as_event_loop*
229 {
230  // The last event loop points to the first event loop to create a circular linked list.
231  // Not atomic because doesn't need to be exactly accurate.
232  as_event_loop* event_loop = as_event_loop_current;
233  as_event_loop_current = event_loop->next;
234  return event_loop;
235 }
236 
237 /**
238  * Close internal event loops and release watchers for internal and external event loops.
239  * The global event loop array will also be destroyed for internal event loops.
240  *
241  * This method should be called once on program shutdown if as_event_create_loops() or
242  * as_event_set_external_loop_capacity() was called.
243  *
244  * The shutdown sequence is slightly different for internal and external event loops.
245  *
246  * Internal:
247  * ~~~~~~~~~~{.c}
248  * as_event_close_loops();
249  * ~~~~~~~~~~
250  *
251  * External:
252  * ~~~~~~~~~~{.c}
253  * as_event_close_loops();
254  * Join on external loop threads.
255  * as_event_destroy_loops();
256  * ~~~~~~~~~~
257  *
258  * @return True if event loop close was successful. If false, as_event_destroy_loops() should
259  * not be called.
260  *
261  * @ingroup async_events
262  */
263 bool
265 
266 /**
267  * Destroy global event loop array. This function only needs to be called for external
268  * event loops.
269  *
270  * @ingroup async_events
271  */
272 void
274 
275 #ifdef __cplusplus
276 } // end extern "C"
277 #endif