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 | My address is now "wnl@groupsys.com". |
---|
7 | |
---|
8 | Before you embark on a port, please send me a mail message telling me |
---|
9 | what platform you are porting top to. There are three reasons for |
---|
10 | this: (1) I may already have a port, (2) module naming needs to be |
---|
11 | centralized, (3) I want to loosely track the various porting efforts. |
---|
12 | You do not need to wait for an "okay", but I do want to know that you |
---|
13 | are working on it. And of course, once it is finished, please send me |
---|
14 | the module files so that I can add them to the main distribution! |
---|
15 | |
---|
16 | ---------- |
---|
17 | |
---|
18 | There is one set of functions which extract all the information that |
---|
19 | top needs for display. These functions are collected in to one file. |
---|
20 | To make top work on a different architecture simply requires a |
---|
21 | different implementation of these functions. The functions for a |
---|
22 | given architecture "foo" are stored in a file called "m_foo.c". The |
---|
23 | Configure script looks for these files and lets the configurer choose |
---|
24 | one of them. This file is called a "module". The idea is that making |
---|
25 | top work on a different machine only requires one additional file and |
---|
26 | does not require changes to any existing files. |
---|
27 | |
---|
28 | A module template is included in the distribution, called "m-template". |
---|
29 | To write your own module, it is a good idea to start with this template. |
---|
30 | If you architecture is similar to one for which a module already |
---|
31 | exists, then you can start with that module instead. If you do so, |
---|
32 | remember to change the "AUTHOR" section at the top! |
---|
33 | |
---|
34 | The first comment in a module contains information which is extracted |
---|
35 | and used by Configure. This information is marked with words in all |
---|
36 | capitals (such as "SYNOPSIS:" and "LIBS:"). Go look at m-template: it |
---|
37 | is fairly self-explanatory. The text after "LIBS:" (on the same line) |
---|
38 | is extracted and included in the LIBS definition of the Makefile so |
---|
39 | that extra libraries which may be necessary on some machines (such as |
---|
40 | "-lkvm") can be specified in the module. The text after "CFLAGS:" |
---|
41 | (on the same line) is extracted and included as flags in the "CFLAGS" |
---|
42 | definition of the Makefile (thus in every compilation step). This is |
---|
43 | used for rare circumstances only: please don't abuse this hook. |
---|
44 | |
---|
45 | Some operating systems have idiosyncrasies which will affect the form |
---|
46 | and/or content of the information top displays. You may wish to |
---|
47 | document such anomalies in the top man page. This can be done by adding |
---|
48 | a file called m_{modulename}.man (where {modulename} is replaced with |
---|
49 | the name of the module). Configure will automatically add this file to |
---|
50 | the end of the man page. See m_sunos4.man for an example. |
---|
51 | |
---|
52 | A module is concerned with two structures: |
---|
53 | |
---|
54 | The statics struct is filled in by machine_init. Each item is a |
---|
55 | pointer to a list of character pointers. The list is terminated |
---|
56 | with a null pointer. |
---|
57 | |
---|
58 | struct statics |
---|
59 | { |
---|
60 | char **procstate_names; /* process state names */ |
---|
61 | char **cpustate_names; /* cpu state names */ |
---|
62 | char **memory_names; /* memory information names */ |
---|
63 | }; |
---|
64 | |
---|
65 | The system_info struct is filled in by get_system_info and |
---|
66 | get_process_info. |
---|
67 | |
---|
68 | struct system_info |
---|
69 | { |
---|
70 | int last_pid; /* last pid assigned (0 means non-sequential assignment) */ |
---|
71 | double load_avg[NUM_AVERAGES]; /* see below */ |
---|
72 | int p_total; /* total number of processes */ |
---|
73 | int p_active; /* number of procs considered "active" */ |
---|
74 | int *procstates; /* array of process state counters */ |
---|
75 | int *cpustates; /* array of cpustate counters */ |
---|
76 | int *memory; /* memory information */ |
---|
77 | }; |
---|
78 | |
---|
79 | The last three pointers each point to an array of integers. The |
---|
80 | length of the array is determined by the length of the corresponding |
---|
81 | _names array in the statics structure. Furthermore, if an entry in a |
---|
82 | _names array is the empty string ("") then the corresponding value in |
---|
83 | the value array will be skipped over. The display routine displays, |
---|
84 | for example, the string procstate_names[0] then the number |
---|
85 | procstates[0], then procstate_names[1], procstates[1], etc. until |
---|
86 | procstate_names[N] == NULL. This allows for a tremendous amount of |
---|
87 | flexibility in labeling the displayed values. |
---|
88 | |
---|
89 | "procstates" and "memory" are displayed as straight integer values. |
---|
90 | Values in "cpustates" are displayed as a percentage * 10. For |
---|
91 | example, the (integer) value 105 is displayed as 10.5%. |
---|
92 | |
---|
93 | These routines must be defined by the machine dependent module. |
---|
94 | |
---|
95 | int machine_init(struct statics *) |
---|
96 | |
---|
97 | returns 0 on success and -1 on failure, |
---|
98 | prints error messages |
---|
99 | |
---|
100 | char *format_header(char *) |
---|
101 | |
---|
102 | Returns a string which should be used as the header for the |
---|
103 | process display area. The argument is a string used to label |
---|
104 | the username column (either "USERNAME" or "UID") and is always |
---|
105 | 8 characters in length. |
---|
106 | |
---|
107 | void get_system_info(struct system_info *) |
---|
108 | |
---|
109 | caddr_t get_process_info(struct system_info *, int, int, int (*func)()) |
---|
110 | |
---|
111 | returns a handle to use with format_next_process |
---|
112 | |
---|
113 | char *format_next_process(caddr_t, char *(*func)()) |
---|
114 | |
---|
115 | returns string which describes next process |
---|
116 | |
---|
117 | int proc_compare(caddr_t, caddr_t) |
---|
118 | |
---|
119 | qsort comparison function |
---|
120 | |
---|
121 | uid_t proc_owner(pid_t) |
---|
122 | |
---|
123 | Returns the uid owner of the process specified by the pid argument. |
---|
124 | This function is VERY IMPORTANT. If it fails to do its job, then |
---|
125 | top may pose a security risk. |
---|
126 | |
---|
127 | |
---|
128 | get_process_info is called immediately after get_system_info. In |
---|
129 | fact, the two functions could be rolled in to one. The reason they |
---|
130 | are not is mostly historical. |
---|
131 | |
---|
132 | Top relies on the existence of a function called "setpriority" to |
---|
133 | change a process's priority. This exists as a kernel call on most 4.3 |
---|
134 | BSD derived Unixes. If neither your operating system nor your C |
---|
135 | library supplies such a function, then you will need to add one to the |
---|
136 | module. It is defined as follows: |
---|
137 | |
---|
138 | int setpriority (int dummy, int who, int niceval) |
---|
139 | |
---|
140 | For the purposes of top, the first argument is meaningless. |
---|
141 | The second is the pid and the third is the new nice value. |
---|
142 | This function should behave just like a kernel call, setting |
---|
143 | errno and returning -1 in case of an error. This function MUST |
---|
144 | check to make sure that a non-root user does not specify a nice |
---|
145 | value less than the process's current value. If it detects such |
---|
146 | a condition, it should set errno to EACCES and return -1. |
---|
147 | Other possible ERRNO values: ESRCH when pid "who" does not exist, |
---|
148 | EPERM when the invoker is not root and not the same as the |
---|
149 | process owner. |
---|
150 | |
---|
151 | Note that top checks process ownership and should never call setpriority |
---|
152 | when the invoker's uid is not root and not the same as the process's owner |
---|
153 | uid. |
---|
154 | |
---|
155 | |
---|
156 | The file "machine.h" contains definitions which are useful to modules |
---|
157 | and to top.c (such as the structure definitions). You SHOULD NOT need |
---|
158 | to change it when porting to a new platform. |
---|
159 | |
---|
160 | Porting to a new platform should NOT require any changes to existing |
---|
161 | files. You should only need to add m_ files. If you feel you need a |
---|
162 | change in one of the existing files, please contact me so that we can |
---|
163 | discuss the details. I want to keep such changes as general as |
---|
164 | possible. |
---|
165 | |
---|