Section 2.5. Quirky C Language Usage


2.5. Quirky C Language Usage

Within the Linux kernel are a number of conventions that can require lots of searching and reading to discover their ultimate meaning and intent. This section clarifies some of the obscure or misleading usage of C, with a specific focus on common C conventions that are used throughout the 2.6 Linux kernel.

2.5.1. asmlinkage

asmlinkage tells the compiler to pass parameters on the local stack. This is related to the FASTCALL macro, which resolves to tell the (architecture-specific) compiler to pass parameters in the general-purpose registers. Here are the macros from include/asm/linkage.h:

 ----------------------------------------------------------------------- include/asm/linkage.h 4  #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) 5  #define FASTCALL(x)  x __attribute__((regparm(3))) 6  #define fastcall  __attribute__((regparm(3))) ----------------------------------------------------------------------- 

An example of asmlinkage is as follows:

 asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz) 

2.5.2. UL

UL is commonly appended to the end of a numerical constant to mark an "unsigned long." UL (or L for long) is necessary because it tells the compiler to treat the value as a long value. This prevents certain architectures from overflowing the bounds of their datatypes. For example, a 16-bit integer can represent numbers between 32,768 and +32,767; an unsigned integer can represent numbers up to 65,535. Using UL allows you to write architecturally independent code for large numbers or long bitmasks.

Some kernel code examples include the following:

 ----------------------------------------------------------------------- include/linux/hash.h 18  #define GOLDEN_RATIO_PRIME 0x9e370001UL ----------------------------------------------------------------------- include/linux/kernel.h 23  #define ULONG_MAX  (~0UL) ----------------------------------------------------------------------- include/linux/slab.h 39  #define SLAB_POISON    0x00000800UL /* Poison objects */ ----------------------------------------------------------------------- 

2.5.3. inline

The inline keyword is intended to optimize the execution of functions by integrating the code of the function into the code of its callers. The Linux kernel uses mainly inline functions that are also declared as static. A "static inline" function results in the compiler attempting to incorporate the function's code into all its callers and, if possible, it discards the assembly code of the function. Occasionally, the compiler cannot discard the assembly code (in the case of recursion), but for the most part, functions declared as static inline are directly incorporated into the callers.

The point of this incorporation is to eliminate any overhead from having a function call. The #define statement can also eliminate function call overhead and is typically used for portability across compilers and within embedded systems.

So, why not always use inline? The drawback to using inline is an increased binary image and, possibly, a slow down when accessing the CPU's cache.

2.5.4. const and volatile

These two keywords are the bane of many an emerging programmer. The const keyword must not be thought of as constant, but rather read only. For example, const int *x is a pointer to a const integer. Thus, the pointer can be changed but the integer cannot. However, int const *x is a const pointer to an integer, and the integer can change but the pointer cannot. Here is an example of const:

 ----------------------------------------------------------------------- include/asm-i386/processor.h 628  static inline void prefetch(const void *x) 629  { 630   __asm__ __volatile__ ("dcbt 0,%0" : : "r" (x)); 631  } ----------------------------------------------------------------------- 

The volatile keyword marks variables that could change without warning. volatile informs the compiler that it needs to reload the marked variable every time it encounters it rather than storing and accessing a copy. Some good examples of variables that should be marked as volatile are ones that deal with interrupts, hardware registers, or variables that are shared between concurrent processes. Here is an example of how volatile is used:

 ----------------------------------------------------------------------- include/linux/spinlock.h 51  typedef struct { ... volatile unsigned int lock; ... 58  } spinlock_t; ----------------------------------------------------------------------- 

Given that const should be interpreted as read only, we see that certain variables can be both const and volatile (for example, a variable holding the contents of a read-only hardware register that changes regularly).

This quick overview puts the prospective Linux kernel hacker on the right track for reading through the kernel sources.




The Linux Kernel Primer. A Top-Down Approach for x86 and PowerPC Architectures
The Linux Kernel Primer. A Top-Down Approach for x86 and PowerPC Architectures
ISBN: 131181637
EAN: N/A
Year: 2005
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net