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