/******************************************************************************* * Copyright (c) 2007, 2010 Wind River Systems, 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: * Wind River Systems - initial API and implementation *******************************************************************************/ /* * This module handles process/thread OS contexts and their state machine. */ #include #include #include #include typedef struct Listener { ContextEventListener * func; void * args; } Listener; static Listener * listeners = NULL; static unsigned listener_cnt = 0; static unsigned listener_max = 0; static size_t extension_size = 0; static int context_created = 0; LINK context_root = { NULL, NULL }; const char * REASON_USER_REQUEST = "Suspended"; const char * REASON_STEP = "Step"; const char * REASON_BREAKPOINT = "Breakpoint"; const char * REASON_EXCEPTION = "Exception"; const char * REASON_CONTAINER = "Container"; const char * REASON_WATCHPOINT = "Watchpoint"; const char * REASON_SIGNAL = "Signal"; const char * REASON_SHAREDLIB = "Shared Library"; const char * REASON_ERROR = "Error"; char * pid2id(pid_t pid, pid_t parent) { static char s[64]; char * p = s + sizeof(s); unsigned long n = (long)pid; *(--p) = 0; do { *(--p) = (char)(n % 10 + '0'); n = n / 10; } while (n != 0); if (parent != 0) { n = (long)parent; *(--p) = '.'; do { *(--p) = (char)(n % 10 + '0'); n = n / 10; } while (n != 0); } *(--p) = 'P'; return p; } pid_t id2pid(const char * id, pid_t * parent) { /* TODO: (pid_t)0 is valid value in Windows, should use (pid_t)-1 to indicate an error */ pid_t pid = 0; if (parent != NULL) *parent = 0; if (id == NULL) return 0; if (id[0] != 'P') return 0; if (id[1] == 0) return 0; pid = (pid_t)strtol(id + 1, (char **)&id, 10); if (id[0] == '.') { if (id[1] == 0) return 0; if (parent != NULL) *parent = pid; pid = (pid_t)strtol(id + 1, (char **)&id, 10); } if (id[0] != 0) return 0; return pid; } void add_context_event_listener(ContextEventListener * listener, void * client_data) { if (listener_cnt >= listener_max) { listener_max += 8; listeners = (Listener *)loc_realloc(listeners, listener_max * sizeof(Listener)); } listeners[listener_cnt].func = listener; listeners[listener_cnt].args = client_data; listener_cnt++; } size_t context_extension(size_t size) { size_t offs = 0; assert(!context_created); while (extension_size % sizeof(void *) != 0) extension_size++; offs = sizeof(Context) + extension_size; extension_size += size; return offs; } Context * create_context(const char * id) { Context * ctx = (Context *)loc_alloc_zero(sizeof(Context) + extension_size); strlcpy(ctx->id, id, sizeof(ctx->id)); list_init(&ctx->children); context_created = 1; return ctx; } void context_clear_memory_map(MemoryMap * map) { unsigned i; for (i = 0; i < map->region_cnt; i++) { MemoryRegion * r = map->regions + i; loc_free(r->file_name); loc_free(r->sect_name); loc_free(r->id); while (r->attrs != NULL) { MemoryRegionAttribute * x = r->attrs; r->attrs = x->next; loc_free(x->name); loc_free(x->value); loc_free(x); } } memset(map->regions, 0, sizeof(MemoryRegion) * map->region_max); map->region_cnt = 0; } #if ENABLE_DebugContext void context_lock(Context * ctx) { assert(ctx->ref_count > 0); ctx->ref_count++; } void context_unlock(Context * ctx) { assert(ctx->ref_count > 0); if (--(ctx->ref_count) == 0) { unsigned i; assert(ctx->exited); assert(list_is_empty(&ctx->children)); if (ctx->parent != NULL) { list_remove(&ctx->cldl); context_unlock(ctx->parent); ctx->parent = NULL; } if (ctx->creator != NULL) { context_unlock(ctx->creator); ctx->creator = NULL; } assert(!ctx->event_notification); ctx->event_notification = 1; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_disposed == NULL) continue; l->func->context_disposed(ctx, l->args); } ctx->event_notification = 0; list_remove(&ctx->ctxl); loc_free(ctx->name); loc_free(ctx); } } const char * context_state_name(Context * ctx) { if (ctx->exited) return "exited"; if (ctx->stopped) return "stopped"; return "running"; } void send_context_created_event(Context * ctx) { unsigned i; assert(ctx->ref_count > 0); assert(!ctx->event_notification); ctx->event_notification = 1; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_created == NULL) continue; l->func->context_created(ctx, l->args); } ctx->event_notification = 0; } void send_context_changed_event(Context * ctx) { unsigned i; assert(ctx->ref_count > 0); assert(!ctx->event_notification); ctx->event_notification = 1; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_changed == NULL) continue; l->func->context_changed(ctx, l->args); } ctx->event_notification = 0; } void send_context_stopped_event(Context * ctx) { unsigned i; assert(ctx->ref_count > 0); assert(ctx->stopped != 0); assert(!ctx->event_notification); assert(context_has_state(ctx)); ctx->event_notification = 1; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_stopped == NULL) continue; l->func->context_stopped(ctx, l->args); assert(ctx->stopped != 0); } ctx->event_notification = 0; } void send_context_started_event(Context * ctx) { unsigned i; assert(ctx->ref_count > 0); assert(context_has_state(ctx)); ctx->stopped = 0; ctx->stopped_by_bp = 0; ctx->stopped_by_cb = NULL; ctx->stopped_by_exception = 0; if (ctx->exception_description) { loc_free(ctx->exception_description); ctx->exception_description = NULL; } ctx->event_notification++; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_started == NULL) continue; l->func->context_started(ctx, l->args); } ctx->event_notification--; } void send_context_exited_event(Context * ctx) { unsigned i; assert(!ctx->event_notification); assert(!ctx->exited); ctx->exiting = 0; ctx->pending_intercept = 0; ctx->exited = 1; ctx->event_notification = 1; for (i = 0; i < listener_cnt; i++) { Listener * l = listeners + i; if (l->func->context_exited == NULL) continue; l->func->context_exited(ctx, l->args); } ctx->event_notification = 0; context_unlock(ctx); } void ini_contexts(void) { list_init(&context_root); init_contexts_sys_dep(); } #endif /* if ENABLE_DebugContext */