Mandalika's scratchpad [ Work blog @Oracle | Stock Market Notes | My Music Compositions ]

Old Posts: 09.04  10.04  11.04  12.04  01.05  02.05  03.05  04.05  05.05  06.05  07.05  08.05  09.05  10.05  11.05  12.05  01.06  02.06  03.06  04.06  05.06  06.06  07.06  08.06  09.06  10.06  11.06  12.06  01.07  02.07  03.07  04.07  05.07  06.07  08.07  09.07  10.07  11.07  12.07  01.08  02.08  03.08  04.08  05.08  06.08  07.08  08.08  09.08  10.08  11.08  12.08  01.09  02.09  03.09  04.09  05.09  06.09  07.09  08.09  09.09  10.09  11.09  12.09  01.10  02.10  03.10  04.10  05.10  06.10  07.10  08.10  09.10  10.10  11.10  12.10  01.11  02.11  03.11  04.11  05.11  07.11  08.11  09.11  10.11  11.11  12.11  01.12  02.12  03.12  04.12  05.12  06.12  07.12  08.12  09.12  10.12  11.12  12.12  01.13  02.13  03.13  04.13  05.13  06.13  07.13  08.13  09.13  10.13  11.13  12.13  01.14  02.14  03.14 

Wednesday, April 27, 2005
C/C++: Functions with variable numbers of arguments

A function usually takes an immutable number of arguments whose types are fixed when its code is compiled. But sometimes it is desirable to implement a function where the number of arguments is not constant or not known beforehand, when the function is written.

For example, the printf function is a special type of routine that takes a variable number of arguments. The declaration requires a special syntax to indicate the fact that beyond a certain argument, the number and type of the parameters cannot be checked at compile time. Instead, the number and type of the parameters has to be computed at run-time. Using ellipsis in the signature denotes a variable argument list.

eg., void printf(const char* format, ... /* variable args */);

Three special macros va_start, va_arg & va_end are defined in sys/stdarg.h, to process the variable arguments.

void va_start(va_list pvar, void name);

va_start() is called to initialize pvar to the beginning of the variable argument list. va_start() must be invoked before any access to the unnamed arguments. The parameter name is the identifier of the rightmost parameter in the variable parameter list in the function definition (the one just before the ellipses ie., ", ...").

(type *) va_arg(va_list pvar, type);

pvar is a pointer to variable argument list; and type is the type name of the next argument to be returned.

va_arg() expands to an expression that has the type and value of the next argument in the call. The parameter pvar must be initialized by va_start(). Each invocation of va_arg() modifies pvar so that the values of successive arguments are returned in turn. The parameter type is the type name of the next argument to be returned.

void va_end(va_list pvar);

pvar is a pointer to variable argument list

The va_end() macro is used to clean up. It invalidates pvar
for use (unless va_start() is invoked again).

The following example creates a variable length argument routine to return the maximum of the data being passed to the routine, maximum.

% more maximum.c
#include <stdio.h>
#include <stdarg.h>

