KHMEXP void perf_set_thread_desc(const char * file, int line, const wchar_t * name, const wchar_t * creator) { thread_info * t; char * fn_copy; perf_once(); t = malloc(sizeof(*t)); ZeroMemory(t, sizeof(*t)); #ifdef _WIN32 t->thread = GetCurrentThreadId(); #else #error Unsupported platform #endif StringCbCopy(t->name, sizeof(t->name), name); if (creator) StringCbCopy(t->creator, sizeof(t->creator), creator); if (file[0] == '.' && file[1] == '\\') file += 2; EnterCriticalSection(&cs_alloc); fn_copy = hash_lookup(&fn_hash, file); if (fn_copy == NULL) { size_t cblen = 0; if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), &cblen))) fn_copy = NULL; else { fn_copy = malloc(cblen + sizeof(char)); if (fn_copy) { hash_bin * b; int hv; StringCbCopyA(fn_copy, cblen + sizeof(char), file); hv = fn_hash.hash(fn_copy) % fn_hash.n; b = malloc(sizeof(*b)); b->data = fn_copy; b->key = fn_copy; LINIT(b); LPUSH(&fn_hash.bins[hv], b); } } } t->file = fn_copy; t->line = line; LPUSH(&threads, t); LeaveCriticalSection(&cs_alloc); }
KHMEXP void * perf_realloc(const char * file, int line, void * data, size_t s) { void * n_data; allocation * a; size_t h; if (data == NULL) return perf_malloc(file, line, s); perf_once(); h = HASHPTR(data); n_data = realloc(data, s); assert(n_data); EnterCriticalSection(&cs_alloc); for (a = ht[h]; a; a = LNEXT(a)) { if (a->ptr == data) break; } assert(a); LDELETE(&ht[h], a); a->size = s; a->ptr = n_data; h = HASHPTR(n_data); LPUSH(&ht[h], a); LeaveCriticalSection(&cs_alloc); return n_data; }
/*! \internal \brief Adds a subscription to a message type \note Obtains ::cs_kmq_types */ void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) { kmq_msg_subscription * ts; if(t < 0 || t > KMQ_MSG_TYPE_MAX) return; if(!msg_types[t]) kmqint_msg_type_create(t); EnterCriticalSection(&cs_kmq_types); s->type = t; /* check if we already have this subscription */ ts = msg_types[t]->subs; while(ts) { if((ts->rcpt_type == s->rcpt_type) && (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) || ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd)))) break; ts = LNEXT(ts); } /* add it if we didn't find it */ if(!ts) { LPUSH(&msg_types[t]->subs, s); } LeaveCriticalSection(&cs_kmq_types); }
/*! \internal \brief Frees a message object \note called with ::cs_kmq_msg held */ void kmqint_put_message(kmq_message *m) { int queued; /* we can only free a message if the refcount is zero. Otherwise we have to wait until the call is freed. */ if(m->refcount == 0) { LDELETE(&msg_active, m); LeaveCriticalSection(&cs_kmq_msg); queued = kmqint_notify_msg_completion(m); EnterCriticalSection(&cs_kmq_msg); if (!queued) { if(m->err_ctx) { kherr_release_context(m->err_ctx); m->err_ctx = NULL; } if(m->wait_o) { CloseHandle(m->wait_o); m->wait_o = NULL; } LPUSH(&msg_free,m); } } else if(m->wait_o) { SetEvent(m->wait_o); } }
/*! \internal \brief Preps a thread for use with kmq \note Obtains ::cs_kmq_global */ void kmqint_attach_this_thread(void) { kmq_queue * q; EnterCriticalSection(&cs_kmq_global); q = (kmq_queue *) TlsGetValue(kmq_tls_queue); if(!q) { q = PMALLOC(sizeof(kmq_queue)); InitializeCriticalSection(&q->cs); q->thread = GetCurrentThreadId(); QINIT(q); LINIT(q); q->wait_o = CreateEvent(NULL, FALSE, FALSE, NULL); q->load = 0; q->last_post = 0; q->flags = 0; LPUSH(&queues, q); TlsSetValue(kmq_tls_queue, (LPVOID) q); } LeaveCriticalSection(&cs_kmq_global); }
kmm_module_i * kmmint_get_module_i(wchar_t * name) { kmm_module_i * m; size_t sz; if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &sz))) return NULL; sz += sizeof(wchar_t); EnterCriticalSection(&cs_kmm); m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); if(m == NULL) { m = PMALLOC(sizeof(kmm_module_i)); ZeroMemory(m, sizeof(kmm_module_i)); m->magic = KMM_MODULE_MAGIC; m->name = PMALLOC(sz); StringCbCopy(m->name, sz, name); m->state = KMM_MODULE_STATE_NONE; hash_add(hash_modules, (void *) m->name, (void *) m); LPUSH(&kmm_all_modules, m); } LeaveCriticalSection(&cs_kmm); return m; }
static void identpro_mark_for_deletion(kcdb_identpro_i * p) { khm_boolean is_default = FALSE; if (!kcdb_is_identpro(p)) return; EnterCriticalSection(&cs_identpro); if (DEFAULT_PROVIDER == p) is_default = TRUE; if (!(p->flags & KCDB_IDENTPRO_FLAG_DELETED)) { QDEL(&id_providers, p); n_id_providers--; LPUSH(&deleted_id_providers, p); p->flags |= KCDB_IDENTPRO_FLAG_DELETED; p->flags &= ~KCDB_IDENTPRO_FLAG_READY; kcdbint_identpro_post_message(KCDB_OP_DELETE, p); } if (p->refcount == 0) identpro_check_and_deleteL(p); if (is_default) identpro_check_and_set_default_provider(); LeaveCriticalSection(&cs_identpro); }
static void free_event(kherr_event * e) { EnterCriticalSection(&cs_error); assert(IS_KHERR_EVENT(e)); #ifdef DEBUG assert(LNEXT(e) == NULL); assert(LPREV(e) == NULL); #endif if(e->flags & KHERR_RF_FREE_SHORT_DESC) { assert(e->short_desc); PFREE((void *) e->short_desc); } if(e->flags & KHERR_RF_FREE_LONG_DESC) { assert(e->long_desc); PFREE((void *) e->long_desc); } if(e->flags & KHERR_RF_FREE_SUGGEST) { assert(e->suggestion); PFREE((void *) e->suggestion); } free_event_params(e); ZeroMemory(e, sizeof(*e)); LPUSH(&evt_free_list, e); LeaveCriticalSection(&cs_error); }
KHMEXP khm_int32 KHMAPI khui_alert_create_empty(khui_alert ** result) { khui_alert * a; a = PMALLOC(sizeof(*a)); ZeroMemory(a, sizeof(*a)); a->magic = KHUI_ALERT_MAGIC; /* set defaults */ a->severity = KHERR_INFO; a->flags = KHUI_ALERT_FLAG_FREE_STRUCT | KHUI_ALERT_FLAG_MODIFIED; a->alert_type = KHUI_ALERTTYPE_NONE; khui_context_create(&a->ctx, KHUI_SCOPE_NONE, NULL, KCDB_CREDTYPE_INVALID, NULL); khui_alert_hold(a); EnterCriticalSection(&cs_alerts); LPUSH(&kh_alerts, a); LeaveCriticalSection(&cs_alerts); *result = a; return KHM_ERROR_SUCCESS; }
/*! \internal \brief Free a message ref object \note called with cs_kmq_msg_ref and cs_kmq_msg held */ void kmqint_put_message_ref(kmq_message_ref * r) { if(!r) return; if(r->msg) { r->msg->refcount--; r->msg = NULL; } LPUSH(&kmq_msg_ref_free, r); }
/* the plugin must be delisted before calling this */ void kmmint_list_plugin(kmm_plugin_i * p) { EnterCriticalSection(&cs_kmm); if((p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) || (p->flags & KMM_PLUGIN_FLAG_IN_LIST)) { RaiseException(2, EXCEPTION_NONCONTINUABLE, 0, NULL); } p->flags |= KMM_PLUGIN_FLAG_IN_LIST; LPUSH(&kmm_listed_plugins, p); LeaveCriticalSection(&cs_kmm); }
/*! \internal \brief Get a message object \note called with ::cs_kmq_msg held */ kmq_message * kmqint_get_message(void) { kmq_message * m; LPOP(&msg_free,&m); if(!m) { /* allocate one */ m = PMALLOC(sizeof(kmq_message)); } ZeroMemory((void*)m, sizeof(kmq_message)); LPUSH(&msg_active, m); return m; }
/*! \internal \brief Create a message type \note Obtains ::cs_kmq_types */ void kmqint_msg_type_create(int t) { if(t < 0 || t > KMQ_MSG_TYPE_MAX) return; EnterCriticalSection(&cs_kmq_types); if(!msg_types[t]) { kmq_msg_type * mt; mt = PMALLOC(sizeof(kmq_msg_type)); ZeroMemory(mt, sizeof(kmq_msg_type)); mt->id = t; LINIT(mt); mt->subs = NULL; msg_types[t] = mt; LPUSH(&all_msg_types, mt); } LeaveCriticalSection(&cs_kmq_types); }
KHMEXP void perf_free (void * b) { size_t h; allocation * a; perf_once(); h = HASHPTR(b); EnterCriticalSection(&cs_alloc); for(a = ht[h]; a; a = LNEXT(a)) { if (a->ptr == b) break; } assert(a); LDELETE(&ht[h], a); LPUSH(&free_alloc, a); LeaveCriticalSection(&cs_alloc); }
/*! \internal \note Obtains ::cs_kmq_global */ KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, khm_handle * result) { kmq_msg_subscription * s; s = PMALLOC(sizeof(kmq_msg_subscription)); ZeroMemory(s, sizeof(*s)); s->magic = KMQ_MSG_SUB_MAGIC; LINIT(s); s->queue = kmqint_get_thread_queue(); s->rcpt_type = KMQ_RCPTTYPE_CB; s->recipient.cb = cb; EnterCriticalSection(&cs_kmq_global); LPUSH(&kmq_adhoc_subs, s); LeaveCriticalSection(&cs_kmq_global); *result = (khm_handle) s; return KHM_ERROR_SUCCESS; }
KHMEXP khm_int32 KHMAPI kmq_create_hwnd_subscription(HWND hw, khm_handle * result) { kmq_msg_subscription * s; s = PMALLOC(sizeof(kmq_msg_subscription)); ZeroMemory(s, sizeof(*s)); s->magic = KMQ_MSG_SUB_MAGIC; LINIT(s); s->queue = NULL; s->rcpt_type = KMQ_RCPTTYPE_HWND; s->recipient.hwnd = hw; EnterCriticalSection(&cs_kmq_global); LPUSH(&kmq_adhoc_subs, s); LeaveCriticalSection(&cs_kmq_global); *result = (khm_handle) s; return KHM_ERROR_SUCCESS; }
/* Assumes that the context has been deleted from all relevant lists */ static void free_context(kherr_context * c) { kherr_context * ch; kherr_event * e; assert(IS_KHERR_CTX(c)); #ifdef DEBUG_CONTEXT if (IsDebuggerPresent()) kherr_debug_printf(L"Freeing context 0x%x\n", c); #endif EnterCriticalSection(&cs_error); if (c->desc_event) free_event(c->desc_event); c->desc_event = NULL; TPOPCHILD(c, &ch); while(ch) { free_context(ch); TPOPCHILD(c, &ch); } QGET(c, &e); while(e) { free_event(e); QGET(c, &e); } c->serial = 0; LPUSH(&ctx_free_list,c); LeaveCriticalSection(&cs_error); #ifdef DEBUG_CONTEXT if (IsDebuggerPresent()) kherr_debug_printf(L"Done with context 0x%x\n", c); #endif }
KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result) { kcdb_credset * cs; cs = PMALLOC(sizeof(kcdb_credset)); ZeroMemory(cs, sizeof(kcdb_credset)); cs->magic = KCDB_CREDSET_MAGIC; InitializeCriticalSection(&(cs->cs)); LINIT(cs); kcdb_credset_buf_new(cs); cs->version = 0; cs->seal_count = 0; EnterCriticalSection(&cs_credset); LPUSH(&kcdb_credsets, cs); LeaveCriticalSection(&cs_credset); *result = (khm_handle) cs; return KHM_ERROR_SUCCESS; }
static kherr_context * get_empty_context(void) { kherr_context * c; EnterCriticalSection(&cs_error); if(ctx_free_list) { LPOP(&ctx_free_list, &c); } else { c = PMALLOC(sizeof(kherr_context)); } ZeroMemory(c,sizeof(*c)); c->severity = KHERR_NONE; c->flags = KHERR_CF_UNBOUND; c->magic = KHERR_CONTEXT_MAGIC; c->serial = ++ctx_serial; LPUSH(&ctx_root_list, c); LeaveCriticalSection(&cs_error); return c; }
KHMEXP khm_int32 KHMAPI kcdb_credtype_register(const kcdb_credtype * type, khm_int32 * new_id) { khm_int32 id; kcdb_credtype_i * ict; size_t cb_name; size_t cb_short_desc; size_t cb_long_desc; int i; if(!type) return KHM_ERROR_INVALID_PARAM; if(type->id > KCDB_CREDTYPE_MAX_ID) return KHM_ERROR_INVALID_PARAM; if(type->name) { if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name))) return KHM_ERROR_TOO_LONG; cb_name += sizeof(wchar_t); } else return KHM_ERROR_INVALID_PARAM; if(type->short_desc) { if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) return KHM_ERROR_TOO_LONG; cb_short_desc += sizeof(wchar_t); } else cb_short_desc = 0; if(type->long_desc) { if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) return KHM_ERROR_TOO_LONG; cb_long_desc += sizeof(wchar_t); } else cb_long_desc = 0; if(type->sub == NULL) return KHM_ERROR_INVALID_PARAM; EnterCriticalSection(&cs_credtype); if(type->id <= 0) { if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) { LeaveCriticalSection(&cs_credtype); return KHM_ERROR_NO_RESOURCES; } } else id = type->id; if(kcdb_credtype_tbl[id]) { LeaveCriticalSection(&cs_credtype); return KHM_ERROR_DUPLICATE; } for (i=1; i <= KCDB_CREDTYPE_MAX_ID; i++) { if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) { LeaveCriticalSection(&cs_credtype); return KHM_ERROR_DUPLICATE; } } ict = PMALLOC(sizeof(kcdb_credtype_i)); ZeroMemory(ict, sizeof(kcdb_credtype_i)); ict->ct.name = PMALLOC(cb_name); StringCbCopy(ict->ct.name, cb_name, type->name); if(cb_short_desc > 0) { ict->ct.short_desc = PMALLOC(cb_short_desc); StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc); } if(cb_long_desc > 0) { ict->ct.long_desc = PMALLOC(cb_long_desc); StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc); } ict->ct.id = id; ict->ct.icon = type->icon; ict->ct.sub = type->sub; ict->ct.is_equal = type->is_equal; kcdb_credtype_tbl[id] = ict; LPUSH(&kcdb_credtypes, ict); LeaveCriticalSection(&cs_credtype); kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct)); if (new_id) *new_id = id; return KHM_ERROR_SUCCESS; }
KHMEXP khm_int32 KHMAPI kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) { kmm_module_i * m; kmm_plugin_i * p; size_t cb_name = 0; size_t cb_desc = 0; size_t cb_dep = 0; m = kmm_module_from_handle(module); /* can only called when handing init_module() */ if(m->state != KMM_MODULE_STATE_INIT) return KHM_ERROR_INVALID_OPERATION; if(!plugin || FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), &cb_name)) || (plugin->description && FAILED(StringCbLength(plugin->description, KMM_MAXCB_DESC - sizeof(wchar_t), &cb_desc))) || (plugin->dependencies && KHM_FAILED(multi_string_length_cb(plugin->dependencies, KMM_MAXCB_DEPS, &cb_dep)))) { return KHM_ERROR_INVALID_PARAM; } cb_name += sizeof(wchar_t); cb_desc += sizeof(wchar_t); p = kmmint_get_plugin_i(plugin->name); /* released below or in kmmint_init_module() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); if(p->state != KMM_PLUGIN_STATE_NONE && p->state != KMM_PLUGIN_STATE_PLACEHOLDER) { kmm_release_plugin(kmm_handle_from_plugin(p)); return KHM_ERROR_DUPLICATE; } /* released when the plugin quits */ kmm_hold_module(module); p->module = m; p->p.flags = plugin->flags; p->p.msg_proc = plugin->msg_proc; p->p.type = plugin->type; if(plugin->description) { p->p.description = PMALLOC(cb_desc); StringCbCopy(p->p.description, cb_desc, plugin->description); } else p->p.description = NULL; if(plugin->dependencies) { p->p.dependencies = PMALLOC(cb_dep); multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies); } else p->p.dependencies = NULL; p->p.module = p->module->name; p->p.icon = plugin->icon; p->state = KMM_PLUGIN_STATE_REG; kmmint_delist_plugin(p); EnterCriticalSection(&cs_kmm); LPUSH(&(m->plugins), p); p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST; LeaveCriticalSection(&cs_kmm); /* leave the plugin held because it is in the module's plugin list */ return KHM_ERROR_SUCCESS; }
KHMEXP khm_int32 KHMAPI kcdb_type_register(const kcdb_type * type, khm_int32 * new_id) { kcdb_type_i *t; size_t cbsize; khm_int32 type_id; if(!type || !type->comp || !type->dup || !type->isValid || !type->toString || !type->name) return KHM_ERROR_INVALID_PARAM; if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB)) { return KHM_ERROR_INVALID_PARAM; } if((type->flags & KCDB_TYPE_FLAG_CB_MAX) && (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB)) { return KHM_ERROR_INVALID_PARAM; } if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && (type->flags & KCDB_TYPE_FLAG_CB_MAX) && (type->cb_max < type->cb_min)) { return KHM_ERROR_INVALID_PARAM; } if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize))) return KHM_ERROR_TOO_LONG; cbsize += sizeof(wchar_t); EnterCriticalSection(&cs_type); if(type->id == KCDB_TYPE_INVALID) { kcdb_type_get_next_free(&type_id); } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) { LeaveCriticalSection(&cs_type); return KHM_ERROR_INVALID_PARAM; } else if(kcdb_type_tbl[type->id]) { LeaveCriticalSection(&cs_type); return KHM_ERROR_DUPLICATE; } else { type_id = type->id; } if(type_id == KCDB_TYPE_INVALID) { LeaveCriticalSection(&cs_type); return KHM_ERROR_NO_RESOURCES; } t = PMALLOC(sizeof(kcdb_type_i)); ZeroMemory(t, sizeof(kcdb_type_i)); t->type.name = PMALLOC(cbsize); StringCbCopy(t->type.name, cbsize, type->name); t->type.comp = type->comp; t->type.dup = type->dup; t->type.flags = type->flags; t->type.id = type_id; t->type.isValid = type->isValid; t->type.toString = type->toString; LINIT(t); kcdb_type_tbl[type_id] = t; LPUSH(&kcdb_types, t); hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t); LeaveCriticalSection(&cs_type); if(new_id) *new_id = type_id; kcdb_type_post_message(KCDB_OP_INSERT, t); return KHM_ERROR_SUCCESS; }
KHMEXP void * perf_malloc(const char * file, int line, size_t s) { allocation * a; void * ptr; size_t h; char * fn_copy = NULL; perf_once(); assert(s > 0); EnterCriticalSection(&cs_alloc); a = get_allocation(); ptr = malloc(s); assert(ptr); /* TODO: handle this gracefully */ if (file[0] == '.' && file[1] == '\\') file += 2; fn_copy = hash_lookup(&fn_hash, file); if (fn_copy == NULL) { size_t cblen = 0; if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), &cblen))) fn_copy = NULL; else { fn_copy = malloc(cblen + sizeof(char)); if (fn_copy) { hash_bin * b; int hv; StringCbCopyA(fn_copy, cblen + sizeof(char), file); hv = fn_hash.hash(fn_copy) % fn_hash.n; b = malloc(sizeof(*b)); b->data = fn_copy; b->key = fn_copy; LINIT(b); LPUSH(&fn_hash.bins[hv], b); } } } a->file = fn_copy; a->line = line; a->size = s; a->ptr = ptr; #ifdef _WIN32 a->thread = GetCurrentThreadId(); #endif h = HASHPTR(ptr); LPUSH(&ht[h], a); LeaveCriticalSection(&cs_alloc); return ptr; }