X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fstatistics%2Fgnunet-service-statistics.c;h=6c3d173c44b78b19eb0386bd4e08745ebce21e80;hb=372afebb55cc8b40d5f7115a398564e6ffd61434;hp=5e0be11832e6a0b95991a84ce5991d813b27bae4;hpb=502af2167f7c218366666ca4944bd7cc54b5b19a;p=oweals%2Fgnunet.git diff --git a/src/statistics/gnunet-service-statistics.c b/src/statistics/gnunet-service-statistics.c index 5e0be1183..6c3d173c4 100644 --- a/src/statistics/gnunet-service-statistics.c +++ b/src/statistics/gnunet-service-statistics.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009, 2010 Christian Grothoff (and other contributing authors) + (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -22,11 +22,9 @@ * @file statistics/gnunet-service-statistics.c * @brief program that tracks statistics * @author Christian Grothoff - * - * TODO: - * - use BIO for IO operations */ #include "platform.h" +#include "gnunet_bio_lib.h" #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_getopt_lib.h" @@ -43,16 +41,37 @@ struct WatchEntry { + /** + * Watch entries are kept in a linked list. + */ struct WatchEntry *next; + /** + * Watch entries are kept in a linked list. + */ struct WatchEntry *prev; + /** + * For which client is this watch entry? + */ struct GNUNET_SERVER_Client *client; + /** + * Last value we communicated to the client for this watch entry. + */ uint64_t last_value; + /** + * Unique watch number for this client and this watched value. + */ uint32_t wid; + /** + * Is last_value valid + * GNUNET_NO : last_value is n/a, GNUNET_YES: last_value is valid + */ + int last_value_set; + }; @@ -61,13 +80,24 @@ struct WatchEntry */ struct ClientEntry { - + /** + * Clients are kept in a linked list. + */ struct ClientEntry *next; + /** + * Clients are kept in a linked list. + */ struct ClientEntry *prev; + /** + * Corresponding server handle. + */ struct GNUNET_SERVER_Client *client; + /** + * Maximum watch ID used by this client so far. + */ uint32_t max_wid; }; @@ -128,6 +158,12 @@ struct StatsEntry */ int persistent; + /** + * Is this value set? + * GNUNET_NO : value is n/a, GNUNET_YES: value is valid + */ + int set; + }; /** @@ -140,10 +176,21 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; */ static struct StatsEntry *start; +/** + * Head of linked list of connected clients. + */ static struct ClientEntry *client_head; +/** + * Tail of linked list of connected clients. + */ static struct ClientEntry *client_tail; +/** + * Handle to our server. + */ +static struct GNUNET_SERVER_Handle *srv; + /** * Our notification context. */ @@ -154,13 +201,26 @@ static struct GNUNET_SERVER_NotificationContext *nc; */ static uint32_t uidgen; +/** + * Set to YES if we are shutting down as soon as possible. + */ +static int in_shutdown; + -static void +/** + * Inject a message to our server with a client of 'NULL'. + * + * @param cls the 'struct GNUNET_SERVER_Handle' + * @param client unused + * @param msg message to inject + */ +static int inject_message (void *cls, void *client, const struct GNUNET_MessageHeader *msg) { struct GNUNET_SERVER_Handle *server = cls; GNUNET_break (GNUNET_OK == GNUNET_SERVER_inject (server, NULL, msg)); + return GNUNET_OK; } @@ -175,50 +235,62 @@ static void load (struct GNUNET_SERVER_Handle *server) { char *fn; - struct GNUNET_DISK_FileHandle *fh; - struct GNUNET_DISK_MapHandle *mh; - struct stat sb; + struct GNUNET_BIO_ReadHandle *rh; + uint64_t fsize; char *buf; struct GNUNET_SERVER_MessageStreamTokenizer *mst; + char *emsg; - fn = GNUNET_DISK_get_home_filename (cfg, - "statistics", "statistics.data", NULL); - if (fn == NULL) + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "STATISTICS", + "DATABASE", + &fn)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "STATISTICS", + "DATABASE"); return; - if ((0 != stat (fn, &sb)) || (sb.st_size == 0)) + } + if ( (GNUNET_OK != + GNUNET_DISK_file_size (fn, &fsize, GNUNET_NO, GNUNET_YES)) || + (0 == fsize) ) { GNUNET_free (fn); return; } - fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); - if (!fh) + buf = GNUNET_malloc (fsize); + rh = GNUNET_BIO_read_open (fn); + if (!rh) { + GNUNET_free (buf); GNUNET_free (fn); return; } - buf = GNUNET_DISK_file_map (fh, &mh, GNUNET_DISK_MAP_TYPE_READ, sb.st_size); - if (NULL == buf) + if (GNUNET_OK != GNUNET_BIO_read (rh, fn, buf, fsize)) { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "mmap", fn); - GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", fn); + GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); + GNUNET_free (buf); + GNUNET_free_non_null (emsg); GNUNET_free (fn); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading %llu bytes of statistics from `%s'\n"), - (unsigned long long) sb.st_size, fn); + fsize, fn); mst = GNUNET_SERVER_mst_create (&inject_message, server); GNUNET_break (GNUNET_OK == - GNUNET_SERVER_mst_receive (mst, - NULL, - buf, - sb.st_size, GNUNET_YES, GNUNET_NO)); + GNUNET_SERVER_mst_receive (mst, NULL, buf, fsize, + GNUNET_YES, GNUNET_NO)); GNUNET_SERVER_mst_destroy (mst); - GNUNET_break (GNUNET_OK == GNUNET_DISK_file_unmap (mh)); - GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); + GNUNET_free (buf); + GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, &emsg)); + GNUNET_free_non_null (emsg); GNUNET_free (fn); } + /** * Write persistent statistics to disk. */ @@ -227,40 +299,46 @@ save () { struct StatsEntry *pos; char *fn; - struct GNUNET_DISK_FileHandle *fh; + struct GNUNET_BIO_WriteHandle *wh; uint16_t size; unsigned long long total; - fh = NULL; - fn = GNUNET_DISK_get_home_filename (cfg, - "statistics", "statistics.data", NULL); - if (fn != NULL) - fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_WRITE - | GNUNET_DISK_OPEN_CREATE | - GNUNET_DISK_OPEN_TRUNCATE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "STATISTICS", + "DATABASE", + &fn)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "STATISTICS", + "DATABASE"); + return; + } + (void) GNUNET_DISK_directory_create_for_file (fn); + wh = GNUNET_BIO_write_open (fn); total = 0; while (NULL != (pos = start)) { start = pos->next; - if ((pos->persistent) && (NULL != fh)) + if ((pos->persistent) && (NULL != wh)) { size = htons (pos->msg->header.size); - if (size != GNUNET_DISK_file_write (fh, pos->msg, size)) + if (GNUNET_OK != GNUNET_BIO_write (wh, pos->msg, size)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn); - GNUNET_DISK_file_close (fh); - fh = NULL; + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); + wh = NULL; } else total += size; } GNUNET_free (pos); } - if (NULL != fh) + if (NULL != wh) { - GNUNET_DISK_file_close (fh); + if (GNUNET_OK != GNUNET_BIO_write_close (wh)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "close", fn); if (total == 0) GNUNET_break (0 == UNLINK (fn)); else @@ -273,6 +351,9 @@ save () /** * Transmit the given stats value. + * + * @param client receiver of the value + * @param e value to transmit */ static void transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) @@ -292,14 +373,12 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) m->uid |= htonl (GNUNET_STATISTICS_PERSIST_BIT); m->value = GNUNET_htonll (e->value); size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); - GNUNET_assert (size == GNUNET_STRINGS_buffer_fill ((char *) &m[1], - size, - 2, e->service, e->name)); -#if DEBUG_STATISTICS + GNUNET_assert (size == + GNUNET_STRINGS_buffer_fill ((char *) &m[1], size, 2, + e->service, e->name)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting value for `%s:%s' (%d): %llu\n", - e->service, e->name, e->persistent, e->value); -#endif + "Transmitting value for `%s:%s' (%d): %llu\n", e->service, + e->name, e->persistent, e->value); GNUNET_SERVER_notification_context_unicast (nc, client, &m->header, GNUNET_NO); GNUNET_free (m); @@ -308,16 +387,26 @@ transmit (struct GNUNET_SERVER_Client *client, const struct StatsEntry *e) /** * Does this entry match the request? + * + * @param e an entry + * @param service name of service to match + * @param name value to match + * @return 1 if they match, 0 if not */ static int matches (const struct StatsEntry *e, const char *service, const char *name) { - return ((0 == strlen (service)) || - (0 == strcmp (service, e->service))) - && ((0 == strlen (name)) || (0 == strcmp (name, e->name))); + return ((0 == strlen (service)) || (0 == strcmp (service, e->service))) && + ((0 == strlen (name)) || (0 == strcmp (name, e->name))); } +/** + * Find a client entry for the given client handle, or create one. + * + * @param client handle to match + * @return corresponding client entry struct + */ static struct ClientEntry * make_client_entry (struct GNUNET_SERVER_Client *client) { @@ -331,9 +420,13 @@ make_client_entry (struct GNUNET_SERVER_Client *client) return ce; ce = ce->next; } - ce = GNUNET_malloc (sizeof (struct ClientEntry)); + if (NULL == nc) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return NULL; + } + ce = GNUNET_new (struct ClientEntry); ce->client = client; - GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ce); GNUNET_SERVER_notification_context_add (nc, client); return ce; @@ -350,8 +443,7 @@ make_client_entry (struct GNUNET_SERVER_Client *client) * GNUNET_SYSERR to close it (signal serious error) */ static void -handle_get (void *cls, - struct GNUNET_SERVER_Client *client, +handle_get (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_MessageHeader end; @@ -360,28 +452,24 @@ handle_get (void *cls, struct StatsEntry *pos; size_t size; - if (client != NULL) - make_client_entry (client); + if ( (NULL != client) && + (NULL == make_client_entry (client)) ) + return; /* new client during shutdown */ size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader); - if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], - size, 2, &service, &name)) + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, + &service, &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } -#if DEBUG_STATISTICS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request for statistics on `%s:%s'\n", strlen (service) ? service : "*", strlen (name) ? name : "*"); -#endif - pos = start; - while (pos != NULL) - { + for (pos = start; NULL != pos; pos = pos->next) if (matches (pos, service, name)) transmit (client, pos); - pos = pos->next; - } end.size = htons (sizeof (struct GNUNET_MessageHeader)); end.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_END); GNUNET_SERVER_notification_context_unicast (nc, client, &end, GNUNET_NO); @@ -389,33 +477,42 @@ handle_get (void *cls, } +/** + * Notify all clients listening about a change to a value. + * + * @param se value that changed + */ static void notify_change (struct StatsEntry *se) { struct GNUNET_STATISTICS_WatchValueMessage wvm; struct WatchEntry *pos; - pos = se->we_head; - while (pos != NULL) + for (pos = se->we_head; NULL != pos; pos = pos->next) { - if (pos->last_value != se->value) + if (GNUNET_YES == pos->last_value_set) { - wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); - wvm.header.size = - htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); - wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); - wvm.wid = htonl (pos->wid); - wvm.reserved = htonl (0); - wvm.value = GNUNET_htonll (se->value); - GNUNET_SERVER_notification_context_unicast (nc, - pos->client, - &wvm.header, GNUNET_NO); - pos->last_value = se->value; + if (pos->last_value == se->value) + continue; } - pos = pos->next; + else + { + pos->last_value_set = GNUNET_YES; + } + wvm.header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_WATCH_VALUE); + wvm.header.size = + htons (sizeof (struct GNUNET_STATISTICS_WatchValueMessage)); + wvm.flags = htonl (se->persistent ? GNUNET_STATISTICS_PERSIST_BIT : 0); + wvm.wid = htonl (pos->wid); + wvm.reserved = htonl (0); + wvm.value = GNUNET_htonll (se->value); + GNUNET_SERVER_notification_context_unicast (nc, pos->client, &wvm.header, + GNUNET_NO); + pos->last_value = se->value; } } + /** * Handle SET-message. * @@ -424,8 +521,7 @@ notify_change (struct StatsEntry *se) * @param message the actual message */ static void -handle_set (void *cls, - struct GNUNET_SERVER_Client *client, +handle_set (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { char *service; @@ -439,9 +535,11 @@ handle_set (void *cls, uint64_t value; int64_t delta; int changed; + int initial_set; - if (client != NULL) - make_client_entry (client); + if ( (NULL != client) && + (NULL == make_client_entry (client)) ) + return; /* new client during shutdown */ msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_STATISTICS_SetMessage)) { @@ -452,8 +550,9 @@ handle_set (void *cls, size = msize - sizeof (struct GNUNET_STATISTICS_SetMessage); msg = (const struct GNUNET_STATISTICS_SetMessage *) message; - if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], - size, 2, &service, &name)) + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &msg[1], size, 2, &service, + &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); @@ -461,17 +560,16 @@ handle_set (void *cls, } flags = ntohl (msg->flags); value = GNUNET_ntohll (msg->value); -#if DEBUG_STATISTICS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received request to update statistic on `%s:%s' (%u) to/by %llu\n", service, name, (unsigned int) flags, (unsigned long long) value); -#endif pos = start; prev = NULL; while (pos != NULL) { if (matches (pos, service, name)) { + initial_set = 0; if ((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) { changed = (pos->value != value); @@ -492,6 +590,11 @@ handle_set (void *cls, pos->value += delta; } } + if (GNUNET_NO == pos->set) + { + pos->set = GNUNET_YES; + initial_set = 1; + } pos->msg->value = GNUNET_htonll (pos->value); pos->msg->flags = msg->flags; pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); @@ -502,12 +605,10 @@ handle_set (void *cls, pos->next = start; start = pos; } -#if DEBUG_STATISTICS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Statistic `%s:%s' updated to value %llu.\n", - service, name, pos->value); -#endif - if (changed) + "Statistic `%s:%s' updated to value %llu.\n", service, name, + pos->value); + if ((changed) || (1 == initial_set)) notify_change (pos); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; @@ -519,7 +620,14 @@ handle_set (void *cls, pos->next = start; if (((flags & GNUNET_STATISTICS_SETFLAG_RELATIVE) == 0) || (0 < (int64_t) GNUNET_ntohll (msg->value))) + { pos->value = GNUNET_ntohll (msg->value); + pos->set = GNUNET_YES; + } + else + { + pos->set = GNUNET_NO; + } pos->uid = uidgen++; pos->persistent = (0 != (flags & GNUNET_STATISTICS_SETFLAG_PERSISTENT)); pos->msg = (void *) &pos[1]; @@ -528,11 +636,9 @@ handle_set (void *cls, pos->name = &pos->service[strlen (pos->service) + 1]; start = pos; -#if DEBUG_STATISTICS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "New statistic on `%s:%s' with value %llu created.\n", - service, name, pos->value); -#endif + "New statistic on `%s:%s' with value %llu created.\n", service, + name, pos->value); GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -545,8 +651,7 @@ handle_set (void *cls, * @param message the actual message */ static void -handle_watch (void *cls, - struct GNUNET_SERVER_Client *client, +handle_watch (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { char *service; @@ -558,6 +663,12 @@ handle_watch (void *cls, struct WatchEntry *we; size_t slen; + if (NULL == nc) + { + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_client_mark_monitor (client); ce = make_client_entry (client); msize = ntohs (message->size); if (msize < sizeof (struct GNUNET_MessageHeader)) @@ -567,18 +678,17 @@ handle_watch (void *cls, return; } size = msize - sizeof (struct GNUNET_MessageHeader); - if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], - size, 2, &service, &name)) + if (size != + GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1], size, 2, + &service, &name)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } -#if DEBUG_STATISTICS GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received request to watch statistic on `%s:%s'\n", - service, name); -#endif + "Received request to watch statistic on `%s:%s'\n", service, + name); pos = start; while (pos != NULL) { @@ -588,10 +698,12 @@ handle_watch (void *cls, } if (pos == NULL) { - pos = GNUNET_malloc (sizeof (struct StatsEntry) + - sizeof (struct GNUNET_STATISTICS_SetMessage) + size); + pos = + GNUNET_malloc (sizeof (struct StatsEntry) + + sizeof (struct GNUNET_STATISTICS_SetMessage) + size); pos->next = start; pos->uid = uidgen++; + pos->set = GNUNET_NO; pos->msg = (void *) &pos[1]; pos->msg->header.size = htons (sizeof (struct GNUNET_STATISTICS_SetMessage) + size); @@ -602,10 +714,13 @@ handle_watch (void *cls, pos->name = &pos->service[slen]; memcpy ((void *) pos->name, name, strlen (name) + 1); start = pos; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New statistic on `%s:%s' with value %llu created.\n", service, + name, pos->value); } - we = GNUNET_malloc (sizeof (struct WatchEntry)); + we = GNUNET_new (struct WatchEntry); we->client = client; - GNUNET_SERVER_client_keep (client); + we->last_value_set = GNUNET_NO; we->wid = ce->max_wid++; GNUNET_CONTAINER_DLL_insert (pos->we_head, pos->we_tail, we); if (pos->value != 0) @@ -615,33 +730,25 @@ handle_watch (void *cls, /** - * Task run during shutdown. - * - * @param cls unused - * @param tc unused + * Actually perform the shutdown. */ static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +do_shutdown () { - struct ClientEntry *ce; struct WatchEntry *we; struct StatsEntry *se; + if (NULL == nc) + return; save (); GNUNET_SERVER_notification_context_destroy (nc); nc = NULL; - while (NULL != (ce = client_head)) - { - GNUNET_SERVER_client_drop (ce->client); - GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); - GNUNET_free (ce); - } + GNUNET_assert (NULL == client_head); while (NULL != (se = start)) { start = se->next; while (NULL != (we = se->we_head)) { - GNUNET_SERVER_client_drop (we->client); GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); GNUNET_free (we); } @@ -650,6 +757,22 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + in_shutdown = GNUNET_YES; + if (NULL != client_head) + return; + do_shutdown (); +} + + /** * A client disconnected. Remove all of its data structure entries. * @@ -669,7 +792,6 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { if (ce->client == client) { - GNUNET_SERVER_client_drop (ce->client); GNUNET_CONTAINER_DLL_remove (client_head, client_tail, ce); GNUNET_free (ce); break; @@ -685,12 +807,14 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) wen = we->next; if (we->client != client) continue; - GNUNET_SERVER_client_drop (we->client); GNUNET_CONTAINER_DLL_remove (se->we_head, se->we_tail, we); GNUNET_free (we); } se = se->next; } + if ( (NULL == client_head) && + (GNUNET_YES == in_shutdown) ) + do_shutdown (); } @@ -702,8 +826,7 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) * @param c configuration to use */ static void -run (void *cls, - struct GNUNET_SERVER_Handle *server, +run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *c) { static const struct GNUNET_SERVER_MessageHandler handlers[] = { @@ -713,12 +836,13 @@ run (void *cls, {NULL, NULL, 0, 0} }; cfg = c; + srv = server; GNUNET_SERVER_add_handlers (server, handlers); nc = GNUNET_SERVER_notification_context_create (server, 16); GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); load (server); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); } @@ -733,10 +857,23 @@ int main (int argc, char *const *argv) { return (GNUNET_OK == - GNUNET_SERVICE_run (argc, - argv, - "statistics", - GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; + GNUNET_SERVICE_run (argc, argv, "statistics", + GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, &run, NULL)) ? 0 : 1; +} + +#ifdef LINUX +#include + +/** + * MINIMIZE heap size (way below 128k) since this process doesn't need much. + */ +void __attribute__ ((constructor)) GNUNET_ARM_memory_init () +{ + mallopt (M_TRIM_THRESHOLD, 4 * 1024); + mallopt (M_TOP_PAD, 1 * 1024); + malloc_trim (0); } +#endif + /* end of gnunet-service-statistics.c */