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 Asynchronous Event 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;
78 
79 /******************************************************************************
80  * GLOBAL VARIABLES
81  *****************************************************************************/
82 
85 extern uint32_t as_event_loop_size;
86 
87 /******************************************************************************
88  * PUBLIC FUNCTIONS
89  *****************************************************************************/
90 
91 /**
92  * Create new event loops. This method should only be called when asynchronous client commands
93  * will be used and the calling program itself is not asynchronous. If this method is used,
94  * it must be called before aerospike_connect().
95  *
96  * @param capacity Number of event loops to create.
97  * @return Event loop array.
98  *
99  * @ingroup async_events
100  */
102 as_event_create_loops(uint32_t capacity);
103 
104 /**
105  * Set the number of externally created event loops. This method should be called when the
106  * calling program wants to share event loops with the client. This reduces resource usage and
107  * can increase performance.
108  *
109  * This method is used in conjunction with as_event_set_external_loop() to fully define the
110  * the external loop to the client and obtain a reference the client's event loop abstraction.
111  *
112  * ~~~~~~~~~~{.c}
113  * struct {
114  * pthread_t thread;
115  * struct ev_loop* loop;
116  * as_event_loop* as_loop;
117  * } my_loop;
118  *
119  * static void* my_loop_worker_thread(void* udata) {
120  * struct my_loop* myloop = udata;
121  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
122  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
123  * ev_loop(myloop->loop, 0);
124  * ev_loop_destroy(myloop->loop);
125  * return NULL;
126  * }
127  *
128  * int capacity = 8;
129  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
130  * as_event_set_external_loop_capacity(capacity);
131  *
132  * for (int i = 0; i < capacity; i++) {
133  * struct my_loop* myloop = &loops[i];
134  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
135  * }
136  * ~~~~~~~~~~
137  *
138  * @param capacity Number of externally created event loops.
139  * @return True if all external loops were initialized.
140  *
141  * @ingroup async_events
142  */
143 bool
144 as_event_set_external_loop_capacity(uint32_t capacity);
145 
146 /**
147  * Register an external event loop with the client. This method should be called when the
148  * calling program wants to share event loops with the client. This reduces resource usage and
149  * can increase performance.
150  *
151  * This method must be called in the same thread as the event loop that is being registered.
152  *
153  * This method is used in conjunction with as_event_set_external_loop_capacity() to fully define
154  * the external loop to the client and obtain a reference the client's event loop abstraction.
155  *
156  * ~~~~~~~~~~{.c}
157  * struct {
158  * pthread_t thread;
159  * struct ev_loop* loop;
160  * as_event_loop* as_loop;
161  * } my_loop;
162  *
163  * static void* my_loop_worker_thread(void* udata) {
164  * struct my_loop* myloop = udata;
165  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
166  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
167  * ev_loop(myloop->loop, 0);
168  * ev_loop_destroy(myloop->loop);
169  * return NULL;
170  * }
171  *
172  * int capacity = 8;
173  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
174  * as_event_set_external_loop_capacity(capacity);
175  *
176  * for (int i = 0; i < capacity; i++) {
177  * struct my_loop* myloop = &loops[i];
178  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
179  * }
180  * ~~~~~~~~~~
181  *
182  * @param loop External event loop.
183  * @return Client's generic event loop abstraction that is used in client async commands.
184  * Returns NULL if external loop capacity would be exceeded.
185  *
186  * @ingroup async_events
187  */
190 
191 /**
192  * Find client's event loop abstraction given the external event loop.
193  *
194  * @param loop External event loop.
195  * @return Client's generic event loop abstraction that is used in client async commands.
196  * Returns NULL if loop not found.
197  *
198  * @ingroup async_events
199  */
201 as_event_loop_find(void* loop);
202 
203 /**
204  * Retrieve event loop by array index.
205  *
206  * @param index Event loop array index.
207  * @return Client's generic event loop abstraction that is used in client async commands.
208  *
209  * @ingroup async_events
210  */
211 static inline as_event_loop*
213 {
214  return index < as_event_loop_size ? &as_event_loops[index] : NULL;
215 }
216 
217 /**
218  * Retrieve a random event loop using round robin distribution.
219  *
220  * @return Client's generic event loop abstraction that is used in client async commands.
221  *
222  * @ingroup async_events
223  */
224 static inline as_event_loop*
226 {
227  // The last event loop points to the first event loop to create a circular linked list.
228  // Not atomic because doesn't need to be exactly accurate.
229  as_event_loop* event_loop = as_event_loop_current;
230  as_event_loop_current = event_loop->next;
231  return event_loop;
232 }
233 
234 /**
235  * Close internal event loops and release watchers for internal and external event loops.
236  * The global event loop array will also be destroyed for internal event loops.
237  *
238  * This method should be called once on program shutdown if as_event_create_loops() or
239  * as_event_set_external_loop_capacity() was called.
240  *
241  * The shutdown sequence is slightly different for internal and external event loops.
242  *
243  * Internal:
244  * ~~~~~~~~~~{.c}
245  * as_event_close_loops();
246  * ~~~~~~~~~~
247  *
248  * External:
249  * ~~~~~~~~~~{.c}
250  * as_event_close_loops();
251  * Join on external loop threads.
252  * as_event_destroy_loops();
253  * ~~~~~~~~~~
254  *
255  * @return True if event loop close was successful. If false, as_event_destroy_loops() should
256  * not be called.
257  *
258  * @ingroup async_events
259  */
260 bool
262 
263 /**
264  * Destroy global event loop array. This function only needs to be called for external
265  * event loops.
266  *
267  * @ingroup async_events
268  */
269 void
271 
272 #ifdef __cplusplus
273 } // end extern "C"
274 #endif