⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 notes.html

📁 快速开发
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<HTML><HEAD><TITLE>State Threads Library Programming Notes</TITLE></HEAD><BODY BGCOLOR=#FFFFFF><H2>Programming Notes</H2><P><B><UL><LI><A HREF=#porting>Porting</A></LI><LI><A HREF=#signals>Signals</A></LI><LI><A HREF=#intra>Intra-Process Synchronization</A></LI><LI><A HREF=#inter>Inter-Process Synchronization</A></LI><LI><A HREF=#nonnet>Non-Network I/O</A></LI><LI><A HREF=#timeouts>Timeouts</A></LI></UL></B><P><HR><P><A NAME="porting"><H3>Porting</H3>The State Threads library uses OS concepts that are available in someform on most UNIX platforms, making the library very portable acrossmany flavors of UNIX.  However, there are several parts of the librarythat rely on platform-specific features.  Here is the list of such parts:<P><UL><LI><I>Thread context initialization</I>: Two ingredients of the<TT>jmp_buf</TT>data structure (the program counter and the stack pointer) have to bemanually set in the thread creation routine. The <TT>jmp_buf</TT> datastructure is defined in the <TT>setjmp.h</TT> header file and differs fromplatform to platform.  Usually the program counter is a structure memberwith <TT>PC</TT> in the name and the stack pointer is a structure memberwith <TT>SP</TT> in the name.  One can also look in the<A HREF="http://www.mozilla.org/source.html">Netscape's NSPR library source</A>which already has this code for many UNIX-like platforms(<TT>mozilla/nsprpub/pr/include/md/*.h</TT> files).<P>Note that on some BSD-derived platforms <TT>_setjmp(3)/_longjmp(3)</TT>calls should be used instead of <TT>setjmp(3)/longjmp(3)</TT> (that isthe calls that manipulate only the stack and registers and do <I>not</I>save and restore the process's signal mask).</LI><P>Starting with glibc 2.4 on Linux the opacity of the <TT>jmp_buf</TT> datastructure is enforced by <TT>setjmp(3)/longjmp(3)</TT> so the<TT>jmp_buf</TT> ingredients cannot be accessed directly anymore (unlessspecial environmental variable LD_POINTER_GUARD is set before applicationexecution). To avoid dependency on custom environment, the State Threadslibrary provides <TT>setjmp/longjmp</TT> replacement functions forall Intel CPU architectures. Other CPU architectures can also be easilysupported (the <TT>setjmp/longjmp</TT> source code is widely available formany CPU architectures).<P><LI><I>High resolution time function</I>: Some platforms (IRIX, Solaris)provide a high resolution time function based on the free running hardwarecounter.  This function returns the time counted since some arbitrarymoment in the past (usually machine power up time).  It is not correlated inany way to the time of day, and thus is not subject to resetting,drifting, etc.  This type of time is ideal for tasks where cheap, accurateinterval timing is required.  If such a function is not available on aparticular platform, the <TT>gettimeofday(3)</TT> function can be used(though on some platforms it involves a system call).<P><LI><I>The stack growth direction</I>: The library needs to know whether thestack grows toward lower (down) or higher (up) memory addresses.One can write a simple test program that detects the stack growth directionon a particular platform.</LI><P><LI><I>Non-blocking attribute inheritance</I>: On some platforms (e.g. IRIX)the socket created as a result of the <TT>accept(2)</TT> call inherits thenon-blocking attribute of the listening socket. One needs to consult the manualpages or write a simple test program to see if this applies to a specificplatform.</LI><P><LI><I>Anonymous memory mapping</I>: The library allocates memory segmentsfor thread stacks by doing anonymous memory mapping (<TT>mmap(2)</TT>). Thismapping is somewhat different on SVR4 and BSD4.3 derived platforms.<P>The memory mapping can be avoided altogether by using <TT>malloc(3)</TT> forstack allocation.  In this case the <TT>MALLOC_STACK</TT> macro should bedefined.</LI></UL><P>All machine-dependent feature test macros should be defined in the<TT>md.h</TT> header file. The assembly code for <TT>setjmp/longjmp</TT>replacement functions for all CPU architectures should be placed inthe <TT>md.S</TT> file.<P>The current version of the library is ported to:<UL>  <LI>IRIX 6.x (both 32 and 64 bit)</LI>  <LI>Linux (kernel 2.x and glibc 2.x) on x86, Alpha, MIPS and MIPSEL,  SPARC, ARM, PowerPC, 68k, HPPA, S390, IA-64, and Opteron (AMD-64)</LI>  <LI>Solaris 2.x (SunOS 5.x) on x86, AMD64, SPARC, and SPARC-64</LI>  <LI>AIX 4.x</LI>  <LI>HP-UX 11 (both 32 and 64 bit)</LI>  <LI>Tru64/OSF1</LI>  <LI>FreeBSD on x86, AMD64, and Alpha</LI>  <LI>OpenBSD on x86, AMD64, Alpha, and SPARC</LI>  <LI>NetBSD on x86, Alpha, SPARC, and VAX</LI>  <LI>MacOS X (Darwin/Tiger)</LI>  <LI>Cygwin</LI></UL><P><A NAME="signals"><H3>Signals</H3>Signal handling in an application using State Threads should be treated thesame way as in a classical UNIX process application. There is no suchthing as per-thread signal mask, all threads share the same signal handlers,and only asynchronous-safe functions can be used in signal handlers.However, there is a way to process signals synchronously by converting asignal event to an I/O event: a signal catching function does a write toa pipe which will be processed synchronously by a dedicated signal handlingthread.  The following code demonstrates this technique (error handling isomitted for clarity):<PRE>/* Per-process pipe which is used as a signal queue. *//* Up to PIPE_BUF/sizeof(int) signals can be queued up. */int sig_pipe[2];/* Signal catching function. *//* Converts signal event to I/O event. */void sig_catcher(int signo){  int err;  /* Save errno to restore it after the write() */  err = errno;  /* write() is reentrant/async-safe */  write(sig_pipe[1], &signo, sizeof(int));  errno = err;}/* Signal processing function. *//* This is the "main" function of the signal processing thread. */void *sig_process(void *arg){  st_netfd_t nfd;  int signo;  nfd = st_netfd_open(sig_pipe[0]);  for ( ; ; ) {    /* Read the next signal from the pipe */    st_read(nfd, &signo, sizeof(int), ST_UTIME_NO_TIMEOUT);    /* Process signal synchronously */    switch (signo) {    case SIGHUP:      /* do something here - reread config files, etc. */      break;    case SIGTERM:      /* do something here - cleanup, etc. */      break;      /*      .              .         Other signals              .              .      */    }  }  return NULL;}int main(int argc, char *argv[]){  struct sigaction sa;        .        .        .  /* Create signal pipe */  pipe(sig_pipe);  /* Create signal processing thread */  st_thread_create(sig_process, NULL, 0, 0);  /* Install sig_catcher() as a signal handler */  sa.sa_handler = sig_catcher;  sigemptyset(&sa.sa_mask);  sa.sa_flags = 0;  sigaction(SIGHUP, &sa, NULL);  sa.sa_handler = sig_catcher;  sigemptyset(&sa.sa_mask);  sa.sa_flags = 0;  sigaction(SIGTERM, &sa, NULL);        .        .        .      }</PRE><P>Note that if multiple processes are used (see below), the signal pipe shouldbe initialized after the <TT>fork(2)</TT> call so that each process has itsown private pipe.<P><A NAME="intra"><H3>Intra-Process Synchronization</H3>Due to the event-driven nature of the library scheduler, the thread contextswitch (process state change) can only happen in a well-known set oflibrary functions.  This set includes functions in which a thread may"block":<TT>  </TT>I/O functions (<TT>st_read(), st_write(), </TT>etc.),sleep functions (<TT>st_sleep(), </TT>etc.), and thread synchronizationfunctions (<TT>st_thread_join(), st_cond_wait(), </TT>etc.).  As a result,process-specific global data need not to be protected by locks since a threadcannot be rescheduled while in a critical section (and only one thread at atime can access the same memory location).  By the same token,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -