Chinaunix首页 | 论坛 | 博客
  • 博客访问: 283699
  • 博文数量: 65
  • 博客积分: 3091
  • 博客等级: 中校
  • 技术积分: 705
  • 用 户 组: 普通用户
  • 注册时间: 2005-01-25 09:44
文章存档

2013年(2)

2012年(11)

2011年(12)

2010年(13)

2009年(15)

2008年(12)

分类:

2010-11-22 15:30:35

作者 Max Bruning,2006 年 6 月
内容
 
 

许多开发者正在编写在 Linux 操作系统下运行的应用程序。随着 Solaris 10 OS 中引入许多新增功能,以及随着 Sun 最近对于在基于 AMD 和 Intel 处理器的计算机上支持 Solaris OS 的格外重视,开发者对于能够在 Solaris 平台上开发应用程序越来越感兴趣了。本文分析了这两种操作系统的开发环境之间的相似和不同之处。负责将应用程序从 Linux 移植到 Solaris OS 的人员,或者之前已具有 Linux 经验而想要学习在 Solaris OS 中进行开发的程序员,将会从本文中获益。

在本文中,术语 "Solaris" 指 Solaris 10 OS(和 OpenSolaris),而 "Linux" 指 Linux 2.6。所涵盖的许多详细信息也适用于 Solaris 和 Linux 的早期版本。Linux 分发版本是指通用分发版本,而示例在 SuSe 9.1 中进行了测试。另外,本文集中讲述使用 C 编程语言编写的应用程序,而使用 C++ 时的情况应该与使用 C 时类似。由于基于 Java 技术的应用程序不应有特定于 Linux 或 Solaris OS 的函数调用,因此可以按原样移植。

本文讨论应用程序程序员和分析员能够看到的有关 Solaris OS 与 Linux 的相似和不同之处。本文并不代表对不同之处的全部说明,也不是用于说明一种 OS 优于另一种。相反,本文旨在帮助那些熟悉其中一种 OS 的开发者能够尽可能快地使用另一种 OS。

与 POSIX 兼容且不含任何特定于 Solaris OS 或 Linux 的系统调用或库函数的简单应用程序应可在两种 OS 之间移植,而无需进行更改。您应该能够编写您的应用程序、针对 Solaris OS 或 Linux 进行编译,然后针对另一种 OS 进行简单重新编译,这样它应该就能正常使用。这两种 OS 中的大多数系统调用和库例程都属于这种类型。

Linux 中的许多系统调用在 Solaris OS 中作为库函数存在,反之亦然。例如,sched_setscheduler() 在 Linux 中为一个系统调用,而在 Solaris OS 中为一个调用 priocntl(2) 系统调用的库函数。priocntl(2) 系统调用在 Linux 中不存在,但 Linux 不支持除分时和实时以外的多个调度程序。本文接下来的一节将系统调用按功能分成多个部分逐一进行介绍,并对比每种 OS 提供的功能。

来自 Linux 领域的大多数应用程序和工具包都可直接编译和运行,而无需进行更改。这包括 gcc、emacs、MySQL、perl 以及许多其他应用程序和工具包。 中提供了许多软件包的预编译二进制代码。

所提供的有关比较 Linux 和 Solaris OS 的文章为数并不多,但大多数这样的文章都是对这两种操作系统的早期版本进行比较。您可以通过在 Web 中搜索 "Linux and Solaris comparison"(Linux 与 Solaris 的比较)来找到这些文章。请参见有关 Solaris OS 和 Linux 的《Seal Rock Research White Paper》(pdf),该文中涵盖了 Solaris 10 OS 和 2.6 Linux。 是讨论有关从 Solaris OS 移植到 Linux 问题的若干页的开始部分。

Solaris OS 和 Linux 之间以及 Linux 的不同分发版本之间存在着各种管理差异。Solaris 10 OS 中引入了“服务管理框架”(Service Management Framework, SMF),较之以前的 Solaris 版本,这是一个很大的变化。本文将不涵盖系统管理方面的差异,但某些对开发者有影响的部分除外。

Linux 中存在的大多数系统调用和库在 Solaris OS 中也同样存在。本节将介绍在两种系统间存在差异的系统调用和库例程。系统调用和库例程的分类如下:

Solaris OS 在 /usr/include/sys/syscall.h 中保存着系统调用的列表。Linux 在 /usr/include/asm/unistd.h 中维护着相同的信息。(请注意,Linux 和 Solaris OS 都有 unistd.hsyscall.h 文件,并且在某些情况下,这些文件的内容相同。)

Solaris OS 和 Linux 的 /usr/share/man/man2 中提供了系统调用的文档。(Solaris OS 具有一个从 /usr/man 到相同位置的符号链接。)库例程记录在各种手册部分。有关 Linux 和 Solaris OS 的库部分的概述,请参见 man intro.3。请注意,与 Linux 相比,Solaris OS 对库例程的划分更细。例如,在 Solaris OS 中,aio_read() 记录在 aio_read(3RT) 中,而在 Linux 中,它记录在 aio_read(3) 中。其结果是,使用 aio_read() 在 Solaris OS 中编译程序时,您必须通过 -lrt 及 compilation/link 命令包括实时库,而在 Linux 中则不需要。

Linux 和 Solaris OS 都附带提供了 200 多种不同的库,这些库中定义了 50,000 多个函数。

下表列出了 Linux 和 Solaris OS 中的某些库。请注意,这并不代表完整的列表。另请注意,其中的某些库必须独立于标准系统安装而单独下载和安装。

表 1:Linux 和 Solaris OS 中的某些库
 
 
Solaris OS
Linux
说明
libc
libc
标准 C 库(POSIX、SysV、ANSI,等),请参见 Solaris OS 中的 man libc。
libucb
libc
UCB(柏克莱加州大学,University California Berkeley)兼容性库
libmalloc
libc
有多种不同的 malloc 库;缺省库位于 libc 中。
libsocket
libc
套接字库(在 Linux 中,套接字位于 libc 中)。
libxnet
libc
X/Open 联网库
libresolv
libresolv
DNS 例程(在 Solaris OS 中为 inet_* 例程)
libnsl
libnsl/libc
网络服务库(linux-nis/nis+ 例程)
librpc
librpc
RPC 函数
libslp
libslp
服务定位协议
libsasl
libsasl
简单验证和安全层
libaio
libaio
异步 I/O 库
libdoor
 
门支持(door_create()door_return(),等)
librt
librt
POSIX 实时库
libcfgadm
 
配置管理库
libcontract
 
