166 lines
6.9 KiB
Plaintext
166 lines
6.9 KiB
Plaintext
|
Instructions for porting top to other architectures.
|
||
|
|
||
|
This is still a preliminary document. Suggestions for improvement are
|
||
|
most welcome.
|
||
|
|
||
|
My address is now "lefebvre@dis.anl.gov".
|
||
|
|
||
|
Before you embark on a port, please send me a mail message telling me
|
||
|
what platform you are porting top to. There are three reasons for
|
||
|
this: (1) I may already have a port, (2) module naming needs to be
|
||
|
centralized, (3) I want to loosely track the various porting efforts.
|
||
|
You do not need to wait for an "okay", but I do want to know that you
|
||
|
are working on it. And of course, once it is finished, please send me
|
||
|
the module files so that I can add them to the main distribution!
|
||
|
|
||
|
----------
|
||
|
|
||
|
There is one set of functions which extract all the information that
|
||
|
top needs for display. These functions are collected in to one file.
|
||
|
To make top work on a different architecture simply requires a
|
||
|
different implementation of these functions. The functions for a
|
||
|
given architecture "foo" are stored in a file called "m_foo.c". The
|
||
|
Configure script looks for these files and lets the configurer choose
|
||
|
one of them. This file is called a "module". The idea is that making
|
||
|
top work on a different machine only requires one additional file and
|
||
|
does not require changes to any existing files.
|
||
|
|
||
|
A module template is included in the distribution, called "m-template".
|
||
|
To write your own module, it is a good idea to start with this template.
|
||
|
If you architecture is similar to one for which a module already
|
||
|
exists, then you can start with that module instead. If you do so,
|
||
|
remember to change the "AUTHOR" section at the top!
|
||
|
|
||
|
The first comment in a module contains information which is extracted
|
||
|
and used by Configure. This information is marked with words in all
|
||
|
capitals (such as "SYNOPSIS:" and "LIBS:"). Go look at m-template: it
|
||
|
is fairly self-explanatory. The text after "LIBS:" (on the same line)
|
||
|
is extracted and included in the LIBS definition of the Makefile so
|
||
|
that extra libraries which may be necessary on some machines (such as
|
||
|
"-lkvm") can be specified in the module. The text after "CFLAGS:"
|
||
|
(on the same line) is extracted and included as flags in the "CFLAGS"
|
||
|
definition of the Makefile (thus in every compilation step). This is
|
||
|
used for rare circumstances only: please don't abuse this hook.
|
||
|
|
||
|
Some operating systems have idiosyncrasies which will affect the form
|
||
|
and/or content of the information top displays. You may wish to
|
||
|
document such anomalies in the top man page. This can be done by adding
|
||
|
a file called m_{modulename}.man (where {modulename} is replaced with
|
||
|
the name of the module). Configure will automatically add this file to
|
||
|
the end of the man page. See m_sunos4.man for an example.
|
||
|
|
||
|
A module is concerned with two structures:
|
||
|
|
||
|
The statics struct is filled in by machine_init. Each item is a
|
||
|
pointer to a list of character pointers. The list is terminated
|
||
|
with a null pointer.
|
||
|
|
||
|
struct statics
|
||
|
{
|
||
|
char **procstate_names; /* process state names */
|
||
|
char **cpustate_names; /* cpu state names */
|
||
|
char **memory_names; /* memory information names */
|
||
|
};
|
||
|
|
||
|
The system_info struct is filled in by get_system_info and
|
||
|
get_process_info.
|
||
|
|
||
|
struct system_info
|
||
|
{
|
||
|
int last_pid; /* last pid assigned (0 means non-sequential assignment) */
|
||
|
double load_avg[NUM_AVERAGES]; /* see below */
|
||
|
int p_total; /* total number of processes */
|
||
|
int p_active; /* number of procs considered "active" */
|
||
|
int *procstates; /* array of process state counters */
|
||
|
int *cpustates; /* array of cpustate counters */
|
||
|
int *memory; /* memory information */
|
||
|
};
|
||
|
|
||
|
The last three pointers each point to an array of integers. The
|
||
|
length of the array is determined by the length of the corresponding
|
||
|
_names array in the statics structure. Furthermore, if an entry in a
|
||
|
_names array is the empty string ("") then the corresponding value in
|
||
|
the value array will be skipped over. The display routine displays,
|
||
|
for example, the string procstate_names[0] then the number
|
||
|
procstates[0], then procstate_names[1], procstates[1], etc. until
|
||
|
procstate_names[N] == NULL. This allows for a tremendous amount of
|
||
|
flexibility in labeling the displayed values.
|
||
|
|
||
|
"procstates" and "memory" are displayed as straight integer values.
|
||
|
Values in "cpustates" are displayed as a percentage * 10. For
|
||
|
example, the (integer) value 105 is displayed as 10.5%.
|
||
|
|
||
|
These routines must be defined by the machine dependent module.
|
||
|
|
||
|
int machine_init(struct statics *)
|
||
|
|
||
|
returns 0 on success and -1 on failure,
|
||
|
prints error messages
|
||
|
|
||
|
char *format_header(char *)
|
||
|
|
||
|
Returns a string which should be used as the header for the
|
||
|
process display area. The argument is a string used to label
|
||
|
the username column (either "USERNAME" or "UID") and is always
|
||
|
8 characters in length.
|
||
|
|
||
|
void get_system_info(struct system_info *)
|
||
|
|
||
|
caddr_t get_process_info(struct system_info *, int, int, int (*func)())
|
||
|
|
||
|
returns a handle to use with format_next_process
|
||
|
|
||
|
char *format_next_process(caddr_t, char *(*func)())
|
||
|
|
||
|
returns string which describes next process
|
||
|
|
||
|
int proc_compare(caddr_t, caddr_t)
|
||
|
|
||
|
qsort comparison function
|
||
|
|
||
|
uid_t proc_owner(pid_t)
|
||
|
|
||
|
Returns the uid owner of the process specified by the pid argument.
|
||
|
This function is VERY IMPORTANT. If it fails to do its job, then
|
||
|
top may pose a security risk.
|
||
|
|
||
|
|
||
|
get_process_info is called immediately after get_system_info. In
|
||
|
fact, the two functions could be rolled in to one. The reason they
|
||
|
are not is mostly historical.
|
||
|
|
||
|
Top relies on the existence of a function called "setpriority" to
|
||
|
change a process's priority. This exists as a kernel call on most 4.3
|
||
|
BSD derived Unixes. If neither your operating system nor your C
|
||
|
library supplies such a function, then you will need to add one to the
|
||
|
module. It is defined as follows:
|
||
|
|
||
|
int setpriority (int dummy, int who, int niceval)
|
||
|
|
||
|
For the purposes of top, the first argument is meaningless.
|
||
|
The second is the pid and the third is the new nice value.
|
||
|
This function should behave just like a kernel call, setting
|
||
|
errno and returning -1 in case of an error. This function MUST
|
||
|
check to make sure that a non-root user does not specify a nice
|
||
|
value less than the process's current value. If it detects such
|
||
|
a condition, it should set errno to EACCES and return -1.
|
||
|
Other possible ERRNO values: ESRCH when pid "who" does not exist,
|
||
|
EPERM when the invoker is not root and not the same as the
|
||
|
process owner.
|
||
|
|
||
|
Note that top checks process ownership and should never call setpriority
|
||
|
when the invoker's uid is not root and not the same as the process's owner
|
||
|
uid.
|
||
|
|
||
|
|
||
|
The file "machine.h" contains definitions which are useful to modules
|
||
|
and to top.c (such as the structure definitions). You SHOULD NOT need
|
||
|
to change it when porting to a new platform.
|
||
|
|
||
|
Porting to a new platform should NOT require any changes to existing
|
||
|
files. You should only need to add m_ files. If you feel you need a
|
||
|
change in one of the existing files, please contact me so that we can
|
||
|
discuss the details. I want to keep such changes as general as
|
||
|
possible.
|
||
|
|