hi,

i am reading the book "Operating Systems Design and Implementation 3rd edition" which analyzes the minix source code... in the part of filesystems we see this code

PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
	no_sys,		/*  0 = unused	*/
	do_exit,	/*  1 = exit	*/
	do_fork,	/*  2 = fork	*/
	do_read,	/*  3 = read	*/
	do_write,	/*  4 = write	*/
	do_open,	/*  5 = open	*/
	do_close,	/*  6 = close	*/
	no_sys,		/*  7 = wait	*/
	do_creat,	/*  8 = creat	*/
	do_link,	/*  9 = link	*/
	do_unlink,	/* 10 = unlink	*/
	no_sys,		/* 11 = waitpid	*/
	do_chdir,	/* 12 = chdir	*/
	no_sys,		/* 13 = time	*/
	do_mknod,	/* 14 = mknod	*/
	do_chmod,	/* 15 = chmod	*/
	do_chown,	/* 16 = chown	*/
	no_sys,		/* 17 = break	*/
	do_stat,	/* 18 = stat	*/
	do_lseek,	/* 19 = lseek	*/
	no_sys,		/* 20 = getpid	*/
	do_mount,	/* 21 = mount	*/
	do_umount,	/* 22 = umount	*/
	do_set,		/* 23 = setuid	*/
	no_sys,		/* 24 = getuid	*/
	do_stime,	/* 25 = stime	*/
	no_sys,		/* 26 = ptrace	*/
	no_sys,		/* 27 = alarm	*/
	do_fstat,	/* 28 = fstat	*/
	no_sys,		/* 29 = pause	*/
	do_utime,	/* 30 = utime	*/
	no_sys,		/* 31 = (stty)	*/
	no_sys,		/* 32 = (gtty)	*/
	do_access,	/* 33 = access	*/
	no_sys,		/* 34 = (nice)	*/
	no_sys,		/* 35 = (ftime)	*/
	do_sync,	/* 36 = sync	*/
	no_sys,		/* 37 = kill	*/
	do_rename,	/* 38 = rename	*/
	do_mkdir,	/* 39 = mkdir	*/
	do_unlink,	/* 40 = rmdir	*/
	do_dup,		/* 41 = dup	*/
	do_pipe,	/* 42 = pipe	*/
	no_sys,		/* 43 = times	*/
	no_sys,		/* 44 = (prof)	*/
	no_sys,		/* 45 = unused	*/
	do_set,		/* 46 = setgid	*/
	no_sys,		/* 47 = getgid	*/
	no_sys,		/* 48 = (signal)*/
	no_sys,		/* 49 = unused	*/
	no_sys,		/* 50 = unused	*/
	no_sys,		/* 51 = (acct)	*/
	no_sys,		/* 52 = (phys)	*/
	no_sys,		/* 53 = (lock)	*/
	do_ioctl,	/* 54 = ioctl	*/
	do_fcntl,	/* 55 = fcntl	*/
	no_sys,		/* 56 = (mpx)	*/
	no_sys,		/* 57 = unused	*/
	no_sys,		/* 58 = unused	*/
	do_exec,	/* 59 = execve	*/
	do_umask,	/* 60 = umask	*/
	do_chroot,	/* 61 = chroot	*/
	do_setsid,	/* 62 = setsid	*/
	no_sys,		/* 63 = getpgrp	*/

	no_sys,		/* 64 = KSIG: signals originating in the kernel	*/
	do_unpause,	/* 65 = UNPAUSE	*/
	no_sys, 	/* 66 = unused  */
	do_revive,	/* 67 = REVIVE	*/
	no_sys,		/* 68 = TASK_REPLY	*/
	no_sys,		/* 69 = unused */
	no_sys,		/* 70 = unused */
	no_sys,		/* 71 = si */
	no_sys,		/* 72 = sigsuspend */
	no_sys,		/* 73 = sigpending */
	no_sys,		/* 74 = sigprocmask */
	no_sys,		/* 75 = sigreturn */
	do_reboot,	/* 76 = reboot */
	do_svrctl,	/* 77 = svrctl */

	no_sys,		/* 78 = unused */
	do_getsysinfo,  /* 79 = getsysinfo */
	no_sys,		/* 80 = unused */
	do_devctl,	/* 81 = devctl */
	do_fstatfs,	/* 82 = fstatfs */
	no_sys,		/* 83 = memalloc */
	no_sys,		/* 84 = memfree */
	do_select,	/* 85 = select */
	do_fchdir,	/* 86 = fchdir */
	do_fsync,	/* 87 = fsync */
	no_sys,		/* 88 = getpriority */
	no_sys,		/* 89 = setpriority */
	no_sys,		/* 90 = gettimeofday */
};