约定管理库(请参见 Solaris OS 中的 man contract.4
libcpc
 
CPU 性能计数器库(在 Linux 中,可能需要安装内核模块)
libdat
 
直接访问传输库(请参见 )
libelf
libelf
ELF 支持库
libm
libm
数学库

以下各节将更加详细地介绍某些系统调用和库。我们将集中讲述它们在系统之间的不同之处。

套接字和联网

对于大多数套接字和联网代码而言,只需针对所使用的 OS 对其进行重新编译,所生成的可执行代码应该就能正常使用。本节对通常在 Solaris OS 和 Linux 中使用的与网络有关的系统调用和库例程进行了比较。

socket()

除了 AF_UNIXAF_INETAF_INET6 域参数以外,socket() 例程在 Solaris OS 和 Linux 中还具有其他值。在 Solaris OS 中,AF_NCA 域用于指定网络高速缓存和加速器(请参见 nca(1))以便与套接字一起使用。大多数地址族(域)都在 Linux 和 Solaris OS 中同时存在。注意:有关可能的地址族,请参见 Solaris OS 中的 /usr/include/sys/socket.h 以及 /usr/include/linux/socket.h。但可能需要下载或编写代码才能支持某些域。

Linux 将若干其他域记录在 socket(2) 手册页中。Linux 中记录的其他域包括:

  • AF_IPX-Novell IPX 协议(可能仅用于 SuSe)。
  • AF_NETLINK-内核/用户接口设备,允许用户访问内核模块。注意:在 Solaris OS 和 Linux 中还存在一些其他方法用于进行这项工作。
  • AF_X25-X25 协议。在 Solaris OS 中,此域包含在 Solstice X.25 产品中。
  • AF_AX25-业余无线电 AX.25 协议。
  • AF_ATMPVC-基于 ATM 的永久虚拟电路 (Permanent Virtual Circuits over ATM)。
  • AF_APPLETALK-请参见 Linux 中的 man ddp。它在 Solaris OS 中也存在,但未记录。
  • AF_PACKET-请参见 Linux 中的 man packet.7。原始包接口。在 Solaris OS 中,请打开 NIC 设备并使用 getmsg(2)/putmsg(2) 来通过 DLPI 接收/发送原始包。(有关 DLPI 的详细信息,请参见)。
bind()

Linux 手册页 (man bind.2) 包含一些有关不同地址族(AF_INETAF_UNIX 除外)的信息。Solaris 手册页为 man bind.3socket

listen()

在 Linux 和 Solaris OS 中,backlog 参数(listen() 的第二个参数)指正等待被接受的已建立连接的队列长度。Linux 手册页中是这么说的,而 Solaris 手册页中仅是指“待处理连接的队列”。

accept()

Linux 支持三种基于连接的套接字类型:SOCK_STREAMSOCK_SEQPACKETSOCK_RDM,而 Solaris OS 只记录了 SOCK_STREAM。Linux 实现不继承某些套接字标志。这可能与其他实现不同。

connect()

Linux 手册页 (man connect.2) 记录了 SOCK_SEQPACKET,而 Solaris OS 中不记录。Linux 通过连接到 struct sockaddrsa_family 设置为 AF_UNSPEC 的某个地址来中断无连接套接字和 connect() 之间的关联。此行为不会记录在 Solaris OS 中。

send()/recv()

如在其他 socket 库函数中的情况那样,它们在不同系统中的行为几乎完全相同。Linux 在手册页中包含一些其他 flags 参数文档。

shutdown()

在 Solaris OS 和 Linux 之间没有显著的差异。

联网示例

查看一个其中存在着某些差异的应用程序可能会很有用。 程序使用包捕获库 () 在用户级读取以太网包。用于读取原始以太网的代码在 Solaris OS 和 Linux 之间完全不同。(也可使用 libpcap 来检查与其他系统(例如,FreeBSD、HP-UX 和 AIX)间的差异。)libpcap 的可用代码位于 pcap-linux.cpcap-dlpi.c 中。DLPI 代码用于 Solaris、HP-UX、AIX 和其他操作系统。Linux 提供了一种用于通过标准 socket 调用读取原始套接字包的机制。Solaris OS 使用 getmsg(2)putmsg(2) 调用来接收和发送 DLPI 包。

以下代码演示了一种在 Solaris OS 中对网络接口执行用户级包捕获的方法。在这段代码之后,列出了在 Linux 中采用的类似代码。这段代码提取自 libpcap 库(此处进行了大量删减)。

#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

int
main(int argc, char *argv[])
{
    register char *cp;
    int fd;
    dl_info_ack_t *infop;
    union DL_primitives dlp;
    dl_info_req_t inforeq;
      dl_bind_req_t    bindreq;
    dl_attach_req_t attachreq;
    dl_promiscon_req_t promisconreq;
    struct    strbuf    ctl, data;
    int    flags;
    char buffer[8192];
    dl_error_ack_t *edlp;

    fd = open(argv[1], O_RDWR);  /* for instance, /dev/elxl0 */

    /* attach to a specific interface */
    attachreq.dl_primitive = DL_ATTACH_REQ;
    attachreq.dl_ppa = 0;  /* assume we want /dev/xxx0 */
    ctl.maxlen = 0;
    ctl.len = sizeof(attachreq);
    ctl.buf = (char *)&attachreq;
    flags = 0;
    /* send attach req */
    putmsg(fd, &ctl, (struct strbuf *)NULL, flags);
    ctl.maxlen = sizeof(dlp);
    ctl.len = 0;
    ctl.buf = (char *)&dlp;
    /* get ok ack, may contain error */
    getmsg(fd, &ctl, (struct strbuf*)NULL, &flags);

    memset((char *)&bindreq, 0, sizeof(bindreq));
    /* the following bind might not need to be done */
    bindreq.dl_primitive = DL_BIND_REQ;
    bindreq.dl_sap = 0; 
    bindreq.dl_max_conind = 1;
    bindreq.dl_service_mode = DL_CLDLS;
    bindreq.dl_conn_mgmt = 0;
    bindreq.dl_xidtest_flg = 0;
    ctl.maxlen = 0;
    ctl.len = sizeof(bindreq);
    ctl.buf = (char *)&bindreq;
    flags = 0;
    /* send bind req */
    putmsg(fd, &ctl, (struct strbuf *)NULL, flags);
    ctl.maxlen = sizeof(dlp);
    ctl.len = 0;
    ctl.buf = (char *)&dlp;
    /* get bind ack */
    getmsg(fd, &ctl, (struct strbuf*)NULL, &flags);

    promisconreq.dl_primitive = DL_PROMISCON_REQ;
    promisconreq.dl_level = DL_PROMISC_PHYS;
    ctl.maxlen = 0;
    ctl.len = sizeof(promisconreq);
    ctl.buf = (char *)&promisconreq;
    flags = 0;
    /* send promiscuous on req */
    putmsg(fd, &ctl, (struct strbuf *)NULL, flags);
    ctl.maxlen = sizeof(dlp);
    ctl.len = 0;
    ctl.buf = (char *)&dlp;
    /* get get ok ack */
    getmsg(fd, &ctl, (struct strbuf*)NULL, &flags);

    promisconreq.dl_primitive = DL_PROMISCON_REQ;
    promisconreq.dl_level = DL_PROMISC_SAP;
    ctl.maxlen = 0;
    ctl.len = sizeof(promisconreq);
    ctl.buf = (char *)&promisconreq;
    flags = 0;
    /* send promiscuous on req */
    putmsg(fd, &ctl, (struct strbuf *)NULL, flags);
    ctl.maxlen = sizeof(dlp);
    ctl.len = 0;
    ctl.buf = (char *)&dlp;
    /* get get ok ack */
    getmsg(fd, &ctl, (struct strbuf*)NULL, &flags);

    /* read and echo to stdout whatever comes to us */
    while (1) {
      data.buf = buffer;
      data.maxlen = sizeof(buffer);
      data.len = 0;
      ctl.buf = (char *) &dlp;
      ctl.maxlen = sizeof(dlp);
      ctl.len = 0;
      flags = 0;
      getmsg(fd, &ctl, &data, &flags);
      write(1, "\nCTL:\n", 6);
      write(1, ctl.buf, ctl.len);
      write(1, "\nDAT:\n", 6);
      write(1, data.buf, data.len);
    }
}

The Solaris code forms DLPI requests and gets DLPI responses to tell the interface that the application wants a copy of all packets arriving at the interface.

The code in Linux is much simpler, as a socket(2) call allows one to specify raw packets. Linux does not use DLPI or STREAMS.

#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

int
main(int argc, char *argv[])
{
    int    sock_fd = -1;
    struct sockaddr_ll    sll, from;
    struct packet_mreq    mr;
    socklen_t    fromlen;
    int        packet_len;
    char        buffer[8192];

    sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

    memset(&sll, 0, sizeof(sll));
    sll.sll_family    = AF_PACKET;
    sll.sll_ifindex    = 0;
    sll.sll_protocol    = htons(ETH_P_ALL);

    bind(sock_fd, (struct sockaddr *) &sll, sizeof(sll));

    while (1) {
      fromlen = sizeof(from);
      packet_len = recvfrom(
        sock_fd, buffer, sizeof(buffer), MSG_TRUNC,
        (struct sockaddr *) &from, &fromlen);
      write(1, buffer, packet_len);
    }
}

Process/Processor Management

A process on both the Solaris OS and Linux is a running instance of a program. In both the Solaris OS and in Linux (2.6), a process is a container for an address space and one or more threads. Every process in the system has a unique process ID (PID), which remains unique for some time after the process dies. Processes are created using fork(2) and its variants. On Linux, processes (and threads) can also be created using clone(2), but pthread_create(3) is more portable. On the Solaris OS, the undocumented lwp_create() system call is somewhat analogous to clone(2).

vfork() performs similarly on both systems. The Solaris OS has fork1() and forkall(). In the case of fork1(), this causes the child process to only have the thread that executed the fork() call; in the case of forkall(), all the threads that were in the parent are replicated in the child. The default fork is fork1(). forkall() must be explicitly used. forkall() does not exist in Linux, (i.e., Linux only supports fork1() semantics).

The ps -elfL command can be used on both the Solaris OS and Linux to see the threads in a process. Both systems report the number of LWPs and the lwpid for each thread in the process. Note that an lwpid is unique across processes in Linux. In the Solaris OS, the lwpid is unique within the process. In Linux, the process ID of a multithreaded process is actually a thread group ID. The thread group ID is equivalent to the process ID of the main thread. Sending a signal (via kill(1)/kill(2)) to any lwpid is equivalent to sending the signal to the process. In the Solaris OS, you send the signal to the pid. In both cases, if the default action is taken, the process typically exits and all threads are terminated. See the man page for ps(1) for more details.

Both Linux and the Solaris OS support the notion of binding a process or thread to a processor. Linux allows binding to a set of processors for non-exclusive use of those processors. The Solaris OS allows binding to a set of processors for exclusive use, (that is, CPU fencing), but does not allow binding to a group for non-exclusive use (except via Solaris Zones?). Linux does not have a mechanism for CPU fencing, though implementations can be found on the web (see, for example, the on the bullopensource.org site). The Linux system calls that are processor affinity based are sched_setaffinity(2) and sched_getaffinity(2). The Solaris OS has the following:

  • processor_bind(2) to bind/unbind LWPs or processes to a processor
  • pset_create(2) to set up a processor set
  • pbind(1) and psrset(1), which are command-line interfaces

For completeness, output of the ps(1) command, first on Linux, then on the Solaris OS, is shown in the section on Threads.

On Linux and the Solaris OS, all forms of the exec system call result in calling execve(2). The Solaris OS documents all six flavors of exec(2) on the same manual page. The Linux man page exec(3) documents execv, execl, execle, execlp, and execvp. A separate page covers execve(2).

The /proc file system exists in slightly different variations on Linux and the Solaris OS. On both systems, /proc is a directory containing files whose names are the process IDs of the current active processes on the system. Each PID-named file is in turn a directory. /proc on Linux has various other directories besides processes. Most of these deal with processors, devices, and statistics on the system. On Linux, one looks in /proc to find information about processes, processors, devices, machine architecture, and so on. On the Solaris OS, the same kind of information is typically available by using a command. For instance, prtconf(1) can be used to learn about machine configuration on the Solaris OS. On Linux, this is done largely by looking at files in /proc.

The virtual address space used by processes can be examined using pmap(1) on the Solaris OS, and by catting the /proc/pid/maps file on Linux, as shown below. See pmap(1) on the Solaris OS and proc(5) on Linux for more details.

<-- on solaris, address space of this instance of bash -->
bash-3.00$ pmap -x $$  
1043:    /usr/bin/bash -i
 Address  Kbytes     RSS    Anon  Locked Mode   Mapped File
08045000      12      12       4       - rw---    [ stack ]
08050000     528     468       -       - r-x--  bash
080E3000      76      72       8       - rwx--  bash
080F6000     124     108      40       - rwx--    [ heap ]
FED8E000       4       4       -       - rwxs-    [ anon ]
FEDA0000       4       4       -       - rwx--    [ anon ]
FEDB0000     760     660       -       - r-x--  libc.so.1
FEE7E000      24      24       8       - rw---  libc.so.1
FEE84000       8       8       -       - rw---  libc.so.1
FEE90000      24       8       4       - rwx--    [ anon ]
FEEA0000     524     324       -       - r-x--  libnsl.so.1
FEF33000      20      20       4       - rw---  libnsl.so.1
FEF38000      32       -       -       - rw---  libnsl.so.1
FEF50000      44      40       -       - r-x--  libsocket.so.1
FEF6B000       4       4       -       - rw---  libsocket.so.1
FEF70000       4       4       4       - rwx--    [ anon ]
FEF80000     144     132       -       - r-x--  libcurses.so.1
FEFB4000      28      24       -       - rw---  libcurses.so.1
FEFBB000       8       -       -       - rw---  libcurses.so.1
FEFC0000       4       4       -       - r-x--  libdl.so.1
FEFC7000     140     140       -       - r-x--  ld.so.1
FEFFA000       4       4       4       - rwx--  ld.so.1
FEFFB000       8       8       4       - rwx--  ld.so.1
-------- ------- ------- ------- -------
total Kb    2528    2072      80       -
bash-3.00$ 
For the equivalent on Linux, see Figure 1. Note that Linux shows the full path name to libraries (the output has been edited to only show the library name). To get the full path names to libraries on the Solaris OS, use pldd(1).

user@linuxhost:~$ cat /proc/$$/maps  <-- get mapping for current shell(bash)
08048000-080e9000 r-xp 00000000 03:01 1954568    /bin/bash
080e9000-080ef000 rw-p 000a0000 03:01 1954568    /bin/bash
080ef000-081b4000 rw-p 080ef000 00:00 0          [heap]
b7acb000-b7ae6000 r-xp 00000000 03:06 716774     /usr/lib/gconv/GBK.so
b7ae6000-b7ae8000 rw-p 0001a000 03:06 716774     /usr/lib/gconv/GBK.so
b7ae8000-b7af1000 r-xp 00000000 03:01 1645899    /lib/tls/i686/cmov/libnss_files-2.3.6.so
b7af1000-b7af3000 rw-p 00008000 03:01 1645899    /lib/tls/i686/cmov/libnss_files-2.3.6.so
b7af3000-b7afb000 r-xp 00000000 03:01 1645901    /lib/tls/i686/cmov/libnss_nis-2.3.6.so
b7afb000-b7afd000 rw-p 00007000 03:01 1645901    /lib/tls/i686/cmov/libnss_nis-2.3.6.so
b7afd000-b7b0f000 r-xp 00000000 03:01 1645896    /lib/tls/i686/cmov/libnsl-2.3.6.so
b7b0f000-b7b11000 rw-p 00011000 03:01 1645896    /lib/tls/i686/cmov/libnsl-2.3.6.so
b7b11000-b7b13000 rw-p b7b11000 00:00 0
b7b13000-b7b1a000 r-xp 00000000 03:01 1645897    /lib/tls/i686/cmov/libnss_compat-2.3.6.so
b7b1a000-b7b1c000 rw-p 00006000 03:01 1645897    /lib/tls/i686/cmov/libnss_compat-2.3.6.so
b7b1c000-b7c21000 r--p 002d4000 03:06 719486     /usr/lib/locale/locale-archive
b7c21000-b7e21000 r--p 00000000 03:06 719486     /usr/lib/locale/locale-archive
b7e21000-b7e22000 rw-p b7e21000 00:00 0
b7e22000-b7f49000 r-xp 00000000 03:01 1645890    /lib/tls/i686/cmov/libc-2.3.6.so
b7f49000-b7f4e000 r--p 00127000 03:01 1645890    /lib/tls/i686/cmov/libc-2.3.6.so
b7f4e000-b7f50000 rw-p 0012c000 03:01 1645890    /lib/tls/i686/cmov/libc-2.3.6.so
b7f50000-b7f54000 rw-p b7f50000 00:00 0
b7f54000-b7f56000 r-xp 00000000 03:01 1645893    /lib/tls/i686/cmov/libdl-2.3.6.so
b7f56000-b7f58000 rw-p 00001000 03:01 1645893    /lib/tls/i686/cmov/libdl-2.3.6.so
b7f58000-b7f90000 r-xp 00000000 03:01 1628907    /lib/libncurses.so.5.5
b7f90000-b7f98000 rw-p 00038000 03:01 1628907    /lib/libncurses.so.5.5
b7f98000-b7f99000 rw-p b7f98000 00:00 0
b7fa2000-b7fa8000 r--s 00000000 03:06 716680     /usr/lib/gconv/gconv-modules.cache
b7fa8000-b7faa000 rw-p b7fa8000 00:00 0
b7faa000-b7fab000 r-xp b7faa000 00:00 0          [vdso]
b7fab000-b7fc0000 r-xp 00000000 03:01 1628802    /lib/ld-2.3.6.so
b7fc0000-b7fc2000 rw-p 00014000 03:01 1628802    /lib/ld-2.3.6.so
bfca4000-bfcb9000 rw-p bfca4000 00:00 0          [stack]
user@linuxhost:~$
Figure 1: Examining Virtual Address Space Used by Processes in Linux

Threads

Linux and the Solaris OS support POSIX threads, Linux via , and the Solaris OS as part of the standard C library. See , specifically, , for details of threads on the Solaris OS. Also quite good is the white paper .

In addition to POSIX threads, the Solaris OS supports "Solaris threads". The threads(5) man page describes the similarities and differences between the POSIX thread library and the Solaris thread library. The implementations are interoperable and can be used with care within the same application. The following is straight from the man page.

Similarities

Most of the functions in the libpthread and libthread libraries have a counterpart in the other corresponding library. POSIX function names, with the exception of the semaphore names, have a "pthread" prefix. Names for similar POSIX and Solaris functions have similar endings. Typically, similar POSIX and Solaris functions have the same number and use of arguments.

Differences
  • POSIX threads are more portable.
  • POSIX threads establish characteristics for each thread according to configurable attribute objects.
  • POSIX pthreads implement thread cancellation.
  • POSIX pthreads enforce scheduling algorithms.
  • POSIX pthreads allow for clean-up handlers for fork(2) calls.
  • Solaris threads can be suspended and continued.
  • Solaris threads implement interprocess robust mutex locks.
  • Solaris threads implement daemon threads, for whose demise the process does not wait.

The following is a very simple MT program. Very few differences are found in the ways in which multithreaded applications work between the two OSes. Of course, the underlying implementations have several differences.

#include 
#include 

void *fcn(void *);

int
main(int argc, char *argv[])
{
    pthread_t tid;

    pthread_create(&tid, NULL, fcn, NULL);
    (void) printf("main thread id = %x\n", pthread_self());
    pthread_join(tid, NULL);
}

void *
fcn(void *arg)
{
    printf("new thread id = %x\n", pthread_self());
}

Use the following to compile and run the program on the Solaris platform:

bash-3.00$ cc simplepthread.c -o simplepthread
bash-3.00$ ./simplepthread
main thread id = 1
new thread id = 2
bash-3.00$
Using gcc on the Solaris platform gives the same results. On Linux it appears thus:

max@linux:~/source> cc simplepthread.c
/tmp/cc8u7kZs.o(.text+0x1e): In function `main':
simplepthread.c: undefined reference to `pthread_create'
/tmp/cc8u7kZs.o(.text+0x4a):simplepthread.c: undefined reference
       to `pthread_join'
collect2: ld returned 1 exit status
max@linux:~/source> cc simplepthread.c -lpthread -o simplepthread
max@linux:~/source> ./simplepthread
main thread id = 4015c6c0
new thread id = 4035cbb0
max@linux:~/source>

On Linux, the POSIX thread library needs to be explicitly linked. Note that Solaris 9 and earlier versions also require this. In the Solaris 10 OS, POSIX threads are in the standard C library (libc.so). Note also that the Solaris OS assigns thread IDs using a monotonically increasing integer starting at 1. Linux uses the user virtual address of the pthread structure (structure used internally by the thread library).

Visibility to threads is provided on both systems by the ps(1) command, and via the /proc file system. See Figure 2 for the output of the ps(1) command on the Solaris platform and Figure 3 for the output on Linux. You'll see that, given the same options, the output is very similar between the machines.

user@solaris:~$ ps -elfcL
 F S      UID   PID  PPID   LWP  NLWP  CLS PRI     ADDR     SZ    WCHAN    STIME TTY        LTIME CMD
 1 T     root     0     0     1     1  SYS  96        ?      0          07:34:50 ?           0:49 sched
 0 S     root     1     0     1     1   TS  59        ?    619        ? 07:35:07 ?           0:06 /sbin/init
 1 S     root     2     0     1     1  SYS  98        ?      0        ? 07:35:07 ?           0:00 pageout
 1 S     root     3     0     1     1  SYS  60        ?      0        ? 07:35:07 ?           0:53 fsflush
 0 S     root   180     1     1     4   TS  59        ?    836        ? 07:35:13 ?           0:00 /usr/lib/picl/picld
 0 S     root   180     1     2     4   TS  59        ?    836        ? 07:35:13 ?           0:00 /usr/lib/picl/picld
 0 S     root   180     1     3     4   TS  59        ?    836        ? 07:35:16 ?           0:00 /usr/lib/picl/picld
 0 S     root   180     1     4     4   TS  59        ?    836        ? 07:35:16 ?           0:00 /usr/lib/picl/picld
 0 S     root     7     1     1    15   TS  59        ?   3341        ? 07:35:07 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     2    15   TS  59        ?   3341        ? 07:35:07 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     3    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     4    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     5    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     6    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     7    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     8    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1     9    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1    59    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1   311    15   TS  59        ?   3341        ? 07:36:04 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1   263    15   TS  59        ?   3341        ? 07:35:19 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1    98    15   TS  59        ?   3341        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1   260    15   TS  59        ?   3341        ? 07:35:18 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     7     1   294    15   TS  59        ?   3341        ? 07:35:22 ?           0:00 /lib/svc/bin/svc.startd
 0 S     root     9     1     1    16   TS  59        ?   2342        ? 07:35:07 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     2    16   TS  59        ?   2342        ? 07:35:08 ?           0:01 /lib/svc/bin/svc.configd
 0 S     root     9     1     3    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     4    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     5    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     6    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     7    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     8    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1     9    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    10    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    11    16   TS  59        ?   2342        ? 07:35:08 ?           0:01 /lib/svc/bin/svc.configd
 0 S     root     9     1    12    16   TS  59        ?   2342        ? 07:35:08 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    13    16   TS  59        ?   2342        ? 07:35:11 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    14    16   TS  59        ?   2342        ? 07:35:11 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    15    16   TS  59        ?   2342        ? 07:35:11 ?           0:00 /lib/svc/bin/svc.configd
 0 S     root     9     1    16    16   TS  59        ?   2342        ? 07:35:11 ?           0:00 /lib/svc/bin/svc.configd
 0 S   daemon   161     1     1     3   TS  59        ?   1079        ? 07:35:12 ?           0:00 /usr/lib/crypto/kcfd
 0 S   daemon   161     1     2     3   TS  59        ?   1079        ? 07:35:12 ?           0:00 /usr/lib/crypto/kcfd
 0 S   daemon   161     1     3     3   TS  59        ?   1079        ? 07:35:24 ?           0:00 /usr/lib/crypto/kcfd
 0 S     root   297     1     1     1   TS  59        ?    709        ? 07:35:16 ?           0:00 /usr/sbin/cron
 0 S     root   139     1     1    15   TS  59        ?   1331        ? 07:35:12 ?           0:00 /usr/lib/sysevent/syseventd

<-- output omitted (on bash) -->

user@solaris:~$

Figure 2: Output of ps(1) Command on Solaris Platform

user@linuxhost:~$ ps -elfcL
F S UID        PID  PPID   LWP NLWP CLS PRI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root         1     0     1    1 TS   24 -   486 -      Nov07 ?        00:00:01 init [2]
1 S root         2     1     2    1 FF  139 -     0 migrat Nov07 ?        00:00:00 [migration/0]
1 S root         3     1     3    1 TS    0 -     0 ksofti Nov07 ?        00:00:00 [ksoftirqd/0]
1 S root         4     1     4    1 FF  139 -     0 migrat Nov07 ?        00:00:00 [migration/1]
1 S root         5     1     5    1 TS    0 -     0 ksofti Nov07 ?        00:00:00 [ksoftirqd/1]
1 S root         6     1     6    1 TS   29 -     0 worker Nov07 ?        00:00:00 [events/0]
1 S root         7     1     7    1 TS   29 -     0 worker Nov07 ?        00:00:00 [events/1]
1 S root         8     1     8    1 TS   29 -     0 worker Nov07 ?        00:00:00 [khelper]
1 S root         9     1     9    1 TS   29 -     0 worker Nov07 ?        00:00:00 [kthread]
1 S root        13     9    13    1 TS   29 -     0 worker Nov07 ?        00:00:00 [kblockd/0]
1 S root        14     9    14    1 TS   29 -     0 worker Nov07 ?        00:00:00 [kblockd/1]
1 S root        15     9    15    1 TS   24 -     0 worker Nov07 ?        00:00:00 [kacpid]
1 S root       108     9   108    1 TS   28 -     0 serio_ Nov07 ?        00:00:00 [kseriod]
1 S root       150     9   150    1 TS   19 -     0 pdflus Nov07 ?        00:00:00 [pdflush]
1 S root       151     9   151    1 TS   24 -     0 pdflus Nov07 ?        00:00:00 [pdflush]
1 S root       152     9   152    1 TS   29 -     0 kswapd Nov07 ?        00:00:02 [kswapd0]
1 S root       153     9   153    1 TS   23 -     0 worker Nov07 ?        00:00:00 [aio/0]
1 S root       154     9   154    1 TS   22 -     0 worker Nov07 ?        00:00:00 [aio/1]
1 S root       304     1   304    1 TS   24 -     0 -      Nov07 ?        00:00:00 [kirqd]
1 S root       630     9   630    1 TS   29 -     0 hub_th Nov07 ?        00:00:00 [khubd]
1 S root       772     9   772    1 TS   26 -     0 worker Nov07 ?        00:00:00 [ata/0]
1 S root       773     9   773    1 TS   25 -     0 worker Nov07 ?        00:00:00 [ata/1]
1 S root       774     9   774    1 TS   26 -     0 worker Nov07 ?        00:00:00 [ata_aux]
1 S root       779     9   779    1 TS   26 -     0 scsi_e Nov07 ?        00:00:00 [scsi_eh_0]
1 S root       781     9   781    1 TS   28 -     0 scsi_e Nov07 ?        00:00:00 [scsi_eh_1]
1 S root      1071     9  1071    1 TS   29 -     0 kjourn Nov07 ?        00:00:00 [kjournald]
5 S root      1259     1  1259    1 TS   24 -   690 429496 Nov07 ?        00:00:00 udevd --daemon
1 S root      1634     9  1634    1 TS   19 -     0 worker Nov07 ?        00:00:00 [kpsmoused]
1 S root      1679     9  1679    1 TS   22 -     0 worker Nov07 ?        00:00:00 [hda_codec]
1 S root      1849     9  1849    1 TS   26 -     0 worker Nov07 ?        00:00:00 [kmirrord]
1 S root      1896     9  1896    1 TS   29 -     0 kjourn Nov07 ?        00:00:00 [kjournald]
1 S root      1898     9  1898    1 TS   29 -     0 kjourn Nov07 ?        00:00:00 [kjournald]
1 S root      1900     9  1900    1 TS   29 -     0 kjourn Nov07 ?        00:00:03 [kjournald]
5 S daemon    2271     1  2271    1 TS   23 -   422 -      Nov07 ?        00:00:00 /sbin/portmap
1 S root      2429     1  2429    1 TS   21 -   406 429496 Nov07 ?        00:00:00 /sbin/syslogd
5 S root      2435     1  2435    1 TS   24 -   394 syslog Nov07 ?        00:00:00 /sbin/klogd -x
1 S root      2458     1  2458    1 TS   18 -  1221 375710 Nov07 ?        00:00:00 /usr/sbin/hpiod
1 S root      2531     1  2531    1 TS   24 -   394 -      Nov07 ?        00:00:00 /usr/sbin/acpid -c
5 S root      2553     1  2553    1 TS   24 -  1173 -      Nov07 ?        00:00:00 /usr/sbin/cupsd
5 S 103       2561     1  2561    1 TS   24 -   629 -      Nov07 ?        00:00:00 /usr/bin/dbus-daemo5 S 105       2569     1  2569    1 TS   21 -  1430 -      Nov07 ?        00:00:01 /usr/sbin/hald
0 S root      2570  2569  2570    1 TS   15 -   724 -      Nov07 ?        00:00:00 hald-runner
4 S 105       2576  2570  2576    1 TS   15 -   505 -      Nov07 ?        00:00:00 hald-addon-acpi: li0 S root      2586  2570  2586    1 TS   21 -   453 -      Nov07 ?        00:00:04 hald-addon-storage:1 S root      2600     1  2600    1 TS   24 -   466 -      Nov07 ?        00:00:00 /usr/sbin/dhcdbd --5 S root      2607     1  2607    1 TS   24 -   996 -      Nov07 ?        00:00:00 /usr/sbin/NetworkMa5 S avahi     2619     1  2619    1 TS   24 -   638 -      Nov07 ?        00:00:00 avahi-daemon: runni1 S avahi     2620  2619  2620    1 TS   14 -   638 -      Nov07 ?        00:00:00 avahi-daemon: chroo1 S root      2627     1  2627    1 TS   16 -   727 -      Nov07 ?        00:00:00 /usr/sbin/NetworkMa5 S 100       2674     1  2674    1 TS   21 -  1329 429496 Nov07 ?        00:00:00 /usr/sbin/exim4 -bd5 S root      2692     1  2692    1 TS   24 -   437 429496 Nov07 ?        00:00:00 /usr/sbin/inetd
5 S root      2702     1  2702    1 TS   24 -  1231 429496 Nov07 ?        00:00:00 /usr/sbin/sshd
4 S root      2706     1  2706    1 TS   24 -   878 375734 Nov07 ?        00:00:00 /usr/sbin/vsftpd
5 S root      2745     1  2745    1 TS   17 -  3707 -      Nov07 ?        00:00:06 /usr/sbin/gdm
5 S root      2751  2745  2751    1 TS   21 -  3506 pipe_w Nov07 ?        00:00:00 /usr/sbin/gdm
4 S root      2752  2751  2752    1 TS   22 -  6752 429496 Nov07 tty7     00:00:00 /usr/bin/X :0 -dpi
5 S statd     2759     1  2759    1 TS   21 -   440 429496 Nov07 ?        00:00:00 /sbin/rpc.statd
1 S daemon    2800     1  2800    1 TS   21 -   458 -      Nov07 ?        00:00:00 /usr/sbin/atd
1 S root      2807     1  2807    1 TS   21 -   549 -      Nov07 ?        00:00:00 /usr/sbin/cron
<-- output omitted (on bash) -->
user@linuxhost:~$

Figure 3: Output of ps(1) Command on Linux

The command shows state, user, PID, parent PID, LWP ID, number of LWPs (for user processes, this is the number of threads), scheduling class, scheduling priority, user virtual size, wait channel, start time, tty, time spent running, and command. Linux does not report ADDR, and the Solaris OS shows the (kernel) virtual address of the proc_t data structure, which the kernel uses to maintain the process. Linux shows WCHAN as a symbol, while the Solaris OS shows it as an address. In the Solaris OS, the WCHAN column is the address of a synchronization variable on which the thread is blocked. On Linux, WCHAN is the routine in which the thread is sleeping. To get the equivalent information in the Solaris OS, use ::threadlist -v inside of mdb -k.

Note that on a machine running a 64-bit kernel (that is, SPARC or AMD64 architecture based), the ADDR and WCHAN fields will display a question mark (?). To see the values for these two fields, use ps -e -o addr,wchan,comm.

More likely, you are interested in what the application threads are doing. For this, use pstack(1) on the process ID of interest. There is a pstack on Linux, but it must be downloaded. Search for it on . Note that it only gives the stack backtrace of one thread (the thread ID that is passed to it as an argument). If you want a backtrace of all threads within a process, you need to pass the thread IDs as separate arguments.

 <-- get user-level stack(s) of a process on Solaris -->
bash-3.00$ pstack `pgrep mozilla-bin` 
21528: /usr/sfw/bin/../lib/mozilla/mozilla-bin -UILocale en-US
-----------------  lwp# 1 / thread# 1  --------------------
 fef68967 pollsys  (896dac8, 9, 0, 0)
 fef2b2aa poll     (896dac8, 9, ffffffff) + 52
 fe793242 g_main_context_iterate () + 39d
-----------------  lwp# 2 / thread# 2  --------------------
 fef68967 pollsys  (fbf5bd04, 1, 0, 0)
 fef2b2aa poll     (fbf5bd04, 1, ffffffff) + 52
 fede047d _pr_poll_with_poll (816fa0c, 1, ffffffff, fbf5bf64,
                                 fc0558aa, 816fa0c) + 2d5
 fede05f1 PR_Poll  (816fa0c, 1, ffffffff) + 11
 fc0558aa __1cYnsSocketTransportServiceEPoll6M_i_ (816f6b8) + 58
 fc055f7d __1cYnsSocketTransportServiceDRun6M_I_ (816f6b8) + 18f
 fc3d1262 __1cInsThreadEMain6Fpv_v_ (816eb60) + 32
 fede1693 _pt_root (816fcc0) + 9e
 fef67b30 _thr_setup (feec2400) + 51
 fef67f40 _lwp_start (feec2400, 0, 0, 0, 0, 0)
-----------------  lwp# 4 / thread# 4  --------------------
 fef67f7b lwp_park (0, fa87deb8, 0)
 fef620bb cond_wait_queue (825cfec, 816b8d0, fa87deb8, 0) + 3e
 fef62462 cond_wait_common (825cfec, 816b8d0, fa87deb8) + 1e9
 fef62691 _cond_timedwait (825cfec, 816b8d0, fa87df38) + 4a
 fef62722 cond_timedwait (825cfec, 816b8d0, fa87df38) + 27
 fef62761 pthread_cond_timedwait (825cfec, 816b8d0,
                                    fa87df38) + 21
 feddc598 pt_TimedWait (825cfec, 816b8d0, f1c) + b8
 feddc767 PR_WaitCondVar (825cfe8, f1c) + 64
 fc3d417e __1cLTimerThreadDRun6M_I_ (81e5108) + 16e
 fc3d1262 __1cInsThreadEMain6Fpv_v_ (820d690) + 32
 fede1693 _pt_root (820e6b0) + 9e
 fef67b30 _thr_setup (fb520400) + 51
 fef67f40 _lwp_start (fb520400, 0, 0, 0, 0, 0)
bash-3.00$ 
Here is an equivalent on Linux. It is interesting that programs like Mozilla and xemacs are stripped on Linux and not stripped on the Solaris OS.
max@linux:~> cd /proc/`pgrep mozilla`/task
max@linux:/proc/3991/task> pstack *

3991: /opt/mozilla/lib/mozilla-bin
(No symbols found)
0xffffe410: ???? (8803488, 8, ffffffff, 8803488, 9, 400fbea0) + 40
0x404b0a6d: ???? (8129258, 4035236c, 57f, 4011e4e6, 4048de14,
                   403513c4) + 20
0x404b0d07: ???? (814b898, 814b898, 0, 0, 415a8f64, 814b898) + 30
0x401dc11f: ???? (8106350, bfffee80, bfffede8, 807673e, 8084cf4, 0)
0x415c4006: ???? (8106350, 0)
0x414fbae4: ???? (8105ee8, 0, 8079c2c, bfffee90, 80a67b8,
                      40ad841c) + 1f0
0x08059b7c: ???? (80e7f08, bffff058, 40017068, 14, 4081ccf8,
                       1) + 90
0x08055a47: ???? (1, bffff134, bffff13c, 4081ccf8, 406eebd0,
                     400168c0) + 40
0x405f2500: ???? (8055840, 1, bffff134, 80557b0, 8055740, 
                     4000d330) + 40000ed8

4001: /opt/mozilla/lib/mozilla-bin
(No symbols found)
0xffffe410: ???? (413eb7f0, 1, ffffffff, 18, 413eb7f8, 0) + 230
0x400c7439: ???? (818911c, 1, ffffffff, 40c5a0a8, ffffffff,
                   8188dec)
0x40bc8a52: ???? (8188dc8, 8188df4, 1, 8188dec, 8188f7c, 1) + 10
0x40bc8bcb: ???? (8188dc8, 413ebbb0, 40102ce0, 400d5238,
                   8189478, 0)
0x40a8da6b: ???? (81893f8, 8189478, 4000ca40, 40102be8, 0, 0)
0x400cb7a6: ???? (8189478, 413ebac4, 0, 0, 0, 0) + 54
0x400fa9dd: ???? (413ebbb0, 0, 0, 0, 0, 0) + bec144d4

4004: /opt/mozilla/lib/mozilla-bin
(No symbols found)
0xffffe410: ???? (40656756, 400d5238, 81ed160, 81ed2d0, 41ffba08,
                   400c5721) + 170fd55
crawl: Input/output error
Error tracing through process 4004
0x1afcdbf8: ????max@linux:/proc/3991/task> 

Solaris threads are given a default user stack size of 1MB. For Linux, the default stack size is 2MB (SuSe 9.1).

Synchronization

Both OSes support POSIX synchronization mechanisms, i.e., mutexes, condition variables, reader/writer locks, semaphores, and barriers. The underlying mechanisms rely on mutexes. In Solaris, user-level mutexes are implemented using "adaptive" spin locks. On Linux, the mechanism is the "futex", or fast user level mutex. Both mechanisms avoid going into the kernel in the non-contention case, and should give comparable performance and behavior.

The Solaris user-level adaptive spin mutexes are described in . Linux futexes are described in .

The Solaris OS mechanisms lwp_park() and lwp_unpark(), and Linux mechanisms futex_up() and futex_down(), can be used by applications. However, I have not found any source code examples. It is probably best to stick with the POSIX APIs. If you want to compare relative speeds of the POSIX locking mechanisms (as well as performance of various other library routines and system calls), I recommend getting a copy of the libmicro micro benchmark and trying it out on both the Solaris OS and Linux. (You can libmicro from the OpenSolaris site.) Be aware that the upcoming Solaris 11 release (the latest build available through OpenSolaris and Solaris Express, code named Nevada), is a debug build, which will have an effect on any performance numbers you are seeing.

Memory Management

Without describing differences in the kernels' handling of memory, we can say that at user level several different memory allocation (malloc) libraries exist, most of which are available (or can be built) for either OS. A comparison of some of the user-level memory allocators can be found in the Sun Developer Network article A Comparison of Memory Allocators in Multiprocessors. "A Memory Allocator" at contains a (dated) description of a memory allocator used on Linux. More comments can be found in the source code.

Timers

At application level, the Solaris OS and Linux both offer POSIX timer routines, including timer_create(), timer_delete(), and nanosleep(). The Solaris OS has an additional timer, CLOCK_HIGHRES, that attempts to use an optimal hardware source, and may give close to nanosecond resolution. A CLOCK_HIGH_RES timer may give similar resolution on Linux, but needs to be installed as a kernel patch (see home page for the high resolution timers project at for details). The following is example code that uses the CLOCK_HIGHRES timer to fire on user-specified intervals for a user-specified duration. The interval is specified in nanoseconds, and the duration in seconds. When the program completes, it prints the number of times the timer fired, and the number of times the timer was "overrun". The "overrun" value is a count of the number of timer expirations that occurred between the time a timer fired (causing a signal to be generated), and the time the signal is handled (see timer_getoverrun(3RT). Running the program real-time with too short an interval may cause the system to hard hang.

#include 
#include 
#include 
#include 
#include 
#include 

#include 

#define DURATION 120    /* default time to run in seconds */

  /* default .5 seconds in nanosecs */
#define INTERVAL (1000*1000*500)

void* timer_fcn(void* arg);
void* signaler_thd(void* arg);

/* Program globals */
extern int errno;
int duration = DURATION;
int interval = INTERVAL;

int
main(int argc, char *argv[]) 
{
   sigset_t mask;
   pthread_t wtid = 0;
   pthread_t stid = 0;
   int rval;
   int n;

   if (argc >=2) {
       errno = 0;
       if (argc == 2)
         duration = strtol(argv[1], NULL, 0);
       else if (argc == 3) {
         interval = strtol(argv[1], NULL, 0);
         duration = strtol(argv[2], NULL, 0);
       }
       if (errno || argc > 3 || interval <= 0
          || duration <= 0) {
           fprintf(stderr, "Usage: %s [[interval] duration]\n",
                  argv[0]);
           fprintf(stderr, "interval nsecs, duration seconds\n");
           exit(1);
       }
   }
     
   /* mask SIGALRM signals */
   sigemptyset(&mask);
   sigaddset(&mask, SIGALRM);
   sigaddset(&mask, SIGUSR1);
   rval = pthread_sigmask(SIG_BLOCK, &mask, NULL);
   if(rval != 0) {
      printf("%s: pthread_sigmask failed, errno = %d.\n",
             argv[0], rval);
      exit(1);
   }

   rval = pthread_create(&wtid, NULL, timer_fcn, NULL);
   if (rval != 0) {  /* Waiter create call create failed */
    perror ("Waiter create");
    printf ("Waiter create call failed: %d.\n", rval);
    exit (1);
    }


   /* Do signaler thread */
   rval = pthread_create(&stid, NULL, signaler_thd, &mask);
   if (rval != 0) {  /* Signaler call create failed */
    printf ("Signaler call create failed: %d.\n", rval);
    exit (1);
   }

   /* Wait for waiter and signaler to finish */    
   rval = pthread_join(stid, NULL);
   if (rval != 0) {  /* Signaler call join failed */
    printf ("Signaler call join failed: %d.\n", rval);
    exit (1);
   }

   rval = pthread_join(wtid, NULL);
   if (rval != 0) {  /* Waiter call join failed */
    printf ("Waiter call join failed: %d.\n", rval);
    exit (1);
   }

   printf("done\n");
   exit(0);
}

pthread_mutex_t mp;
pthread_cond_t cv;
int time_expired = 0;
int timerentered;
int timeroverrun;
timer_t itimerid;

void *
timer_fcn(void *arg)
{
  struct itimerspec value;
  struct sigevent event;

  value.it_interval.tv_sec = 0;
  value.it_interval.tv_nsec = interval;  /* nsec intervals  */
  value.it_value.tv_sec = 1;  /* starting in 1 second */
  value.it_value.tv_nsec = 0;  /* plus 0 nanosecs */

  event.sigev_notify = SIGEV_SIGNAL;
  event.sigev_signo = SIGALRM;
  event.sigev_value.sival_int = 0;
  

  if (timer_create(CLOCK_HIGHRES, &event,
     &itimerid) == -1) {
       perror("timer_create failed");
       exit(1);
  }

  /* the second arg can be set to TIMER_ABSTIME */
  if (timer_settime(itimerid, 0, &value, NULL) == -1) {
      /* else time value is relative to when the call is made */
    perror("timer_settime failed");
    exit(1);
  }

  pthread_mutex_lock(&mp);
  while (time_expired == 0)
    pthread_cond_wait(&cv, &mp);
  printf("timerentered = %d\n", timerentered);
  printf("timeroverrun = %d\n", timeroverrun);
  pthread_mutex_unlock(&mp);
  exit(0);
}

int timerset;

void *
signaler_thd(void *arg)
{
    int signo;
    
    while (1) {
      signo = sigwait(arg);
      if (signo == SIGALRM) {
       if (!timerset) {
        struct itimerspec value;
        struct sigevent event;

        timer_t endtimerid;

        ++timerset;
        value.it_interval.tv_sec = 0;
        value.it_interval.tv_nsec = 0;
        value.it_value.tv_sec = duration; /*wait duration secs*/
        value.it_value.tv_nsec = 0;  /* plus 0 nanosecs */

        event.sigev_notify = SIGEV_SIGNAL;
        event.sigev_signo = SIGUSR1;
        event.sigev_value.sival_int = 0;
  

        if (timer_create(CLOCK_HIGHRES, &event,
         &endtimerid) == -1) {
           perror("timer_create failed");
           exit(1);
        }

        /* the second arg can be set to TIMER_ABSTIME */
        if (timer_settime(endtimerid, 0, &value, NULL)
          == -1) {
          perror("timer_settime failed");
          exit(1);
        }
       } else {  /* if (!timerset) */
        ++timerentered;
        timeroverrun += timer_getoverrun(itimerid);
       }
      } else {  /* SIGUSR1 */

       struct itimerspec value;
       struct sigevent event;


       /* cancel the interval timer */
       value.it_interval.tv_sec = 0;
       value.it_interval.tv_nsec = 0;  /* nanosecond intervals */
       /* setting the following to 0 should stop the timer */
       value.it_value.tv_sec = 0;
       value.it_value.tv_nsec = 0;  /* plus 0 nanosecs */

       event.sigev_notify = SIGEV_SIGNAL;
       event.sigev_signo = SIGALRM;
       event.sigev_value.sival_int = 0;
  
       pthread_mutex_lock(&mp);
       if (timer_settime(itimerid, 0, &value, NULL) == -1) {
        perror("timer_settime failed");
        exit(1);
       }

       ++time_expired;
       pthread_cond_signal(&cv);
       pthread_mutex_unlock(&mp);
      }
   }
}

And here are some examples of running the compiled code.

  <-- realtime library and best optimization -->
bash-3.00$ cc timerex1.c -lrt -o timerex1 -O -fast
bash-3.00$ ./timerex1  <-- only root can use high res timer
timer_create failed: Not owner
bash-3.00$ su
Password: 
  <-- default interval is .5 seconds, duration is 120 seconds -->
# ./timerex1  
timerentered = 240  <-- timer fired every .5 seconds
timeroverrun = 0
# ./timerex1 1000000 10  <-- interval is 1 msec for 10 secs
timerentered = 9912
timeroverrun = 88
# priocntl -e -c RT ./timerex1 1000000 10  <-- run it real time
timerentered = 10000  <-- timer fired once each msec for 10 secs
timeroverrun = 0
# ./timerex1 100000 10  <-- interval is 100 usecs for 10 seconds
timerentered = 99615  <-- we missed a few
timeroverrun = 386
# priocntl -e -c RT ./timerex1 100000 10  <-- try real time 
timerentered = 99871  <-- almost 1 every 100 microseconds
timeroverrun = 129
# ./timerex1 10000 10  <-- interval is 10 microseconds
timerentered = 485905  <-- here we miss over half
timeroverrun = 514125  <-- (sig handler takes > 10 usecs?)
 <-- using RT 1 usec interval causes hang on my machine -->

# priocntl -e -c RT ./timerex1 1000 10 

IPC

Both the Solaris OS and Linux support System V IPC (shared memory, message queues, and semaphores). Both systems also support pipes and the real-time shared memory operations (shm_open(), shm_unlink(), and so on). Both systems support the tmpfs file system (using memory and swap space for files). The Solaris OS places /tmp, /var/run, and /etc/svc/volatile in tmpfs. Linux uses /dev/shm. Both systems allow other mount points to be added.

Here are the steps for using tmpfs on the Solaris OS; steps for Linux are shown below. Note that "swap" on the Solaris OS uses memory as well as disk (if needed). In other words, files created in /tmp are stored in memory. If memory gets full, the pageout daemon may write data from /tmp to swap space on disk.

# mkdir /foo
<-- create a tmpfs file system using swap on /foo
# mount -F tmpfs swap /foo  
# df -h /foo
Filesystem         size   used  avail capacity  Mounted on
swap           652M     0K   652M     0%    /foo
# df -h /tmp
Filesystem         size   used  avail capacity  Mounted on
swap           652M    52K   652M     1%    /tmp
# 

And here are the analogous steps on Linux.

linux:/home/max # mkdir /foo
 <-- tmpfs also uses swap space and memory -->
linux:/home/max # mount tmpfs /foo -t tmpfs 
linux:/home/max # df -h /foo
Filesystem        Size  Used Avail Use% Mounted on
tmpfs         248M     0  248M   0% /foo
linux:/home/max # df -h /dev/shm
Filesystem        Size  Used Avail Use% Mounted on
tmpfs         248M   16K  248M   1% /dev/shm
linux:/home/max # 

It might be interesting to run the libmicro benchmarks mentioned earlier in the article to get some idea of relative performance between the systems.

Signal Handling

The Solaris OS and Linux treat signals similarly. Some signals exist in the Solaris OS and not in Linux, and vice versa. Also, some of the same signals use different signal numbers. Both OSes recommend using sigaction(2) over signal() to catch signals, and the use of sigwait() to handle asynchronous signals in multithreaded applications. The sigwait(3) manual page on Linux has a BUGS section. The Linux signal handling differs from the POSIX standard. POSIX states that an asynchronously delivered signal (a signal sent externally to the process), is handled by any thread that does not have the signal currently blocked. In Linux, asynchronous signals may be sent to specific threads (signals can be sent to the thread ID via kill(1)). The Solaris OS implements the POSIX standard for this. There is no way to send a signal to a specific thread externally to the process. One can send a signal via kill(1) to the process, not to a specific thread within the process.

Some of the differences are described in "Building Applications with the Linux Standard Base" at . Note that this page may not be entirely accurate. For instance, the page says that Linux sets SIGBUS to SIGUNUSED because there is no "bus error" in Linux. However, the Linux man page for mmap(2) documents receiving SIGBUS when accessing a memory range that does not correspond to a valid location in the file that mmap was used with. (The Solaris OS does the same).

On both the Solaris OS and Linux, signals are handled when a non-held, non-ignored signal is found pending for a thread returning from kernel to user mode. On both systems, SIGKILL and SIGSTOP take priority over other signals. Otherwise, on Solaris signals are handled in an undocumented order (lowest signal number first). On Linux, signals are handled in the order they are delivered (again, excepting SIGKILL and SIGSTOP).

On the Solaris OS, to see the signal settings for a running process, use psig.

bash-3.00$ psig $$  <-- signal disp for current shell
954:	/usr/bin/bash -i
HUP	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
INT	caught	sigint_sighandler	0
QUIT	ignored
ILL	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
TRAP	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
ABRT	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
EMT	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
FPE	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
KILL	default
BUS	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
SEGV	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
SYS	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
PIPE	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
ALRM	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
TERM	ignored
USR1	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
USR2	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
CLD	blocked,caught	0x807d4d7 	0
PWR	default
WINCH	caught	0x807e182   0  <-- not all syms are present
URG	default
POLL	default
STOP	default
TSTP	ignored
CONT	default
TTIN	ignored
TTOU	ignored
VTALRM	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
PROF	default
XCPU	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
XFSZ	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
WAITING	default
LWP	default
FREEZE	default
THAW	default
CANCEL	default
LOST	caught	termination_unwind_protect	0	HUP,INT,
  ILL,TRAP,ABRT,EMT,FPE,BUS,SEGV,SYS,PIPE,ALRM,TERM,USR1,USR2,
  VTALRM,XCPU,XFSZ,LOST
XRES	default
JVM1	default
JVM2	default
RTMIN	default
RTMIN+1	default
RTMIN+2	default
RTMIN+3	default
RTMAX-3	default
RTMAX-2	default
RTMAX-1	default
RTMAX	default
bash-3.00$ 

As far as I can tell, there is no easy way to do this in Linux, but someone has probably implemented a kernel patch/module to give you the information. Certainly it should be do-able with User Mode Linux.

Generally, if you are developing a POSIX-compliant application on Linux or the Solaris OS, the application should port to the other OS simply by recompilation. Of course, many applications will have parts that are not addressed by POSIX. For instance, device ioctl(2) handling tends to be OS (and, of course, device) specific.

Getting documentation for the Solaris OS is reasonably straightforward, since most of the documentation is at . Getting documentation for Linux is sometimes simple (search on the web), and sometimes not so simple. You'll find that Linux typically offers multiple ways to do the same thing (different implementations of threads, for example). My impression is that much of the Linux documentation is in the source code itself. This is fine if you have access to all the source code. You do have access to all of the source code, but it is not all in one place. In fact, it seems scattered all over the place. Sun's source is currently available all in one place (), but not all of it is there. I expect that over time, developers will add software to OpenSolaris that may not be available in the OpenSolaris source tree.

This article touched on some of the visibility tools available on the two systems, but did not get into much detail. Prior to Sun's coming out with OpenSolaris, Linux advocates could always point to the source as a differentiator when it came to visibility as to how things work. Now, with OpenSolaris and tools such as DTrace, Linux will have to play catch up. And at the rate of change of Linux, I'm sure it won't take long. I'm looking forward to both systems benefiting from each other's good features, and learning from their mistakes.




阅读(2128) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-23 15:45:21

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com