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 {
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 
63  pthread_mutex_t lock;
66  pthread_t thread;
67  uint32_t index;
70 
71 /******************************************************************************
72  * GLOBAL VARIABLES
73  *****************************************************************************/
74 
76 extern uint32_t as_event_loop_size;
77 extern uint32_t as_event_loop_current;
78 
79 /******************************************************************************
80  * PUBLIC FUNCTIONS
81  *****************************************************************************/
82 
83 /**
84  * Create new event loops. This method should only be called when asynchronous client commands
85  * will be used and the calling program itself is not asynchronous. If this method is used,
86  * it must be called before aerospike_connect().
87  *
88  * @param capacity Number of event loops to create.
89  *
90  * @ingroup async_events
91  */
93 as_event_create_loops(uint32_t capacity);
94 
95 /**
96  * Set the number of externally created event loops. This method should be called when the
97  * calling program wants to share event loops with the client. This reduces resource usage and
98  * can increase performance.
99  *
100  * This method is used in conjunction with as_event_set_external_loop() to fully define the
101  * the external loop to the client and obtain a reference the client's event loop abstraction.
102  *
103  * ~~~~~~~~~~{.c}
104  * struct {
105  * pthread_t thread;
106  * struct ev_loop* loop;
107  * as_event_loop* as_loop;
108  * } my_loop;
109  *
110  * static void* my_loop_worker_thread(void* udata) {
111  * struct my_loop* myloop = udata;
112  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
113  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
114  * ev_loop(myloop->loop, 0);
115  * ev_loop_destroy(myloop->loop);
116  * return NULL;
117  * }
118  *
119  * int capacity = 8;
120  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
121  * as_event_set_external_loop_capacity(capacity);
122  *
123  * for (int i = 0; i < capacity; i++) {
124  * struct my_loop* myloop = &loops[i];
125  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
126  * }
127  * ~~~~~~~~~~
128  *
129  * @param capacity Number of externally created event loops.
130  *
131  * @ingroup async_events
132  */
133 bool
134 as_event_set_external_loop_capacity(uint32_t capacity);
135 
136 /**
137  * Register an external event loop with the client. This method should be called when the
138  * calling program wants to share event loops with the client. This reduces resource usage and
139  * can increase performance.
140  *
141  * This method must be called in the same thread as the event loop that is being registered.
142  *
143  * This method is used in conjunction with as_event_set_external_loop_capacity() to fully define
144  * the external loop to the client and obtain a reference the client's event loop abstraction.
145  *
146  * ~~~~~~~~~~{.c}
147  * struct {
148  * pthread_t thread;
149  * struct ev_loop* loop;
150  * as_event_loop* as_loop;
151  * } my_loop;
152  *
153  * static void* my_loop_worker_thread(void* udata) {
154  * struct my_loop* myloop = udata;
155  * myloop->loop = ev_loop_new(EVFLAG_AUTO);
156  * myloop->as_loop = as_event_set_external_loop(myloop->loop);
157  * ev_loop(myloop->loop, 0);
158  * ev_loop_destroy(myloop->loop);
159  * return NULL;
160  * }
161  *
162  * int capacity = 8;
163  * struct my_loop* loops = malloc(sizeof(struct my_loop) * capacity);
164  * as_event_set_external_loop_capacity(capacity);
165  *
166  * for (int i = 0; i < capacity; i++) {
167  * struct my_loop* myloop = &loops[i];
168  * return pthread_create(&myloop->thread, NULL, my_loop_worker_thread, myloop) == 0;
169  * }
170  * ~~~~~~~~~~
171  *
172  * @param loop External event loop.
173  * @return Client's generic event loop abstraction that is used in client async commands.
174  * Returns NULL if external loop capacity would be exceeded.
175  *
176  * @ingroup async_events
177  */
179 as_event_set_external_loop(void* loop);
180 
181 /**
182  * Find client's event loop abstraction given the external event loop.
183  *
184  * @param loop External event loop.
185  * @return Client's generic event loop abstraction that is used in client async commands.
186  * Returns NULL if loop not found.
187  *
188  * @ingroup async_events
189  */
191 as_event_loop_find(void* loop);
192 
193 /**
194  * Retrieve event loop by array index.
195  *
196  * @param index Event loop array index.
197  * @return Client's generic event loop abstraction that is used in client async commands.
198  *
199  * @ingroup async_events
200  */
201 static inline as_event_loop*
203 {
204  return index < as_event_loop_size ? &as_event_loops[index] : NULL;
205 }
206 
207 /**
208  * Retrieve a random event loop using round robin distribution.
209  *
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  // Increment is not atomic because it doesn't need to be exactly accurate.
218  uint32_t current = as_event_loop_current++;
219  return &as_event_loops[current % as_event_loop_size];
220 }
221 
222 /**
223  * Close internally created event loops and release memory for event loop abstraction.
224  * This method should be called once on program shutdown if as_event_create_loops() or
225  * as_event_set_external_loop_capacity() was called.
226  *
227  * @ingroup async_events
228  */
229 void
231 
232 #ifdef __cplusplus
233 } // end extern "C"
234 #endif