The problem is that i fail to understand what the hell is the above {syntactically}...

any help will be appreciated,
-nicolas

PS:: the source code is copied from the file src/servers/fs/table.c {that can be downloaded from here so there is no typo!
PS2:: merry christmas to all!! :)

Dani AI

Generated

As and noted, that odd-looking line is just MINIX using macros to express a normal C declaration in a way that stays compatible with both ANSI and older K&R compilers. The table is the filesystem server's system-call dispatch table: each entry is the address of a handler function (functions convert to pointers in initializers), and the two-part form is a macro trick that the preprocessor turns into a single, ordinary declaration describing an array of pointers to functions returning int.

To see exactly what the compiler sees, inspect the macro definitions and the preprocessed output in the source tree rather than guessing. Useful commands for a checked-out MINIX tree:

grep -nR "#define _PROTOTYPE" .
grep -nR "#define PUBLIC" .
gcc -E -dD src/servers/fs/table.c | sed -n '1,160p'

That will show where _PROTOTYPE and PUBLIC are defined and what the preprocessor expands the unusual syntax into. The macro exists to allow declarations to expand to either full prototypes (ANSI C) or empty parameter lists (K&R C), so checking the expansion removes doubt about exact linkage and parameter typing.

A reminder about reading such types: parentheses and the * operator control whether a name is an array, a pointer, or a function pointer — the usual source of confusion. A concise refresher on function-pointer syntax is available at the C language reference for function pointers, and GCC's preprocessor documentation explains the options used above for viewing macro expansion: , GCC preprocessor options.

Recommended Answers

All 7 Replies

call_vec is a array of pointer to functions which pass void and return int.
PUBLIC _PROTOTYPE should be some typedef.

>>PS2:: merry christmas to all!!
Same tt you!

An addition to dubeyprateek's reply....
PUBLIC is a preprocessor defination and _PROTOTYPE is typedef.

can you elaborate a bit more, because i still can't quite get it....

call_vec is a array of pointer to functions which pass void and return int.

shouldn't then be written like this int (*call_vec[])(void) thank you both for your answers!

-nicolas

PUBLIC _PROTOTYPE indicates folowing routine is a System call handler. Systems-tasks are more like a hardware abstraction. The call_vec table is an array of function pointers that is indexed by the
system-call number. In each line, the address of a system-call handler function is
assigned to one entry in the table and the index of the entry is the system-call number.
We could call the system-handler function directly using the system call _syscall. _syscall
takes three parameters: the recipient process, system-call number, and pointer to a
message structure.
PUBLIC int _syscall(int who, int syscallnr, register message *msgptr);

since _PROTOTYPE is a preprocessor macro, it's defination looks like
#define _PROTOTYPE(function, params) function params
Hence, int (*call_vec[]), (void) gets resolved to int (*call_vec[])(void)

commented: awsome!! +2

since _PROTOTYPE is a preprocessor macro, it's defination looks like
#define _PROTOTYPE(function, params) function params
Hence, int (*call_vec[]), (void) gets resolved to int (*call_vec[])(void)

you are right... the book mentions this trick when it talks about process implementation....

When compiling a C program the data types of the arguments and the returned values of functions must be known before code that references such data can be generated. In a complex system ordering of function definitions to meet this requirement is difficult, so C allows use of function prototypes to declare the arguments and return value types of a function before it is defined. The most important macro in ansi.h is _PROTOTYPE. This macro allows us to write function prototypes in the form

_PROTOTYPE (return-type function-name, (argument-type argument, ... ) )

and have this transformed by the C preprocessor into

return-type function-name(argument-type, argument, ...)

if the compiler is an ANSI Standard C compiler, or

return-type function-name()

if the compiler is an old-fashioned (i.e., Kernighan & Ritchie) compiler.

-nicolas

thank you all for your help!!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.