1Instructions for porting top to other architectures. 2 3This is still a preliminary document. Suggestions for improvement are 4most welcome. 5 6Before you embark on a port, please send me a mail message telling me 7what platform you are porting top to. There are three reasons for 8this: (1) I may already have a port, (2) module naming needs to be 9centralized, (3) I want to loosely track the various porting efforts. 10You do not need to wait for an "okay", but I do want to know that you 11are working on it. And of course, once it is finished, please send me 12the module files so that I can add them to the main distribution! 13 14---------- 15 16There is one set of functions which extract all the information that 17top needs for display. These functions are collected in to one file. 18To make top work on a different architecture simply requires a 19different implementation of these functions. The functions for a 20given architecture "foo" are stored in a file called "m_foo.c". The 21Configure script looks for these files and lets the configurer choose 22one of them. This file is called a "module". The idea is that making 23top work on a different machine only requires one additional file and 24does not require changes to any existing files. 25 26A module template is included in the distribution, called "m-template". 27To write your own module, it is a good idea to start with this template. 28If you architecture is similar to one for which a module already 29exists, then you can start with that module instead. If you do so, 30remember to change the "AUTHOR" section at the top! 31 32The first comment in a module contains information which is extracted 33and used by Configure. This information is marked with words in all 34capitals (such as "SYNOPSIS:" and "LIBS:"). Go look at m-template: it 35is fairly self-explanatory. The text after "LIBS:" (on the same line) 36is extracted and included in the LIBS definition of the Makefile so 37that extra libraries which may be necessary on some machines (such as 38"-lkvm") can be specified in the module. The text after "CFLAGS:" 39(on the same line) is extracted and included as flags in the "CFLAGS" 40definition of the Makefile (thus in every compilation step). This is 41used for rare circumstances only: please don't abuse this hook. 42 43Some operating systems have idiosyncrasies which will affect the form 44and/or content of the information top displays. You may wish to 45document such anomalies in the top man page. This can be done by adding 46a file called m_{modulename}.man (where {modulename} is replaced with 47the name of the module). Configure will automatically add this file to 48the end of the man page. See m_sunos4.man for an example. 49 50A module is concerned with two structures: 51 52The statics struct is filled in by machine_init. Each item is a 53pointer to a list of character pointers. The list is terminated 54with a null pointer. 55 56struct statics 57{ 58 char **procstate_names; /* process state names */ 59 char **cpustate_names; /* cpu state names */ 60 char **memory_names; /* memory information names */ 61}; 62 63The system_info struct is filled in by get_system_info and 64get_process_info. 65 66struct system_info 67{ 68 int last_pid; /* last pid assigned (0 means non-sequential assignment) */ 69 double load_avg[NUM_AVERAGES]; /* see below */ 70 int p_total; /* total number of processes */ 71 int p_active; /* number of procs considered "active" */ 72 int *procstates; /* array of process state counters */ 73 int *cpustates; /* array of cpustate counters */ 74 int *memory; /* memory information */ 75}; 76 77The last three pointers each point to an array of integers. The 78length of the array is determined by the length of the corresponding 79_names array in the statics structure. Furthermore, if an entry in a 80_names array is the empty string ("") then the corresponding value in 81the value array will be skipped over. The display routine displays, 82for example, the string procstate_names[0] then the number 83procstates[0], then procstate_names[1], procstates[1], etc. until 84procstate_names[N] == NULL. This allows for a tremendous amount of 85flexibility in labeling the displayed values. 86 87"procstates" and "memory" are displayed as straight integer values. 88Values in "cpustates" are displayed as a percentage * 10. For 89example, the (integer) value 105 is displayed as 10.5%. 90 91These routines must be defined by the machine dependent module. 92 93int machine_init(struct statics *) 94 95 returns 0 on success and -1 on failure, 96 prints error messages 97 98char *format_header(char *) 99 100 Returns a string which should be used as the header for the 101 process display area. The argument is a string used to label 102 the username column (either "USERNAME" or "UID") and is always 103 8 characters in length. 104 105void get_system_info(struct system_info *) 106 107caddr_t get_process_info(struct system_info *, int, int, int (*func)()) 108 109 returns a handle to use with format_next_process 110 111char *format_next_process(caddr_t, char *(*func)()) 112 113 returns string which describes next process 114 115int proc_compare(caddr_t, caddr_t) 116 117 qsort comparison function 118 119uid_t proc_owner(pid_t) 120 121 Returns the uid owner of the process specified by the pid argument. 122 This function is VERY IMPORTANT. If it fails to do its job, then 123 top may pose a security risk. 124 125 126get_process_info is called immediately after get_system_info. In 127fact, the two functions could be rolled in to one. The reason they 128are not is mostly historical. 129 130Top relies on the existence of a function called "setpriority" to 131change a process's priority. This exists as a kernel call on most 4.3 132BSD derived Unixes. If neither your operating system nor your C 133library supplies such a function, then you will need to add one to the 134module. It is defined as follows: 135 136 int setpriority (int dummy, int who, int niceval) 137 138 For the purposes of top, the first argument is meaningless. 139 The second is the pid and the third is the new nice value. 140 This function should behave just like a kernel call, setting 141 errno and returning -1 in case of an error. This function MUST 142 check to make sure that a non-root user does not specify a nice 143 value less than the process's current value. If it detects such 144 a condition, it should set errno to EACCES and return -1. 145 Other possible ERRNO values: ESRCH when pid "who" does not exist, 146 EPERM when the invoker is not root and not the same as the 147 process owner. 148 149Note that top checks process ownership and should never call setpriority 150when the invoker's uid is not root and not the same as the process's owner 151uid. 152 153 154The file "machine.h" contains definitions which are useful to modules 155and to top.c (such as the structure definitions). You SHOULD NOT need 156to change it when porting to a new platform. 157 158Porting to a new platform should NOT require any changes to existing 159files. You should only need to add m_ files. If you feel you need a 160change in one of the existing files, please contact me so that we can 161discuss the details. I want to keep such changes as general as 162possible. 163 164-------- 165 166Changes were made to the module interface between 3.5 and 3.6. Here are 167the changes that need to be made to port a 3.5 module to 3.6: 168 169The array that stores memory statistics and is passed back in the system 170information structure as "memory" must now be an array of (signed) longs. 171This was done to more easily accomodate systems that have gigabytes of 172memory. Since the numbers are supposed to be kilobytes, a long can still 173represent up to 2 terabytes. Look for "int memory_stats[X]" (where "X" 174is some arbitrary number) and change it to "long memory_stats[X]". If 175the module support reporting swap information on a separate line, then 176its "swap_stats" array also needs to be an array of longs. 177 178The argument to proc_owner should be an int, as in "int pid". When it is 179used in proc_owner it should be cast as necessary. Many operating systems 180will require it to be cast to a pid_t before being compared to the appropriate 181element in the proc structure. 182 183In the function format_next_process, the last argument in the main call 184to sprintf is the string that contains the command for the process. 185Make sure that this last argument is enclosed in a call to "printable". 186For example: "printable(MPP(pp, p_comm))". 187 188The third argument to "get_process_info" needs to be changed to an integer, 189typically "int compare_index". The call to qsort in get_process_info may 190be guarded by "if (compare != NULL)". If it is, remove the if statement. 191 192The other changes to get_process_info depends on whether or not the module 193supports multiple sort orders. 194 195To support multiple keys: 196 197Create an array int (*proc_compares[])() and assign to it the list of 198comparison functions, NULL terminated. For example: 199 200int (*proc_compares[])() = { 201 compare_cpu, 202 compare_size, 203 compare_res, 204 compare_time, 205 NULL }; 206 207In get_process_info there is a call to qsort which uses one of the 208functions in proc_compares. It should be changed so that its fourth 209argument is "proc_compares[compare_index]". 210 211If the module contains the function "proc_compare", it should be removed. 212 213There should also be a NULL-terminated array of strings which list the names 214for the sort keys, for example: 215 216char *ordernames[] = 217{"cpu", "size", "res", "time", NULL}; 218 219To indicate that this module supports multiple sort keys, add the following 220line in machine_init: 221 222 statics->order_names = ordernames; 223 224If there is no support for multiple keys: 225 226Leave statics->order_names alone and call the comparison function of 227your choice in get_process_info, ignoring the third argument. 228 229 230