X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fprocesses.c;h=9d8bc01d468eb088c65845e119dde4d9c4584d1f;hb=90ac9957e95378d729bce1c00bb0ef2efadab33e;hp=cb6bb4871011744f9046c67ff600f88e578953f4;hpb=5f5ef3288c97d80f599ebabde73f0ae2117ec62c;p=collectd.git diff --git a/src/processes.c b/src/processes.c index cb6bb487..9d8bc01d 100644 --- a/src/processes.c +++ b/src/processes.c @@ -1,7 +1,7 @@ /** * collectd - src/processes.c * Copyright (C) 2005 Lyonel Vincent - * Copyright (C) 2006 Florian Forster (Mach code) + * Copyright (C) 2006-2007 Florian Forster (Mach code) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,7 +25,6 @@ #include "collectd.h" #include "common.h" #include "plugin.h" -#include "utils_debug.h" #include "configfile.h" /* Include header files for the mach system, if they exist.. */ @@ -69,6 +68,9 @@ # if HAVE_MACH_VM_PROT_H # include # endif +# if HAVE_SYS_SYSCTL_H +# include +# endif /* #endif HAVE_THREAD_INFO */ #elif KERNEL_LINUX @@ -78,70 +80,15 @@ # ifndef CONFIG_HZ # define CONFIG_HZ 100 # endif -#endif /* KERNEL_LINUX */ - -#define MODULE_NAME "processes" +/* #endif KERNEL_LINUX */ -#if HAVE_THREAD_INFO || KERNEL_LINUX -# define PROCESSES_HAVE_READ 1 #else -# define PROCESSES_HAVE_READ 0 +# error "No applicable input method." #endif #define BUFSIZE 256 -static char *processes_file = "processes.rrd"; -static char *processes_ds_def[] = -{ - "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:sleeping:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:zombies:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:stopped:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:paging:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:blocked:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - NULL -}; -static int processes_ds_num = 6; - -static char *ps_rss_file = "processes/ps_rss-%s.rrd"; -static char *ps_rss_ds_def[] = -{ - /* max = 2^63 - 1 */ - "DS:byte:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807", - NULL -}; -static int ps_rss_ds_num = 1; - -static char *ps_cputime_file = "processes/ps_cputime-%s.rrd"; -static char *ps_cputime_ds_def[] = -{ - /* 1 second in user-mode per second ought to be enough.. */ - "DS:user:COUNTER:"COLLECTD_HEARTBEAT":0:1000000", - "DS:syst:COUNTER:"COLLECTD_HEARTBEAT":0:1000000", - NULL -}; -static int ps_cputime_ds_num = 2; - -static char *ps_count_file = "processes/ps_count-%s.rrd"; -static char *ps_count_ds_def[] = -{ - "DS:processes:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - "DS:threads:GAUGE:"COLLECTD_HEARTBEAT":0:65535", - NULL -}; -static int ps_count_ds_num = 2; - -static char *ps_pagefaults_file = "processes/ps_pagefaults-%s.rrd"; -static char *ps_pagefaults_ds_def[] = -{ - /* max = 2^63 - 1 */ - "DS:minflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807", - "DS:majflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807", - NULL -}; -static int ps_pagefaults_ds_num = 2; - -static char *config_keys[] = +static const char *config_keys[] = { "Process", NULL @@ -373,7 +320,7 @@ static void ps_list_reset (void) { if (pse->age > 10) { - DBG ("Removing this procstat entry cause it's too old: " + DEBUG ("Removing this procstat entry cause it's too old: " "id = %lu; name = %s;", pse->id, ps->name); @@ -400,7 +347,7 @@ static void ps_list_reset (void) } /* for (ps = list_head_g; ps != NULL; ps = ps->next) */ } -static int ps_config (char *key, char *value) +static int ps_config (const char *key, const char *value) { if (strcasecmp (key, "Process") == 0) { @@ -414,7 +361,7 @@ static int ps_config (char *key, char *value) return (0); } -static void ps_init (void) +static int ps_init (void) { #if HAVE_THREAD_INFO kern_return_t status; @@ -435,149 +382,79 @@ static void ps_init (void) &pset_list, &pset_list_len)) != KERN_SUCCESS) { - syslog (LOG_ERR, "host_processor_sets failed: %s\n", + ERROR ("host_processor_sets failed: %s\n", mach_error_string (status)); pset_list = NULL; pset_list_len = 0; - return; + return (-1); } /* #endif HAVE_THREAD_INFO */ #elif KERNEL_LINUX pagesize_g = sysconf(_SC_PAGESIZE); - DBG ("pagesize_g = %li; CONFIG_HZ = %i;", + DEBUG ("pagesize_g = %li; CONFIG_HZ = %i;", pagesize_g, CONFIG_HZ); #endif /* KERNEL_LINUX */ - return; -} - -static void ps_write (char *host, char *inst, char *val) -{ - rrd_update_file (host, processes_file, val, - processes_ds_def, processes_ds_num); -} - -static void ps_rss_write (char *host, char *inst, char *val) -{ - char filename[256]; - int status; - - status = snprintf (filename, 256, ps_rss_file, inst); - if ((status < 1) || (status >= 256)) - return; - - rrd_update_file (host, filename, val, ps_rss_ds_def, ps_rss_ds_num); -} - -static void ps_cputime_write (char *host, char *inst, char *val) -{ - char filename[256]; - int status; - - status = snprintf (filename, 256, ps_cputime_file, inst); - if ((status < 1) || (status >= 256)) - return; - - DBG ("host = %s; filename = %s; val = %s;", - host, filename, val); - rrd_update_file (host, filename, val, - ps_cputime_ds_def, ps_cputime_ds_num); -} - -static void ps_count_write (char *host, char *inst, char *val) -{ - char filename[256]; - int status; - - status = snprintf (filename, 256, ps_count_file, inst); - if ((status < 1) || (status >= 256)) - return; - - DBG ("host = %s; filename = %s; val = %s;", - host, filename, val); - rrd_update_file (host, filename, val, - ps_count_ds_def, ps_count_ds_num); -} - -static void ps_pagefaults_write (char *host, char *inst, char *val) -{ - char filename[256]; - int status; - - status = snprintf (filename, 256, ps_pagefaults_file, inst); - if ((status < 1) || (status >= 256)) - return; - - DBG ("host = %s; filename = %s; val = %s;", - host, filename, val); - rrd_update_file (host, filename, val, - ps_pagefaults_ds_def, ps_pagefaults_ds_num); -} + return (0); +} /* int ps_init */ -#if PROCESSES_HAVE_READ -static void ps_submit (int running, - int sleeping, - int zombies, - int stopped, - int paging, - int blocked) +static void ps_submit_state (const char *state, double value) { - char buf[BUFSIZE]; + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; - if (snprintf (buf, BUFSIZE, "%u:%i:%i:%i:%i:%i:%i", - (unsigned int) curtime, - running, sleeping, zombies, stopped, paging, - blocked) >= BUFSIZE) - return; + values[0].gauge = value; - DBG ("running = %i; sleeping = %i; zombies = %i; stopped = %i; paging = %i; blocked = %i;", - running, sleeping, zombies, stopped, paging, blocked); + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "processes"); + strcpy (vl.plugin_instance, ""); + strncpy (vl.type_instance, state, sizeof (vl.type_instance)); - plugin_submit (MODULE_NAME, "-", buf); + plugin_dispatch_values ("ps_state", &vl); } static void ps_submit_proc_list (procstat_t *ps) { - char buffer[64]; - - if (ps == NULL) - return; - - snprintf (buffer, 64, "%u:%lu", - (unsigned int) curtime, - ps->vmem_rss); - buffer[63] = '\0'; - plugin_submit ("ps_rss", ps->name, buffer); - - snprintf (buffer, 64, "%u:%u:%u", - (unsigned int) curtime, - /* Make the counter overflow */ - (unsigned int) (ps->cpu_user_counter & 0xFFFFFFFF), - (unsigned int) (ps->cpu_system_counter & 0xFFFFFFFF)); - buffer[63] = '\0'; - plugin_submit ("ps_cputime", ps->name, buffer); - - snprintf (buffer, 64, "%u:%lu:%lu", - (unsigned int) curtime, - ps->num_proc, ps->num_lwp); - buffer[63] = '\0'; - plugin_submit ("ps_count", ps->name, buffer); - - snprintf (buffer, 64, "%u:%lu:%lu", - (unsigned int) curtime, - ps->vmem_minflt_counter, ps->vmem_majflt_counter); - buffer[63] = '\0'; - plugin_submit ("ps_pagefaults", ps->name, buffer); - - DBG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; " - "vmem_minflt_counter = %i; vmem_majflt_counter = %i; " - "cpu_user_counter = %i; cpu_system_counter = %i;", + value_t values[2]; + value_list_t vl = VALUE_LIST_INIT; + + vl.values = values; + vl.values_len = 2; + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "processes"); + strncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance)); + + vl.values[0].gauge = ps->vmem_rss; + vl.values_len = 1; + plugin_dispatch_values ("ps_rss", &vl); + + vl.values[0].counter = ps->cpu_user_counter; + vl.values[1].counter = ps->cpu_system_counter; + vl.values_len = 2; + plugin_dispatch_values ("ps_cputime", &vl); + + vl.values[0].gauge = ps->num_proc; + vl.values[1].gauge = ps->num_lwp; + vl.values_len = 2; + plugin_dispatch_values ("ps_count", &vl); + + vl.values[0].counter = ps->vmem_minflt_counter; + vl.values[1].counter = ps->vmem_majflt_counter; + vl.values_len = 2; + plugin_dispatch_values ("ps_pagefaults", &vl); + + DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; " + "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; " + "cpu_user_counter = %lu; cpu_system_counter = %lu;", ps->name, ps->num_proc, ps->num_lwp, ps->vmem_rss, - ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter, - ps->cpu_system_counter); - -} + ps->vmem_minflt_counter, ps->vmem_majflt_counter, + ps->cpu_user_counter, ps->cpu_system_counter); +} /* void ps_submit_proc_list */ #if KERNEL_LINUX static int *ps_read_tasks (int pid) @@ -595,8 +472,7 @@ static int *ps_read_tasks (int pid) if ((dh = opendir (dirname)) == NULL) { - syslog (LOG_NOTICE, "processes plugin: Failed to open directory `%s'", - dirname); + DEBUG ("Failed to open directory `%s'", dirname); return (NULL); } @@ -616,7 +492,7 @@ static int *ps_read_tasks (int pid) { if (list != NULL) free (list); - syslog (LOG_ERR, "processes plugin: " + ERROR ("processes plugin: " "Failed to allocate more memory."); return (NULL); } @@ -634,11 +510,14 @@ static int *ps_read_tasks (int pid) closedir (dh); + if (list_len == 0) + return (NULL); + assert (list_len < list_size); assert (list[list_len] == 0); return (list); -} +} /* int *ps_read_tasks */ int ps_read_process (int pid, procstat_t *ps, char *state) { @@ -678,20 +557,17 @@ int ps_read_process (int pid, procstat_t *ps, char *state) fields_len = strsplit (buffer, fields, 64); if (fields_len < 24) { - DBG ("`%s' has only %i fields..", - filename, fields_len); + DEBUG ("processes plugin: ps_read_process (pid = %i):" + " `%s' has only %i fields..", + (int) pid, filename, fields_len); return (-1); } - else if (fields_len != 41) - { - DBG ("WARNING: (fields_len = %i) != 41", fields_len); - } /* copy the name, strip brackets in the process */ name_len = strlen (fields[1]) - 2; if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')')) { - DBG ("No brackets found in process name: `%s'", fields[1]); + DEBUG ("No brackets found in process name: `%s'", fields[1]); return (-1); } fields[1] = fields[1] + 1; @@ -700,17 +576,21 @@ int ps_read_process (int pid, procstat_t *ps, char *state) ppid = atoi (fields[3]); - if ((tasks = ps_read_tasks (pid)) == NULL) + *state = fields[2][0]; + + if (*state == 'Z') { - /* This happends for zombied, e.g. */ - DBG ("ps_read_tasks (%i) failed.", pid); - *state = 'Z'; ps->num_lwp = 0; ps->num_proc = 0; } + else if ((tasks = ps_read_tasks (pid)) == NULL) + { + /* Kernel 2.4 or so */ + ps->num_lwp = 1; + ps->num_proc = 1; + } else { - *state = '\0'; ps->num_lwp = 0; ps->num_proc = 1; for (i = 0; tasks[i] != 0; i++) @@ -720,10 +600,10 @@ int ps_read_process (int pid, procstat_t *ps, char *state) tasks = NULL; } - /* Leave the rest at zero if this is only an LWP */ + /* Leave the rest at zero if this is only a zombi */ if (ps->num_proc == 0) { - DBG ("This is only an LWP: pid = %i; name = %s;", + DEBUG ("This is only a zombi: pid = %i; name = %s;", pid, ps->name); return (0); } @@ -743,14 +623,48 @@ int ps_read_process (int pid, procstat_t *ps, char *state) ps->cpu_system_counter = (unsigned long) cpu_system_counter; ps->vmem_rss = (unsigned long) vmem_rss; - *state = fields[2][0]; - /* success */ return (0); } /* int ps_read_process (...) */ #endif /* KERNEL_LINUX */ -static void ps_read (void) +#if HAVE_THREAD_INFO +static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_len) +{ + int mib[4]; + + struct kinfo_proc kp; + size_t kp_size; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + + if (pid_for_task (t, pid) != KERN_SUCCESS) + return (-1); + mib[3] = *pid; + + kp_size = sizeof (kp); + if (sysctl (mib, 4, &kp, &kp_size, NULL, 0) != 0) + return (-1); + + if (name_max_len > (MAXCOMLEN + 1)) + name_max_len = MAXCOMLEN + 1; + + strncpy (name, kp.kp_proc.p_comm, name_max_len - 1); + name[name_max_len - 1] = '\0'; + + DEBUG ("pid = %i; name = %s;", *pid, name); + + /* We don't do the special handling for `p_comm == "LaunchCFMApp"' as + * `top' does it, because it is a lot of work and only used when + * debugging. -octo */ + + return (0); +} +#endif /* HAVE_THREAD_INFO */ + +static int ps_read (void) { #if HAVE_THREAD_INFO kern_return_t status; @@ -762,6 +676,9 @@ static void ps_read (void) task_array_t task_list; mach_msg_type_number_t task_list_len; + int task_pid; + char task_name[MAXCOMLEN + 1]; + int thread; thread_act_array_t thread_list; mach_msg_type_number_t thread_list_len; @@ -774,6 +691,11 @@ static void ps_read (void) int stopped = 0; int blocked = 0; + procstat_t *ps; + procstat_entry_t pse; + + ps_list_reset (); + /* * The Mach-concept is a little different from the traditional UNIX * concept: All the work is done in threads. Threads are contained in @@ -788,7 +710,7 @@ static void ps_read (void) pset_list[pset], &port_pset_priv)) != KERN_SUCCESS) { - syslog (LOG_ERR, "host_processor_set_priv failed: %s\n", + ERROR ("host_processor_set_priv failed: %s\n", mach_error_string (status)); continue; } @@ -797,7 +719,7 @@ static void ps_read (void) &task_list, &task_list_len)) != KERN_SUCCESS) { - syslog (LOG_ERR, "processor_set_tasks failed: %s\n", + ERROR ("processor_set_tasks failed: %s\n", mach_error_string (status)); mach_port_deallocate (port_task_self, port_pset_priv); continue; @@ -805,6 +727,71 @@ static void ps_read (void) for (task = 0; task < task_list_len; task++) { + ps = NULL; + if (mach_get_task_name (task_list[task], + &task_pid, + task_name, PROCSTAT_NAME_LEN) == 0) + ps = ps_list_search (task_name); + + /* Collect more detailed statistics for this process */ + if (ps != NULL) + { + task_basic_info_data_t task_basic_info; + mach_msg_type_number_t task_basic_info_len; + task_events_info_data_t task_events_info; + mach_msg_type_number_t task_events_info_len; + task_absolutetime_info_data_t task_absolutetime_info; + mach_msg_type_number_t task_absolutetime_info_len; + + memset (&pse, '\0', sizeof (pse)); + pse.id = task_pid; + + task_basic_info_len = TASK_BASIC_INFO_COUNT; + status = task_info (task_list[task], + TASK_BASIC_INFO, + (task_info_t) &task_basic_info, + &task_basic_info_len); + if (status != KERN_SUCCESS) + { + ERROR ("task_info failed: %s", + mach_error_string (status)); + continue; /* with next thread_list */ + } + + task_events_info_len = TASK_EVENTS_INFO_COUNT; + status = task_info (task_list[task], + TASK_EVENTS_INFO, + (task_info_t) &task_events_info, + &task_events_info_len); + if (status != KERN_SUCCESS) + { + ERROR ("task_info failed: %s", + mach_error_string (status)); + continue; /* with next thread_list */ + } + + task_absolutetime_info_len = TASK_ABSOLUTETIME_INFO_COUNT; + status = task_info (task_list[task], + TASK_ABSOLUTETIME_INFO, + (task_info_t) &task_absolutetime_info, + &task_absolutetime_info_len); + if (status != KERN_SUCCESS) + { + ERROR ("task_info failed: %s", + mach_error_string (status)); + continue; /* with next thread_list */ + } + + pse.num_proc++; + pse.vmem_rss = task_basic_info.resident_size; + + pse.vmem_minflt_counter = task_events_info.cow_faults; + pse.vmem_majflt_counter = task_events_info.faults; + + pse.cpu_user_counter = task_absolutetime_info.total_user; + pse.cpu_system_counter = task_absolutetime_info.total_system; + } + status = task_threads (task_list[task], &thread_list, &thread_list_len); if (status != KERN_SUCCESS) @@ -814,7 +801,7 @@ static void ps_read (void) * thread is nonsense, since the task/process * is dead. */ zombies++; - DBG ("task_threads failed: %s", + DEBUG ("task_threads failed: %s", mach_error_string (status)); if (task_list[task] != port_task_self) mach_port_deallocate (port_task_self, @@ -831,7 +818,7 @@ static void ps_read (void) &thread_data_len); if (status != KERN_SUCCESS) { - syslog (LOG_ERR, "thread_info failed: %s\n", + ERROR ("thread_info failed: %s", mach_error_string (status)); if (task_list[task] != port_task_self) mach_port_deallocate (port_task_self, @@ -839,6 +826,9 @@ static void ps_read (void) continue; /* with next thread_list */ } + if (ps != NULL) + pse.num_lwp++; + switch (thread_data.run_state) { case TH_STATE_RUNNING: @@ -860,8 +850,7 @@ static void ps_read (void) * There's only zombie tasks, which are * handled above. */ default: - syslog (LOG_WARNING, - "Unknown thread status: %s", + WARNING ("Unknown thread status: %s", thread_data.run_state); break; } /* switch (thread_data.run_state) */ @@ -871,7 +860,7 @@ static void ps_read (void) status = mach_port_deallocate (port_task_self, thread_list[thread]); if (status != KERN_SUCCESS) - syslog (LOG_ERR, "mach_port_deallocate failed: %s", + ERROR ("mach_port_deallocate failed: %s", mach_error_string (status)); } } /* for (thread_list) */ @@ -881,7 +870,7 @@ static void ps_read (void) thread_list_len * sizeof (thread_act_t))) != KERN_SUCCESS) { - syslog (LOG_ERR, "vm_deallocate failed: %s", + ERROR ("vm_deallocate failed: %s", mach_error_string (status)); } thread_list = NULL; @@ -895,16 +884,19 @@ static void ps_read (void) status = mach_port_deallocate (port_task_self, task_list[task]); if (status != KERN_SUCCESS) - syslog (LOG_ERR, "mach_port_deallocate failed: %s", + ERROR ("mach_port_deallocate failed: %s", mach_error_string (status)); } + + if (ps != NULL) + ps_list_add (task_name, &pse); } /* for (task_list) */ if ((status = vm_deallocate (port_task_self, (vm_address_t) task_list, task_list_len * sizeof (task_t))) != KERN_SUCCESS) { - syslog (LOG_ERR, "vm_deallocate failed: %s", + ERROR ("vm_deallocate failed: %s", mach_error_string (status)); } task_list = NULL; @@ -913,12 +905,19 @@ static void ps_read (void) if ((status = mach_port_deallocate (port_task_self, port_pset_priv)) != KERN_SUCCESS) { - syslog (LOG_ERR, "mach_port_deallocate failed: %s", + ERROR ("mach_port_deallocate failed: %s", mach_error_string (status)); } } /* for (pset_list) */ - ps_submit (running, sleeping, zombies, stopped, -1, blocked); + ps_submit_state ("running", running); + ps_submit_state ("sleeping", sleeping); + ps_submit_state ("zombies", zombies); + ps_submit_state ("stopped", stopped); + ps_submit_state ("blocked", blocked); + + for (ps = list_head_g; ps != NULL; ps = ps->next) + ps_submit_proc_list (ps); /* #endif HAVE_THREAD_INFO */ #elif KERNEL_LINUX @@ -945,8 +944,10 @@ static void ps_read (void) if ((proc = opendir ("/proc")) == NULL) { - syslog (LOG_ERR, "Cannot open `/proc': %s", strerror (errno)); - return; + char errbuf[1024]; + ERROR ("Cannot open `/proc': %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); } while ((ent = readdir (proc)) != NULL) @@ -960,7 +961,7 @@ static void ps_read (void) status = ps_read_process (pid, &ps, &state); if (status != 0) { - DBG ("ps_read_process failed: %i", status); + DEBUG ("ps_read_process failed: %i", status); continue; } @@ -996,25 +997,24 @@ static void ps_read (void) closedir (proc); - ps_submit (running, sleeping, zombies, stopped, paging, blocked); + ps_submit_state ("running", running); + ps_submit_state ("sleeping", sleeping); + ps_submit_state ("zombies", zombies); + ps_submit_state ("stopped", stopped); + ps_submit_state ("paging", paging); + ps_submit_state ("blocked", blocked); for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next) ps_submit_proc_list (ps_ptr); #endif /* KERNEL_LINUX */ -} -#else -# define ps_read NULL -#endif /* PROCESSES_HAVE_READ */ + + return (0); +} /* int ps_read */ void module_register (void) { - plugin_register (MODULE_NAME, ps_init, ps_read, ps_write); - plugin_register ("ps_rss", NULL, NULL, ps_rss_write); - plugin_register ("ps_cputime", NULL, NULL, ps_cputime_write); - plugin_register ("ps_count", NULL, NULL, ps_count_write); - plugin_register ("ps_pagefaults", NULL, NULL, ps_pagefaults_write); - cf_register (MODULE_NAME, ps_config, config_keys, config_keys_num); -} - -#undef BUFSIZE -#undef MODULE_NAME + plugin_register_config ("processes", ps_config, + config_keys, config_keys_num); + plugin_register_init ("processes", ps_init); + plugin_register_read ("processes", ps_read); +} /* void module_register */