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