float maximum (const char *format, ...) {
int maxint = 0, temp_maxint = 0;
float maxfloat = 0.0, temp_maxfloat = 0.0;

va_list ap; /* declare an argument pointer to a variable arg list */
va_start(ap, format); /* initialize arg pointer using last known arg */

const char *p = format;

while (*p) {
switch(*p) {
case 'i':
temp_maxint = va_arg(ap, int);
if (temp_maxint > maxint) {
maxint = temp_maxint;

case 'f':
temp_maxfloat = va_arg(ap, float);
if (temp_maxfloat > maxfloat) {
maxfloat = temp_maxfloat;

} // switch
} // while

va_end(ap); /* restore any special stack manipulations */

if (*format == 'i') {
return (maxint);
} else if (*format == 'f') {
return (maxfloat);

return (0);
} // maximum

int main() {
float max;

max = maximum("iiiii", 431, 276, 3982, 5, 54);
printf("\nMaximum of 431, 276, 3982, 5, 54 = %d", (int)max);

max = maximum("fff", 12.2, 1.3, 54.43);
printf("\nMaximum of 12.2, 1.3, 54.43 = %f", max);

max = maximum("iiiiiiiiii", 43, 45, 65, 12, 32, 78, 9, 28, 14, 44);
printf("\nMaximum of 43, 45, 65, 12, 32, 78, 9, 28, 14, 44 = %d", (int)max);

return (0);
} // main

% CC -o maximum maximum.c

% ./maximum
Maximum of 431, 276, 3982, 5, 54 = 3982
Maximum of 12.2, 1.3, 54.43 = 54.430000
Maximum of 43, 45, 65, 12, 32, 78, 9, 28, 14, 44 = 78

The caller knows the number of arguments pushed onto the stack, but the called routine maximum does not, so it has to compute them at run-time. The va_start macro computes the (saved frame pointer + offset) value following the argument past the last known argument (ie., const char* format)). The rest of the arguments are then computed by calling va_arg, where the argument to va_arg is some (saved frame pointer + offset) value.

Man page of va_start, va_arg, va_end

Sunday, April 24, 2005
Solaris: Fixing sound card woes

System cannot play any kind of audio files. All attempts to play audio files
fail with can't find audio device dev/audioctl does not exist error message.

  1. With mixerctl command:

    • check if a driver has been installed for the sound card, and
    • if a driver has already been installed, check the default or primary audio device.

    eg., % mixerctl
    mixerctl: device /dev/audioctl does not exist

    That means, the primary audio device is not configured properly.

    /dev/audio is a symbolic link, points to the sound card device on the machine. It exists only if there is a supported sound device on the machine. When the audio device(s) are installed on the system, they appear under /dev/sound directory.

    % ls -l /dev/audio*
    No match

  2. The driver might have installed already, but not loaded. Try to load it with devfsadm command. By default, devfsadm tries to load every driver in the system and attach to all possible device instances. Also it creates logical links to device nodes in /dev and /devices and loads the device policy, if the driver load succeeds.

    eg., # devfsadm -v
    devfsadm[1739]: verbose: removing link /dev/syscon -> ../../devices/pseudo/pts@0:4
    invalid contents
    devfsadm[1739]: verbose: symlink /dev/syscon -> ../devices/pseudo/cn@0:syscon

    % mixerctl
    mixerctl: device /dev/audioctl does not exist

    In this example, the driver for the sound card is not loaded even with devfsadm. The relevant driver might not have installed on the machine. So, the next step is to install the driver for the audio device.

  3. Get the audio driver for your OS version and chipset from: and install.

    If you are not sure about the audio device information and the driver to download
    for your device, the steps are as follows to get that information:

    To get the information like device-id and vendor-id, check the output of prtconf -pv for "Audio device".

    eg., % prtconf -pv
    Node 0x1d80f8
    assigned-addresses: 8100fd10.00000000.00001c00.00000000.00000100.8100fd14.00000000.00001880.
    class-code: 00040100
    compatible: 'pci8086,2485.1028.f3.2' + 'pci8086,2485.1028.f3' + 'pci1028,f3' + 'pci8086,2485.2' + 'pci8086,2485' + 'pciclass,040100' + 'pciclass,0401'
    device-id: 00002485
    devsel-speed: 00000001
    interrupts: 00000002
    max-latency: 00000000
    min-grant: 00000000
    model: 'PCI: 8086,2485.1028.f3.2 - Audio device'
    name: 'pci1028,f3'
    power-consumption: 00000001.00000001
    reg: 0000fd00.00000000.00000000.00000000.00000000.0100fd10.00000000.00000000.
    revision-id: 00000002
    slot: 00000000
    subsystem-id: 000000f3
    subsystem-vendor-id: 00001028
    unit-address: '1f,5'
    vendor-id: 00008086

    In this example, device-id = 2485 and the vendor-id = 8086.

    Searching for device "2485" at, showed the following result:

    Device IdChip DescriptionVendor IdVendor Name
    0x2485AC97 Audio Controller0x8086Intel Corporation

    So, audioi810 driver from, has to be installed since it supports AC97 Audio Controller on Intel.

  4. After installing the audio driver, reboot the machine once to let the
    system configure everything properly for you during the system startup.

  5. Once the machine is up, check the status of the primary audio device again
    with mixerctl.

    % mixerctl
    Device /dev/audioctl:
    Name = SUNW,CS4231
    Version = 02,ICH3:82801CA
    Config = i810

    /dev/audioctl doesn't support the audio mixer function

    % ls -l /dev/audio*
    lrwxrwxrwx 1 root root 7 Apr 24 00:23 /dev/audio -> sound/0
    lrwxrwxrwx 1 root root 10 Apr 24 00:23 /dev/audioctl -> sound/0ctl

    % ls -l /dev/sound/*
    lrwxrwxrwx 1 root root 49 Apr 24 00:23 /dev/sound/0 -> ../../devices/pci@0,0/pci1028,f3@1f,5:sound,audio
    lrwxrwxrwx 1 root root 52 Apr 24 00:23 /dev/sound/0ctl -> ../../devices/pci@0,0/pci1028,f3@1f,5:sound,audioctl

  6. To quickly check if the newly installed driver is functioning properly,
    play any of the audio clips that we can find under /usr/demo/SOUND/sounds/
    with audioplay utility.

    eg., % audioplay /usr/demo/SOUND/sounds/

    If you cannot hear any audio from the system, check /var/adm/message
    for error messages from the audio device driver. Also check prtconf -D output, to make sure the audio driver (audioi810 from above examples) has attached to your hardware.

  7. If the audio files play too fast with any media player, read the following for the workaround (straight lift from:; thanks to "gnu noob" for posting the problem/solution at

    The AC'97 standard defines that the AC'97 codec has to run with an internal sample rate of 48kHz, but some mainboard manufacturers seem to overclock their chipsets / AC'97 codec. On such an overclocked AC'97 codec the internal sample rate is significantly higher than 48kHz, and audio plays back too fast.

    If you install the latest version of the audio drivers, you'll find a driver property "ac97_codec_clockrate" for the audioi810 driver in /platform/i86pc/kernel/drv/audioi810.conf, to workaround the problem with such an overclocked AC'97 codec.

    You'll find some instructions in the audioi810.conf file how to measure the exact internal clock rate used in your system's AC'97 codec.

    It appears that the latest version of the linux audio drivers are having a timing loop at i810 audio driver initialization time, to measure the AC'97 internal clock rate, so that the user doesn't have to configure a device specific clockrate.

  1. With more than one audio devices installed on the system, make sure the primary audio device (ie., the symbolic links /dev/audio and
    /dev/audioctl) is pointing to the right audio device ie., /dev/sound/x (where x = any integer).

  2. The primary audio device can be changed by modifying the /dev/audio
    and /dev/audioctl symbolic links. For more information, please read Solaris
    documentation at

  3. For a lot of applications you can select which one of multiple audio devices
    should to be used by setting the environment variable AUDIODEV: e.g.

    eg., % env AUDIODEV=/dev/sound/0 audioplay /usr/demo/SOUND/sounds/

J.Keil (
Technorati tag:

Wednesday, April 20, 2005
Solaris: Recovering from a Runtime Linker Failure -2

Recovering from a Solaris Runtime Linker failure shows some steps to bring back the system to normal state as soon as the runtime linker starts malfunctioning.

The following steps show how to recover the system after the damage has been done ie., after the losing access to the system completely.

The recovery process starts with booting Solaris from bootable CD-ROM. The steps are as follows:

  1. Put the CD-ROM into CD drive and reboot the system.
  2. From the boot solaris menu, select CD-ROM drive and then type b -s at the prompt.

    The other way is the type boot cdrom -s at ok prompt.
  3. The above step takes you to single user mode with a functional but limited Solaris access from CD-ROM.

  4. To access your file system(s), you need to mount them. So, atleast mount the root file system (/).

    If your root file system is c0t0d0s0, mount it as follows:
    mount /dev/dsk/c0t0d0s0 /mnt

    If you don't know the partition name where / is installed, have a look at /mnt/etc/vfstab file.

  5. Then copy back the original run-time linker ( For example, if you have the original copied to, copy it to as shown below:

    cp /mnt/usr/lib/ /mnt/usr/lib/

  6. Finally reboot the system.

Friday, April 15, 2005
Sun C/C++ compilers: Inlining routines

The C++ compiler has two kinds of inlining: front-end (parser) and back-end (code generator). The C and Fortran compilers have only back-end inlining. The same code generator is used for all compilers on a platform.

Function inlining improves performance by replacing a call to a function with the body of the function itself. This eliminates the overhead of jumping to and returning from a subroutine. An additional advantage is that placing the function code "inline" exposes it to further optimization, enhancing performance even more.

The C++ compiler front end will attempt to expand inline a function declared implicitly or explicitly as inline. If the function is too large, the front end emits a warning when the +w or +w2 ("more warnings") option is used. The +d option prevents the front end from attempting to inline any function. The -g option also turns off front-end inlining. The -O options do not affect front-end inlining. For C++, with -g and -O options, you lose function inlining in the front end of the compiler. This can result is serious loss of performance. To avoid this problem, use -g0 instead of -g. C does not have -g0, use -g instead.

The C++ compiler performs front-end inlining because it can use its knowledge of C++ semantics to eliminate extra copies of objects, among other things that the code generator would not be able to do.

The back-end inlining does not depend on the programming language. With an optimization level of -O4 or higher, the code generator will examine all functions, independent of how they were declared in source code, and replace function calls with inline code where it thinks the replacement will be beneficial. No messages are emitted about back-end inlining (or failure to inline). The +d option does not affect back-end inlining.

  1. Don't use "if(0)" in an inline function. Use "#if 0" instead.
  2. Also, don't put a return statement in the "then" part of an if-statement.
    Rearrange the code to put the return in the "else" part, or outside
    the if-else entirely.

Example #1:

% more inline.c
#include <stdio.h>

inline void printmespam() {
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me"); printf("print me");
printf("print me");

inline void printme() {
printf("print me");

int main() {
return (0);

% CC +w2 inline.c
"inline.c", line 17: Warning: "printmespam()" is too large and will not be expanded inline.
1 Warning(s) detected.

In this example, printmespam() was not inlined by the compiler though we requested it to "inline" it. The keyword "inline" is a request, not a guarantee.

How to check if the routine is inlined:
Check the symbol table of the executable. If the routine doesn't showup in the symbol table, it is an indication that the missing routine is inlined. This is because the compiler might have replaced the function call with the body of the function.

% elfdump -CsN.symtab a.out | grep printme
[85] 0x00010e68 0x000000a4 FUNC GLOB D 0 .text void printmespam()

printme is inlined, where as printmespam is not.

The other way is to check the assembly code being generated. To generate the assembly code, compile the code with -S option of Sun Studio compilers.

% more swap.c
void swap (int *a, int *b) {
int t = *a;
*a = *b;
*b = t;

int main() {
int x = 5, y = 2;
return (0);

% CC +w2 -S swap.c

% grep call swap.s
call __1cEswap6Fpi0_v_

% dem __1cEswap6Fpi0_v_
__1cEswap6Fpi0_v_ == void swap(int*,int*)

From the above output(s), it is clear that the function is not inlined since an assembly instruction has been generated with a call to routine swap.

% more swap.c
inline void swap (int *a, int *b) {
int t = *a;
*a = *b;
*b = t;

int main() {
int x = 5, y = 2;
return (0);
% CC +w2 -S swap.c
% grep call swap.s

Now after instructing the compiler to inline the routine swap, the compiler was able to inline the function in main(), since it was not too big. That's why no assembly instruction has been generated with a call to swap.

Example #2:

%more inline2.c
#include <stdio.h>

int globvar = 0;

inline void setglob () {
globvar= 25;

int main(int argc, char *argv[]) {
globvar= 5;
printf("Now global variable holds %d\n", globvar);
return (0);

%cc -o test inline2.c
Undefined first referenced
symbol in file
setglob inline2.o
ld: fatal: Symbol referencing errors. No output written to test

The above code violates a C rule. An inline definition without an "extern" directive does not create an instance of the function. Calling the function has undefined results.

The fix is to declare setglob with external linkage.

C++ has a different rule for inline functions. The compiler is required to figure out how to generate a defining instance if one is needed, without any special action by the programmer. So, the above example (#2) is valid C++ code, but not valid C code.

Modified code:

% more inline2.c
#include <stdio.h>

int globvar = 0;

extern inline void setglob () {
globvar= 25;

int main(int argc, char *argv[]) {
globvar= 5;
printf("Now global variable holds %d\n", globvar);
return (0);

% cc inline2.c
% ./a.out
Now global variable holds 25

Steve Clamage

Monday, April 11, 2005
Solaris Linker: -B {static | dynamic}

By default, unless we explicitly specify by using a linker flag such as -Bstatic, the linker on Solaris will search a given directory for a shared object and link against the shared library if it is available. This means that the external reference will not be resolved until the code starts running and even then the linking will not take effect until an actual call is made to the routine requiring that library.

If the linker couldn't find the relevant shared object in the search path, it will search for an archive (static) library. In the case of static libraries the actual code to execute the external routine will be physically copied into the executable.

-Bdynamic & -Bstatic options of Solaris linker provides finer control of which library, shared or static should searched for each library specified on the link line. One advantage of the method of explicitly specifying which librariess we want static and which we want dynamic is that we don't have to hardcode full paths to any libraries (more portable and easier to maintain).

The library search option can be toggled between shared objects and archives by specifying -Bdynamic and -Bstatic on the command line as many times as required.

CC -Bstatic -lstatic -Bdynamic -ldyn -o driver driver.o

This command tells the linker to search for only static library of libstatic, and search for until the search exhausts, before the next search for libdyn.a archive begins. In other words, the link-editor (ld aka linker) first searches for libstatic.a, and then for, and if that fails, then for libdyn.a.

With -Bstatic option, the linker does not accept shared objects as input until the next occurrence of -Bdynamic. However, with -Bdynamic option, the linker first looks for shared objects and then archives in any given directory.

Solaris Linker and Libraries Guide

Saturday, April 02, 2005
Solaris: Useful Commands - 1


Prints process arguments, environment variables; pargs can examine both processes and their core files

% ps -eaf | grep mozilla-bin
techno 11723 11704 0 22:05:35 ? 2:51
/usr/sfw/bin/../lib/mozilla/mozilla-bin -UILocale en-US -contentLocale US

% pargs 11723
11723: /usr/sfw/bin/../lib/mozilla/mozilla-bin -UILocale en-US -contentLocale US
argv[0]: /usr/sfw/bin/../lib/mozilla/mozilla-bin
argv[1]: -UILocale
argv[2]: en-US
argv[3]: -contentLocale
argv[4]: US

% pargs -e 11723
11723: /usr/sfw/bin/../lib/mozilla/mozilla-bin -UILocale en-US -contentLocale US
envp[0]: AB_CARDCATALOG=/usr/dt/share/answerbooks/C/ab_cardcatalog
envp[1]: ADDON_PATH=/usr/sfw/bin/../lib/mozilla
envp[2]: DISPLAY=:0.0
envp[3]: DTAPPSEARCHPATH=/export/home/techno/.dt/appmanager:/etc/dt/appconfig/appmanager/%L:
envp[4]: DTDATABASESEARCHPATH=/export/home/techno/.dt/types,/etc/dt/appconfig/types/
envp[5]: DTDEVROOT=
envp[7]: DTUSERSESSION=techno-unknown-0


Reports status of service(s); useful for debugging service issues

svcs with -x option, displays the states of services which:
  • are enabled, but not running
  • are preventing another enabled service from running

-v option along with -x, displays verbose information

% svcs -x
svc:/application/print/server:default (LP print server)
State: disabled since Tue Mar 22 01:51:18 2005
Reason: Disabled by an administrator.
See: lpsched(1M)
Impact: 2 dependent services are not running. (Use -v for list.)

% svcs -xv
svc:/application/print/server:default (LP print server)
State: disabled since Tue Mar 22 01:51:18 2005
Reason: Disabled by an administrator.
See: man -M /usr/share/man -s 1M lpsched
Impact: 2 dependent services are not running:

-a option, displays all services including the offline/disabled ones

% svcs -a
legacy_run Mar_22 lrc:/etc/rcS_d/S50sk98sol
legacy_run Mar_22 lrc:/etc/rc2_d/S20sysetup
legacy_run Mar_22 lrc:/etc/rc2_d/S40llc2
disabled Mar_22 svc:/network/dhcp-server:default
disabled Mar_22 svc:/network/ipfilter:default
disabled Mar_22 svc:/network/security/kadmin:default
online Mar_22 svc:/system/filesystem/minimal:default
online Mar_22 svc:/system/rmtmpfiles:default
online Mar_22 svc:/system/keymap:default
online Mar_22 svc:/system/name-service-cache:default
offline Mar_22 svc:/application/print/ipp-listener:default
offline Mar_22 svc:/application/print/rfc1179:default

-p option lists processes associated with each service instance

% svcs -p network/telnet:default
online Mar_22 svc:/network/telnet:default


Services can be enabled/disabled with svcadm

Lets check the state of ftp server, and enable/disable it depending on its current state
% svcs -p network/ftp:default
online Mar_22 svc:/network/ftp:default

% ftp localhost
Connected to localhost.
220 unknown FTP server ready.
Name (localhost:techno): techno
331 Password required for techno.

Since FTP server is up, let's disable the service using svcadm command

% svcadm disable /network/ftp

% svcs -p network/ftp:default
disabled 2:12:04 svc:/network/ftp:default

% ftp localhost
ftp: connect to address Connection refused
Trying ::1...
ftp: connect: Network is unreachable
ftp> bye

It is very easy to enable the service again with svcadm

% svcadm enable /network/ftp

% svcs -p network/ftp:default
online 2:14:08 svc:/network/ftp:default

At this point, though the ftp service is available, no processes are associated with the service instance. If we "ftp localhost" from another window, we can then see the ftp daemon:

% svcs -p network/ftp:default
online 2:14:08 svc:/network/ftp:default
2:16:27 11976 in.ftpd


Solaris Management Console, a Graphical User Interface (GUI) that provides access to Solaris system administration tools.
This tool is comparable to YaST2 of SuSE Linux Or X-Configs of RedHat


Reports fstat() & fcntl() information for all open files in a process, including their paths

% ps -eaf | grep xchat
techno 7958 7945 12 Mar 28 pts/4 361:05 xchat
root 12022 11958 0 02:31:05 pts/4 0:00 grep xchat

% pfiles 7958
7958: xchat
Current rlimit: 256 file descriptors
0: S_IFCHR mode:0620 dev:270,0 ino:12582924 uid:100 gid:7 rdev:24,4
1: S_IFCHR mode:0620 dev:270,0 ino:12582924 uid:100 gid:7 rdev:24,4
2: S_IFCHR mode:0620 dev:270,0 ino:12582924 uid:100 gid:7 rdev:24,4
3: S_IFDOOR mode:0444 dev:279,0 ino:59 uid:0 gid:0 size:0
4: S_IFSOCK mode:0666 dev:276,0 ino:37799 uid:0 gid:0 size:0
sockname: AF_UNIX
peername: AF_UNIX /tmp/.X11-unix/X0
5: S_IFSOCK mode:0666 dev:276,0 ino:45917 uid:0 gid:0 size:0
6: S_IFSOCK mode:0666 dev:276,0 ino:27017 uid:0 gid:0 size:0
sockname: AF_INET port: 4000
7: S_IFREG mode:0600 dev:102,7 ino:1237 uid:100 gid:1 size:8435712


Describes the underlying instruction set architecture

isainfo prints the name(s) of the native instruction sets for applications supported by the current version of the operating system.

With -v option, we can find out whether 64-bit applications are supported, or whether the running kernel uses 32-bit or 64-bit device drivers

% isainfo

% isainfo -v
32-bit i386 applications
sse2 sse fxsr mmx cmov sep cx8 tsc fpu


-b option, shows the time and date of the last reboot

% who -b
. system boot Mar 22 01:51

-r can be used to get the current run level of the init process
% who -r
. run-level 3 Mar 22 01:51 3 0 S

with -d option, who displays all processes that have expired and not been respawned by init. The exit field appears for dead processes and contains the termination and exit values of the dead process. This can be useful in determining why a process terminated.

# who -dH
techno pts/5 Mar 25 00:58
techno pts/7 Mar 28 00:05
techno pts/8 Mar 27 19:19
techno pts/6 Apr 2 02:08 (localhost)


Shows how long the system has been up

uptime command prints the current time, the length of time the system has been up, and the average number of jobs in the run queue over the last 1, 5 and 15 minutes

% uptime
2:47am up 11 day(s), 57 min(s), 1 user, load average: 0.14, 0.15, 0.17


This page is powered by Blogger. Isn't yours?