#include "control.h"
-#ifdef DEBUG_MEMORY_LEAKS
-struct igheap {
- struct igheap *next;
- char file[32];
- int line;
- void *block;
-};
-
-struct igheap *igheap = NULL;
-#endif
-
-
/*
* Signal handler to shut down the server.
*/
}
return LOG_DAEMON;
}
-
-
-/********** MEM CHEQQER ***********/
-
-#ifdef DEBUG_MEMORY_LEAKS
-
-#undef malloc
-#undef realloc
-#undef strdup
-#undef free
-
-void *tracked_malloc(size_t size, char *file, int line) {
- struct igheap *thisheap;
- void *block;
-
- block = malloc(size);
- if (block == NULL) return(block);
-
- thisheap = malloc(sizeof(struct igheap));
- if (thisheap == NULL) {
- free(block);
- return(NULL);
- }
-
- thisheap->block = block;
- strcpy(thisheap->file, file);
- thisheap->line = line;
-
- begin_critical_section(S_DEBUGMEMLEAKS);
- thisheap->next = igheap;
- igheap = thisheap;
- end_critical_section(S_DEBUGMEMLEAKS);
-
- return(block);
-}
-
-
-void *tracked_realloc(void *ptr, size_t size, char *file, int line) {
- struct igheap *thisheap;
- void *block;
-
- block = realloc(ptr, size);
- if (block == NULL) return(block);
-
- thisheap = malloc(sizeof(struct igheap));
- if (thisheap == NULL) {
- free(block);
- return(NULL);
- }
-
- thisheap->block = block;
- strcpy(thisheap->file, file);
- thisheap->line = line;
-
- begin_critical_section(S_DEBUGMEMLEAKS);
- thisheap->next = igheap;
- igheap = thisheap;
- end_critical_section(S_DEBUGMEMLEAKS);
-
- return(block);
-}
-
-
-
-void tracked_free(void *ptr) {
- struct igheap *thisheap;
- struct igheap *trash;
-
- free(ptr);
-
- if (igheap == NULL) return;
- begin_critical_section(S_DEBUGMEMLEAKS);
- for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
- if (thisheap->next != NULL) {
- if (thisheap->next->block == ptr) {
- trash = thisheap->next;
- thisheap->next = thisheap->next->next;
- free(trash);
- }
- }
- }
- if (igheap->block == ptr) {
- trash = igheap;
- igheap = igheap->next;
- free(trash);
- }
- end_critical_section(S_DEBUGMEMLEAKS);
-}
-
-char *tracked_strdup(const char *s, char *file, int line) {
- char *ptr;
-
- if (s == NULL) return(NULL);
- ptr = tracked_malloc(strlen(s) + 1, file, line);
- if (ptr == NULL) return(NULL);
- strncpy(ptr, s, strlen(s));
- return(ptr);
-}
-
-void dump_heap(void) {
- struct igheap *thisheap;
-
- for (thisheap = igheap; thisheap != NULL; thisheap = thisheap->next) {
- syslog(LOG_CRIT, "UNFREED: %30s : %d\n",
- thisheap->file, thisheap->line);
- }
-}
-
-#endif /* DEBUG_MEMORY_LEAKS */
#ifndef SYSDEP_DECLS_H
#define SYSDEP_DECLS_H
-/*
- * Uncomment this #define if you are a Citadel developer tracking
- * down memory leaks in the server. Do NOT do this on a production
- * system because it definitely incurs a lot of additional overhead.
-#define DEBUG_MEMORY_LEAKS
- */
-
-
#include <stdarg.h>
#include "sysdep.h"
#endif /* HAVE_PTHREAD_H */
-
-#ifdef DEBUG_MEMORY_LEAKS
-#define malloc(x) tracked_malloc(x, __FILE__, __LINE__)
-#define realloc(x,y) tracked_realloc(x, y, __FILE__, __LINE__)
-#undef strdup
-#define strdup(x) tracked_strdup(x, __FILE__, __LINE__)
-#define free(x) tracked_free(x)
-void *tracked_malloc(size_t size, char *file, int line);
-void *tracked_realloc(void *ptr, size_t size, char *file, int line);
-void tracked_free(void *ptr);
-char *tracked_strdup(const char *s, char *file, int line);
-void dump_heap(void);
-#endif
-
#endif /* SYSDEP_DECLS_H */
#include "context.h"
#include "event_client.h"
-/*
- * define this to use the new worker_thread method of handling connections
- */
-//#define NEW_WORKER
/*
- * New thread interface.
* To create a thread you must call one of the create thread functions.
* You must pass it the address of (a pointer to a CtdlThreadNode initialised to NULL) like this
* struct CtdlThreadNode *node = NULL;
* transaction; this could lead to deadlock.
*/
if ( (which_one != S_FLOORCACHE)
-#ifdef DEBUG_MEMORY_LEAKS
- && (which_one != S_DEBUGMEMLEAKS)
-#endif
&& (which_one != S_RPLIST)
) {
cdb_check_handles();
* transaction; this could lead to deadlock.
*/
if ( (which_one != S_FLOORCACHE)
-#ifdef DEBUG_MEMORY_LEAKS
- && (which_one != S_DEBUGMEMLEAKS)
-#endif
&& (which_one != S_RPLIST)
) {
cdb_check_handles();
}
-/*
- * A function to update a threads load averages
- */
- void ctdl_thread_internal_update_avgs(CtdlThreadNode *this_thread)
- {
- struct timeval now, result;
- double last_duration;
-
- gettimeofday(&now, NULL);
- timersub(&now, &(this_thread->last_state_change), &result);
- /* I don't think these mutex's are needed here */
- citthread_mutex_lock(&this_thread->ThreadMutex);
- // result now has a timeval for the time we spent in the last state since we last updated
- last_duration = (double)result.tv_sec + ((double)result.tv_usec / (double) 1000000);
- if (this_thread->state == CTDL_THREAD_SLEEPING)
- this_thread->avg_sleeping += last_duration;
- if (this_thread->state == CTDL_THREAD_RUNNING)
- this_thread->avg_running += last_duration;
- if (this_thread->state == CTDL_THREAD_BLOCKED)
- this_thread->avg_blocked += last_duration;
- memcpy (&this_thread->last_state_change, &now, sizeof (struct timeval));
- citthread_mutex_unlock(&this_thread->ThreadMutex);
-}
-
/*
* A function to chenge the state of a thread
*/
/*
* Wether we change state or not we need update the load values
*/
- ctdl_thread_internal_update_avgs(this_thread);
/* This mutex not needed here? */
citthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
if ((new_state == CTDL_THREAD_STOP_REQ) && (this_thread->state > CTDL_THREAD_STOP_REQ))
citthread_mutex_unlock(&CT->ThreadMutex);
}
-/*
- * A quick function to show the load averages
- */
-void ctdl_thread_internal_calc_loadavg(void)
-{
- CtdlThreadNode *that_thread;
- double load_avg, worker_avg;
- int workers = 0;
-
- that_thread = CtdlThreadList;
- load_avg = 0;
- worker_avg = 0;
- while(that_thread)
- {
- /* Update load averages */
- ctdl_thread_internal_update_avgs(that_thread);
- citthread_mutex_lock(&that_thread->ThreadMutex);
- that_thread->load_avg = (that_thread->avg_sleeping + that_thread->avg_running) / (that_thread->avg_sleeping + that_thread->avg_running + that_thread->avg_blocked) * 100;
- that_thread->avg_sleeping /= 2;
- that_thread->avg_running /= 2;
- that_thread->avg_blocked /= 2;
- load_avg += that_thread->load_avg;
- if (that_thread->flags & CTDLTHREAD_WORKER)
- {
- worker_avg += that_thread->load_avg;
- workers++;
- }
-#ifdef WITH_THREADLOG
- syslog(LOG_DEBUG, "CtdlThread, \"%s\" (%lu) \"%s\" %.2f %.2f %.2f %.2f\n",
- that_thread->name,
- that_thread->tid,
- CtdlThreadStates[that_thread->state],
- that_thread->avg_sleeping,
- that_thread->avg_running,
- that_thread->avg_blocked,
- that_thread->load_avg);
-#endif
- citthread_mutex_unlock(&that_thread->ThreadMutex);
- that_thread = that_thread->next;
- }
- CtdlThreadLoadAvg = load_avg/num_threads;
- CtdlThreadWorkerAvg = worker_avg/workers;
-#ifdef WITH_THREADLOG
- syslog(LOG_INFO, "System load average %.2f, workers averag %.2f, threads %d, workers %d, sessions %d\n", CtdlThreadGetLoadAvg(), CtdlThreadWorkerAvg, num_threads, num_workers, num_sessions);
-#endif
-}
-
-
/*
* Garbage collection routine.
* Gets called by main() in a loop to clean up the thread list periodically.
CtdlThreadList = this_thread;
if (this_thread->next)
this_thread->next->prev = this_thread;
- ctdl_thread_internal_calc_loadavg();
end_critical_section(S_THREAD_LIST);
if (this_thread->next)
this_thread->next->prev = this_thread;
- ctdl_thread_internal_calc_loadavg();
end_critical_section(S_THREAD_LIST);
{
int i;
CtdlThreadNode *last_worker;
- struct timeval start, now, result;
- double last_duration;
/*
* Initialise the thread system
if (CT->state > CTDL_THREAD_STOP_REQ)
{
begin_critical_section(S_THREAD_LIST);
- ctdl_thread_internal_calc_loadavg();
end_critical_section(S_THREAD_LIST);
ctdl_thread_internal_check_scheduled(); /* start scheduled threads */