blob: 42f74525d17ce656ff86eb6984b43a08711cde51 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2013 Xilinx, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* Xilinx - initial API and implementation
*******************************************************************************/
/*
* Shutdown manager.
*/
#include <tcf/config.h>
#include <tcf/framework/link.h>
#include <tcf/framework/trace.h>
#include <tcf/framework/events.h>
#include <tcf/framework/shutdown.h>
#include <assert.h>
static void (*shutdown_complete_handler)(void *shutdown_complete_arg);
static void * shutdown_complete_arg;
static int notify_pending;
LINK shutdown_active = TCF_LIST_INIT(shutdown_active);
static void notify_all(void * arg) {
LINK * l;
assert(notify_pending);
notify_pending = 0;
if (list_is_empty(&shutdown_active)) {
/* All subsystems are stopped, cancel event dispatching and
* notify shutdown initiator. */
trace(LOG_SHUTDOWN, "shutdown complete");
cancel_event_loop();
shutdown_complete_handler(shutdown_complete_arg);
return;
}
l = shutdown_active.next;
while (l != &shutdown_active) {
ShutdownInfo *obj = active2ShutdownInfo(l);
l = l->next;
trace(LOG_SHUTDOWN, "shutdown notify %p %d", obj, obj->state);
if (obj->state == SHUTDOWN_STATE_NORMAL) {
obj->state = SHUTDOWN_STATE_PENDING;
obj->notify(obj);
}
else {
assert(obj->state == SHUTDOWN_STATE_PENDING);
}
}
}
int shutdown_start(void (*handler)(void *arg), void * arg) {
assert(is_dispatch_thread());
assert(handler != NULL);
assert(!notify_pending);
trace(LOG_SHUTDOWN, "shutdown start");
if (shutdown_complete_handler) {
return 1;
}
shutdown_complete_handler = handler;
shutdown_complete_arg = arg;
notify_pending = 1;
post_event(notify_all, NULL);
return 0;
}
void shutdown_set_stopped(ShutdownInfo *obj) {
assert(is_dispatch_thread());
assert(obj != NULL);
trace(LOG_SHUTDOWN, "shutdown_set_stopped %p", obj);
if (obj->state == SHUTDOWN_STATE_STOPPED) {
/* Noop */
return;
}
assert(obj->state == SHUTDOWN_STATE_NORMAL ||
obj->state == SHUTDOWN_STATE_PENDING);
obj->state = SHUTDOWN_STATE_STOPPED;
list_remove(&obj->link_active);
if (shutdown_complete_handler && !notify_pending) {
notify_pending = 1;
post_event(notify_all, NULL);
}
}
void shutdown_set_normal(ShutdownInfo *obj) {
assert(is_dispatch_thread());
assert(obj != NULL);
trace(LOG_SHUTDOWN, "shutdown_set_normal %p", obj);
if (obj->state == SHUTDOWN_STATE_NORMAL) {
/* Noop */
return;
}
if (obj->state == SHUTDOWN_STATE_STOPPED) {
list_add_last(&obj->link_active, &shutdown_active);
}
else {
assert(obj->state == SHUTDOWN_STATE_PENDING);
}
obj->state = SHUTDOWN_STATE_NORMAL;
}