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