comparison libfdcore/core.c @ 1111:84162710428e

Cleanup to avoid sending several terminate event
author Sebastien Decugis <sdecugis@freediameter.net>
date Mon, 13 May 2013 11:37:12 +0800
parents 96f2051215c8
children d87cee14b051
comparison
equal deleted inserted replaced
1110:a731051d2e83 1111:84162710428e
46 /* gcrypt functions to support posix threads */ 46 /* gcrypt functions to support posix threads */
47 #ifndef GNUTLS_VERSION_210 47 #ifndef GNUTLS_VERSION_210
48 GCRY_THREAD_OPTION_PTHREAD_IMPL; 48 GCRY_THREAD_OPTION_PTHREAD_IMPL;
49 #endif /* GNUTLS_VERSION_210 */ 49 #endif /* GNUTLS_VERSION_210 */
50 50
51 /* Signal extensions when the framework is completely initialized (they are waiting in fd_core_waitstartcomplete()) */
52 static int is_ready = 0;
53 static pthread_mutex_t is_ready_mtx = PTHREAD_MUTEX_INITIALIZER;
54 static pthread_cond_t is_ready_cnd = PTHREAD_COND_INITIALIZER;
55
56 static int signal_framework_ready(void)
57 {
58 TRACE_ENTRY("");
59 CHECK_POSIX( pthread_mutex_lock( &is_ready_mtx ) );
60 is_ready = 1;
61 CHECK_POSIX( pthread_cond_broadcast( &is_ready_cnd ) );
62 CHECK_POSIX( pthread_mutex_unlock( &is_ready_mtx ) );
63 return 0;
64 }
65
66 /* Thread that process incoming events on the main queue -- and terminates the framework when requested */ 51 /* Thread that process incoming events on the main queue -- and terminates the framework when requested */
67 static pthread_t core_runner = (pthread_t)NULL; 52 static pthread_t core_runner = (pthread_t)NULL;
68 53
69 /* How the thread is terminated */ 54 /* Signal extensions when the framework is completely initialized (they are waiting in fd_core_waitstartcomplete()) */
70 enum core_mode { 55 static enum core_state {
71 CORE_MODE_EVENTS, 56 CORE_NOT_INIT, /* initial state */
72 CORE_MODE_IMMEDIATE 57 CORE_LIBS_INIT, /* fd_core_initialize was called */
73 }; 58 CORE_CONF_READY,/* Configuration was parsed, extensions are loaded */
59 CORE_RUNNING, /* Servers and clients are started, core_runner thread is running */
60 CORE_SHUTDOWN, /* The framework is terminating all objects */
61 CORE_TERM /* Shutdown complete. */
62 } core_state = CORE_NOT_INIT;
63 static pthread_mutex_t core_mtx = PTHREAD_MUTEX_INITIALIZER;
64 static pthread_cond_t core_cnd = PTHREAD_COND_INITIALIZER;
65
66 static enum core_state core_state_get(void)
67 {
68 enum core_state cur_state;
69 CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
70 cur_state = core_state;
71 CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
72 return cur_state;
73 }
74
75 static void core_state_set(enum core_state newstate)
76 {
77 CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
78 LOG_D("Core state: %d -> %d", core_state, newstate);
79 core_state = newstate;
80 CHECK_POSIX_DO( pthread_cond_broadcast( &core_cnd ), );
81 CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
82 }
83
84 static int core_state_wait(enum core_state waitstate)
85 {
86 int ret;
87 CHECK_POSIX( pthread_mutex_lock( &core_mtx ));
88 pthread_cleanup_push( fd_cleanup_mutex, &core_mtx );
89 do {
90 CHECK_POSIX_DO(ret = pthread_cond_wait(&core_cnd, &core_mtx), break);
91 } while (waitstate > core_state);
92 pthread_cleanup_pop( 0 );
93 CHECK_POSIX( pthread_mutex_unlock( &core_mtx ));
94 return ret;
95 }
96
97 static void core_shutdown(void)
98 {
99 LOG_N( FD_PROJECT_BINARY " framework is stopping...");
100 fd_log_threadname("fD Core Shutdown");
101
102 /* cleanups */
103 CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
104 CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
105 CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
106 CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
107
108 CHECK_FCT_DO( fd_ext_term(), /* Cleanup all extensions */ );
109 CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ );
110
111 GNUTLS_TRACE( gnutls_global_deinit() );
112
113 CHECK_FCT_DO( fd_conf_deinit(), );
114
115 CHECK_FCT_DO( fd_event_trig_fini(), );
116
117 fd_log_debug(FD_PROJECT_BINARY " framework is terminated.");
118
119 fd_libproto_fini();
120
121 }
122
74 123
75 static void * core_runner_thread(void * arg) 124 static void * core_runner_thread(void * arg)
76 { 125 {
77 if (arg && (*(int *)arg == CORE_MODE_IMMEDIATE))
78 goto end;
79
80 fd_log_threadname("fD Core Runner"); 126 fd_log_threadname("fD Core Runner");
127
128 core_state_wait(CORE_RUNNING);
81 129
82 /* Handle events incoming on the main event queue */ 130 /* Handle events incoming on the main event queue */
83 while (1) { 131 while (1) {
84 int code; size_t sz; void * data; 132 int code; size_t sz; void * data;
85 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break ); 133 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break );
107 TRACE_DEBUG(INFO, "Unexpected event in the main event queue (%d), ignored.", code); 155 TRACE_DEBUG(INFO, "Unexpected event in the main event queue (%d), ignored.", code);
108 } 156 }
109 } 157 }
110 158
111 end: 159 end:
112 TRACE_DEBUG(INFO, FD_PROJECT_BINARY " framework is stopping..."); 160 core_shutdown();
113 fd_log_threadname("fD Core Shutdown");
114
115 /* cleanups */
116 CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
117 CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
118 CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
119 CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
120
121 CHECK_FCT_DO( fd_ext_term(), /* Cleanup all extensions */ );
122 CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ );
123
124 GNUTLS_TRACE( gnutls_global_deinit() );
125
126 CHECK_FCT_DO( fd_conf_deinit(), );
127
128 CHECK_FCT_DO( fd_event_trig_fini(), );
129
130 fd_log_debug(FD_PROJECT_BINARY " framework is terminated.");
131
132 fd_libproto_fini();
133 161
134 return NULL; 162 return NULL;
135 } 163 }
136 164
137 /*********************************/ 165 /*********************************/
145 173
146 /* Initialize the libfdcore internals. This also initializes libfdproto */ 174 /* Initialize the libfdcore internals. This also initializes libfdproto */
147 int fd_core_initialize(void) 175 int fd_core_initialize(void)
148 { 176 {
149 int ret; 177 int ret;
178
179 if (core_state_get() != CORE_NOT_INIT) {
180 fprintf(stderr, "fd_core_initialize() called more than once!\n");
181 return EINVAL;
182 }
150 183
151 /* Initialize the library -- must come first since it initializes the debug facility */ 184 /* Initialize the library -- must come first since it initializes the debug facility */
152 ret = fd_libproto_init(); 185 ret = fd_libproto_init();
153 if (ret != 0) { 186 if (ret != 0) {
154 fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret)); 187 fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret));
190 CHECK_FCT( fd_queues_init() ); 223 CHECK_FCT( fd_queues_init() );
191 CHECK_FCT( fd_msg_init() ); 224 CHECK_FCT( fd_msg_init() );
192 CHECK_FCT( fd_sess_start() ); 225 CHECK_FCT( fd_sess_start() );
193 CHECK_FCT( fd_p_expi_init() ); 226 CHECK_FCT( fd_p_expi_init() );
194 227
228 core_state_set(CORE_LIBS_INIT);
229
195 /* Next thing is to parse the config, leave this for a different function */ 230 /* Next thing is to parse the config, leave this for a different function */
196 return 0; 231 return 0;
197 } 232 }
198 233
199 /* Parse the freeDiameter.conf configuration file, load the extensions */ 234 /* Parse the freeDiameter.conf configuration file, load the extensions */
227 LOG_N("%s", b ?: "Error during triggers dump..."); 262 LOG_N("%s", b ?: "Error during triggers dump...");
228 } 263 }
229 264
230 free(buf); 265 free(buf);
231 266
267 core_state_set(CORE_CONF_READY);
268
232 return 0; 269 return 0;
233 } 270 }
234 271
235 /* For threads that would need to wait complete start of the framework (ex: in extensions) */ 272 /* For threads that would need to wait complete start of the framework (ex: in extensions) */
236 int fd_core_waitstartcomplete(void) 273 int fd_core_waitstartcomplete(void)
237 { 274 {
238 int ret = 0;
239
240 TRACE_ENTRY(""); 275 TRACE_ENTRY("");
241 276
242 CHECK_POSIX( pthread_mutex_lock( &is_ready_mtx ) ); 277 return core_state_wait(CORE_RUNNING);
243 pthread_cleanup_push( fd_cleanup_mutex, &is_ready_mtx );
244
245 while (!ret && !is_ready) {
246 CHECK_POSIX_DO( ret = pthread_cond_wait( &is_ready_cnd, &is_ready_mtx ), );
247 }
248
249 pthread_cleanup_pop( 0 );
250 CHECK_POSIX( pthread_mutex_unlock( &is_ready_mtx ) );
251
252 return ret;
253 } 278 }
254 279
255 /* Start the server & client threads */ 280 /* Start the server & client threads */
256 int fd_core_start(void) 281 int fd_core_start(void)
257 { 282 {
261 /* Start the peer state machines */ 286 /* Start the peer state machines */
262 CHECK_FCT( fd_psm_start() ); 287 CHECK_FCT( fd_psm_start() );
263 288
264 /* Start the core runner thread that handles main events (until shutdown) */ 289 /* Start the core runner thread that handles main events (until shutdown) */
265 CHECK_POSIX( pthread_create(&core_runner, NULL, core_runner_thread, NULL) ); 290 CHECK_POSIX( pthread_create(&core_runner, NULL, core_runner_thread, NULL) );
266 291
267 /* Unlock threads waiting into fd_core_waitstartcomplete */ 292 /* Unlock threads waiting into fd_core_waitstartcomplete */
268 CHECK_FCT( signal_framework_ready() ); 293 core_state_set(CORE_RUNNING);
269 294
270 /* Ok, everything is running now... */ 295 /* Ok, everything is running now... */
271 return 0; 296 return 0;
272 } 297 }
273 298
274 299
275 /* Initialize shutdown of the framework. This is not blocking. */ 300 /* Initialize shutdown of the framework. This is not blocking. */
276 int fd_core_shutdown(void) 301 int fd_core_shutdown(void)
277 { 302 {
278 if (core_runner != (pthread_t)NULL) { 303 enum core_state cur_state = core_state_get();
279 /* Signal the framework to terminate */ 304
305 if (cur_state < CORE_RUNNING) {
306 core_shutdown();
307 } else if (cur_state == CORE_RUNNING) {
308 core_state_set(CORE_SHUTDOWN);
280 CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL) ); 309 CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL) );
281 } else { 310 }
282 /* The framework was maybe not fully initialized (ex: tests) */ 311
283 enum core_mode arg = CORE_MODE_IMMEDIATE; 312 /* Other case, the framework is already shutting down */
284 (void) core_runner_thread(&arg); 313
285 } 314 return 0;
286 315 }
287 return 0; 316
288 } 317
289 318 /* Wait for the shutdown to be complete -- this must be called after fd_core_shutdown to reclaim some resources. */
290
291 /* Wait for the shutdown to be complete -- this must always be called after fd_core_shutdown to reclaim some resources. */
292 int fd_core_wait_shutdown_complete(void) 319 int fd_core_wait_shutdown_complete(void)
293 { 320 {
294 int ret; 321 int ret;
322 enum core_state cur_state = core_state_get();
295 void * th_ret = NULL; 323 void * th_ret = NULL;
296 324
297 if (core_runner != (pthread_t)NULL) { 325 if (cur_state == CORE_TERM)
298 /* Just wait for core_runner_thread to complete and return gracefully */ 326 return 0;
299 ret = pthread_join(core_runner, &th_ret); 327
300 if (ret != 0) { 328 CHECK_FCT(core_state_wait(CORE_SHUTDOWN));
301 TRACE_ERROR( "Unable to wait for main framework thread termination: %s", strerror(ret)); 329
302 return ret; 330 /* Just wait for core_runner_thread to complete and return gracefully */
303 } 331 CHECK_POSIX(pthread_join(core_runner, &th_ret));
304 } 332
305 333 core_state_set(CORE_TERM);
306 return 0; 334
307 } 335 return 0;
308 336 }
309 337
310 338
311 339
340
"Welcome to our mercurial repository"