Monday, March 31, 2008

volatile

[Original: ] http://www.airs.com/blog/archives/154

The volatile qualifier in C/C++ is widely misunderstood. Because it is described so vaguely in language standards, many people interpret it as a do-what-I-mean qualifier.

What the standard says is that accesses to volatile objects must be evaluated strictly according to the abstract machine defined by the language standard; this means that if the C/C++ code reads the volatile object twice, then the machine code must do so as wel. The standard says that volatile objects must be stable at sequence points; this means, approximately, that in between statements all reads and writes of volatile objects must have been completed–the value may not be cached in a register. The standard makes clear that it is possible that the values of volatile objects may change in some unknown way between accesses.

One relatively unimportant misunderstanding is due to the fact that the standard only talks about accesses to volatile objects. It does not talk about accesses via volatile qualified pointers. Some programmers believe that using a pointer-to-volatile should be handled as though it pointed to a volatile object. That is not guaranteed by the standard and is therefore not portable. However, this is relatively unimportant because gcc does in fact treat a pointer-to-volatile as though it pointed to a volatile object.

A way to think about volatile is to observe that it was invented to support memory mapped hardware. Some hardware is controlled by accesses to specific memory addresses. For example, a serial controller often handles input by setting a bit in one memory location and making the new byte available in another memory location. The kernel code must observe that the bit is set, read the byte, and set another bit to tell the serial controller that the byte has been read (I’m skipping the interrupt which is also involved). These accesses should use volatile to make sure that they happen in the exact order written in the program.

The standard also explicitly describes two other uses of volatile. One is for setjmp and is relatively uninteresting. The other is that a variable of type volatile sig_atomic_t may be set in a signal handler and read by code outside the signal handler. In fact, just about all that a portable signal handler may do is set such a variable.

For dealing with memory mapped hardware, volatile is exactly what you want. For most other types of code, including multi-threaded code, volatile does not help.

Using volatile does not mean that the variable is accessed atomically; no locks are used. Using volatile does not mean that other cores in a multi-core system will see the memory accesses; no cache flushes are used. While volatile writes are guaranteed to occur in the program order for the core which is executing them, there is no guarantee that any other core will see the writes in the same order. Using volatile does not imply any sort of memory barrier; the processor can and will rearrange volatile memory accesses (this will not happen for address ranges used for memory mapped hardware, but it will for ordinary memory).

Conversely, if you use the locking primitives which are part of any threading library, then you do not need to use volatile. The locking primitives will include the required memory barriers or cache flushes. They will include whatever special directives are needed to tell the compiler that memory must be stable.

There is one case where volatile may be used for multi-threaded programming with some reliability. You may use a single volatile sig_atomic_t variable to communicate between threads, much as you may use such a variable to communicate between a signal handler and the main program. You should not use more than one such variable to communicate between any pair of threads, as there is no guarantee that the different threads will see the accesses in the same order.

In summary, if you are using volatile for anything other than manipulating memory mapped hardware, or for very limited communication between threads, it is very likely that you are making a mistake. Think carefully about what volatile means and about what it does not mean.

Friday, March 28, 2008

CJKbookmarks with dvipdfm

Today I eventually managed to create a PDF file with Chinese bookmark.
Suppose the LaTeX source file is foo.tex:
  1. Insert the following code into preamble section:
    \usepackage[CJKbookmarks,dvipdfm,bookmarksnumbered=true,%
    colorlinks=true,linkbordercolor={1 1 1},%
    linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref}

  2. The following command line create the PDF file.
    1. latex foo.tex
    2. gbk2uni foo.out
    3. latex foo.tex
    4. dvipdfm foo.dvi
The linkbordercolor option will change the color of link border to white other than the default red color.

Thursday, March 27, 2008

A couple of Bash tips

  1. Single instance
    # make use of bash `set -C'
    (set -C; : > $lockfile) 2>/dev/null
    if [ $? -ne 0 ]; then
      log_msg "$0 already running, exit"
      exit 0
    fi

  2. Daemonize script
    # `-d' option indicates to daemonize
    if [ x"$1" = "x-d" ]; then
      $0 2>&1 >/dev/null &
      exit 0
    fi

Tuesday, March 11, 2008

First GDB Script

Here I added my first GDB macro functions in the file $HOME/.gdbinit to dump the content of task array.
  1. define tasks
  2. x/210u *((unsigned int*) tobj+1)
  3. end
  4. document tasks
  5. Display content of tasks.
  6. end
The array is of 210 machine words long and it's easy to use awk to format the output neatly.

Friday, March 07, 2008

symbol-file

Although still I do NOT know now to extract a symbol file from
unstripped binary executable, but seems I got a solution. -_-

% echo "int main(void) {return 0; }" > foo.c
% gcc -ggdb foo.c -o foo.gdb
% gcc -s foo.c -o foo
% gdb -q foo
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) b main
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) symbol-file foo.gdb
Reading symbols from /home/david/foo.gdb...done.
(gdb) b main
Breakpoint 1 at 0x8048352: file foo.c, line 1.
(gdb) l
1 int main(void) {return 0; }
(gdb)

Thursday, March 06, 2008

How to Generate Symbol file?

I wonder how to generate symbol file from binary executable under GNU/Linux?

I googled a lot and tried the following but with no luck. x-(
  1. nm -n
  2. objdump -h -S
  3. objdump -t
GDB 'symbol-file' always complaint:
can't read symbols: File format not recognized.