This article series is intended as a reference for migration between OS/2 and Linux. You can refer to it at any time in the migration process, but it is most helpful in the planning stages, as it provides tips and caveats you will want to know as you plan your migration design and strategies.
This time you will examine timer calls and DLL calls in OS/2 and in Linux, plus mapping between the two systems.
In Parts 1 and 2 of this series, you looked at threads, synchronization mechanisms like semaphores and mutexes, memory management, various IPC mechanisms, and file management.
First, we will look at calls for several types of timers:
- Interval timers
- Start timers
- Stop timers
- High resolution timers
In OS/2, the call DosStartTimer starts a
repeated interval timer that posts an event semaphore at every timer
interval. Linux does not provide a direct mappable call that repeatedly
posts a semaphore, but you can be achieve that functionality by using a
combination of the setitimer system call and
the Linux signal handling mechanism.
In OS/2, the timer value parameter is in milliseconds. On
Linux, this information is specified with an object of type struct itimerval, which has both seconds and
microseconds resolution.
Table 1. Interval timer calls mapping table
| OS/2 | Linux | Classification |
| DosStartTimer | setitimer | Mappable |
| DosStopTimer | setitimer itimerclear | Mappable |
In OS/2, the system call DosStartTimer() starts an asynchronous, repeated-interval timer:
APIRETDosStartTimer(ULONG msec, HSEM hsem, PHTIMER phtimer);
msecis the time, in milliseconds, that will elapse between postings of the event semaphore.hsemis the handle of the event semaphore that is posted each timemsecelapses.phtimeris a pointer to the timer handle.
Linux does not have a direct mappable API call to signal a semaphore
at repeated intervals. To achieve this, use interval timers. An interval timer sends a SIGALRM
signal to the process. The event semaphore is posted in the signal
handler, or the code that is waiting for the semaphore to be posted is placed in the signal handler routine:
int setitimer (int mode, const struct itimerval *newvalue, struct itimerval
*oldvalue);
modemust beITIMER_REALso the timer decrements in real time, and delivers aSIGALRMupon expiration.newvalueis a pointer to anitimervalstructure containing the timer value to be set.oldvalueis a pointer to anitimervalstructure to hold the old timer value.
On success, setitimer returns zero (and -1
on error) with errno set to the appropriate
value. A timer value is defined by the first parameter newvalue of type struct
itimerval. When newvalue->it_value is
non-zero, it indicates the time to the next timer expiration. When newvalue ->it_interval is non-zero, it specifies
the value to be used in reloading newvalue
->it_value when the timer expires.
Only use async-safe functions in signal
handlers. For instance, do not use pthread
conditional variables in the signal handler.
In OS/2, DosStopTimer() stops an
asynchronous timer:
APIRETDosStopTimer(HTIMER htimer);
htimeris the handle of the timer to stop. It returns zero on success and non-zero on failure.
In Linux, to stop an interval timer, first call the macro timerclear to clear the it_value field of struct itimerval. Then call setitimer with a cleared itimerval.
Setting it_value to 0 disables the timer,
regardless of the value of it_interval. Setting
it_interval to 0 disables a timer after its
next expiration (assuming it_value is
non-zero).
timerclear is a macro defined (in
sys/time.h) as:
#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
The code in Listing 1 starts an asynchronous timer that repeatedly posts an event semaphore at every timer interval.
Listing 1. OS/2 Interval timers example
int main(VOID)
{
HEV hevEvent1 = 0; /* Event semaphore handle */
HTIMER htimerEvent1 = 0; /* Timer handle */
APIRET rc = NO_ERROR; /* Return code */
ULONG ulPostCount = 0; /* Semaphore post count */
ULONG i = 0; /* A loop index */
/*
* Create an even semaphore that will be posted on timer interval
*/
rc = DosCreateEventSem(NULL, /* Unnamed semaphore */
&hevEvent1, /* Handle of semaphore
* returned
*/
DC_SEM_SHARED, /* Indicate a shared semaphore */
FALSE); /* Put in RESET state */
if (rc != NO_ERROR) {
printf("DosCreateEventSem error: return code = %u\n", rc);
return 1;
}
/*
* Start the timer setting a interval at 1 sec
*/
rc = DosStartTimer(1000L, /* 1 second interval */
(HSEM) hevEvent1, /* Semaphore to post */
&htimerEvent1); /* Timer handler (returned) */
if (rc != NO_ERROR) {
printf("DosStartTimer error: return code = %u\n", rc);
return 1;
}
for (i = 1 ; i < 6 ; i++)
{
DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT); /* Wait indefinitely */
DosResetEventSem(hevEvent1, /* Reset the semaphore */
&ulPostCount); /* And get count
* (should be 1)
*/
printf("Iteration %u: ulPostCount = %u\n", i, ulPostCount);
} /* for loop */
rc = DosStopTimer(htimerEvent1); /* Stop the timer */
if (rc != NO_ERROR)
{
printf("DosStopTimer error: return code = %u\n", rc);
return 1;
}
DosCloseEventSem(hevEvent1); /* Get rid of semaphore */
return NO_ERROR;
}
|
The code in Listing 2 starts an asynchronous timer that repeatedly posts an event semaphore at every timer interval.
Listing 2. Linux interval timer example
sem_t sem;
/* callback to handle SIGALRM */
void f (int signo)
{
/* Here you can post on a semaphore */
sem_post(&sem);
}
int main ()
{
int i;
int rc;
/* Declare an itimer object to start a timer */
struct itimerval itimer;
/* Initialize the semaphore. */
sem_init(&sem,0,0);
/* timer interval is 1 sec. */
itimer.it_interval.tv_sec = 1;
itimer.it_interval.tv_usec = 0;
/* Time to the next timer expiration */
itimer.it_value.tv_sec = 1;
itimer.it_value.tv_usec = 0;
/* Install a signal handler to handle SIGALRM */
signal (SIGALRM, f);
/* Start a timer with the ITIMER_REAL clock */
i = setitimer (ITIMER_REAL, &itimer, 0);
if (i == -1)
{
perror ("timer st failed ...\n");
exit (0);
}
for (i = 1 ; i < 6 ; i++)
{
rc = sem_wait(&sem);
if (rc != 0)
{
perror ("sem_wait:");
return 1;
}
printf("Iteration %d: \n", i);
} /* for loop */
/* Set the timer object value with zero, by using the macro
* timerclear and
* set the ITIMER_REAL by calling setitimer.
* This essentially stops the timer.
*/
timerclear(&itimer.it_value);
setitimer (ITIMER_REAL, &itimer, 0);
return 0;
}
|
Next, we will show you how to get the current timer count and frequency
from a high resolution timer. On OS/2, DosTmrQueryTime() returns the time stamp counter from
intel 8254 timer (programmable interrupt timer). Linux has no APIs
available to get this information. You can use the inline function get_cycles() defined in the
<asm/timex.h> kernel header.
Use the time stamp counter in conjunction with the frequency of the clock, as the ratio of counter to frequency remains the same on different clocks.
Table 2. Timer query calls mapping table
| OS/2 | Linux | Classification |
| DosTmrQueryTime | get_cycles | Mappable |
| DosTmrQueryFreq | Unmappable, but you can obtain the clock frequency from /proc/cpuinfo; see Listing 3. |
In OS2, the system call DosTmrQueryTime() gets a snapshot of the high-resolution timer count from the IRQ0
high-resolution timer (Intel 8254):
APIRET DosTmrQueryTime(PQWORD pqwTmrTime);
pqwTmrTimeis the output parameter where timer count value is returned.
In Linux, the inline function get_cycles()
returns the time stamp counter of the system clock, which is a 64-bit
value. The function always succeeds (basically, it executes a machine
instruction):
static inline cycles_t get_cycles (void);
In OS2, the system call DosTmrQueryFreq()
gets the frequency of the IRQ0 high resolution timer (Intel
8254):
APIRET DosTmrQueryFreq (PULONG pulTmrFreq)
pulTmrFreqis the output parameter to which the timer frequency is returned byDosTmrQueryFreq.
Linux has no equivalent to DosTmrQueryFreq, but you can obtain the clock frequency from /proc/cpuinfo.
Listing 3 shows a user-defined function to get the frequency of the CPU. It opens the /proc/cpuinfo file, searches for the "cpu MHz" string, and reads the CPU frequency. This function converts the read value to Hz and returns the same.
Listing 3. Linux implementation for getting clock frequency
/*
* Macro to compare keywords
* strcmp is called only when the first characters are the same
*/
#define WordMatch(a, b) ( (*(a) == *(b)) && (strcmp(a, b) == 0) )
int GetClockFreq(unsigned long *pulCpuFreq)
{
char* pcFilename = "/proc/cpuinfo";
char pcReadLine[BUFSIZE];
char pcKeyword[BUFSIZE];
char pcKeyword2[BUFSIZE];
int iDone = 0; /* Flag to determine end of loop */
*pulCpuFreq = 0;
memset(pcReadLine,0,BUFSIZE);
memset(pcKeyword,0,BUFSIZE);
memset(pcKeyword2,0,BUFSIZE);
/*
* Open the /proc/cpuinfo file
*/
fstream fpCpuInfo(pcFilename, ios::in);
if (fpCpuInfo)
{
/*
* Read a line into the buffer
*/
while ((fpCpuInfo.getline(pcReadLine, BUFSIZE)) && (iDone == 0))
{
/*
* Instantiate istrmInput to translate input line into
* a stream object
*/
istrstream istrmInput(pcReadLine);
/*
* Get first 2 word from the input line and build the keyword
*/
istrmInput >> pcKeyword;
istrmInput >> pcKeyword2;
strcat(pcKeyword, " ");
strcat(pcKeyword, pcKeyword2);
if (WordMatch(pcKeyword, "cpu MHz"))
{
/*
* Get the Mhz value from input line by skipping
* past the colon.
*/
istrmInput >> pcKeyword;
istrmInput >> pcKeyword;
/*
* Convert the char* to float and multiply by 1000000 to
* get the clock in Hz
*/
*pulCpuFreq = (unsigned long)(atof(pcKeyword) * 1000000);
iDone = 1;
}
} /* end of while */
fpCpuInfo.close();
}
return ((iDone)?0:-1);
}
|
Listing 4 illustrates the use of the DosTmrQueryTime and DosTmrQueryFreq calls.
Listing 4. OS/2 timer query example
void GetTimeStampPair( )
{
struct QWORD qwStartTime, qwStopTime;
double diff;
Unsigned long ulTmrFreq;
DosTmrQueryTime(&qwStartTime);
/* perform an activity */
diff = 0;
DosTmrQueryTime(&qwStopTime);
/* Calculate the difference between two times */
diff = qwStopTime.ulLo - qwStartTime.ulLo;
/* Query the Intel chip's resolution */
DosTmrQueryFreq(&ulTmrFreq);
printf ("Timer Frequency is %ld\n Hz", ulTmrFreq);
/* calculate the time take for the assignment operation */
/* diff time/frequency */
printf(" Time taken for the activity %ld\n", diff/ulTmrFreq);
} /* end GetTimeStampPair */
|
Listing 5 shows how to measure time between two operations by mapping
the OS/2 DosTmrQueryTime and DosTmrQueryFreq calls.
Listing 5. Linux timer query example
/*
* This function uses the user defined function GetClockFreq()
*/
#define NANOSLEEP 10000000 /* 10 ms */
#define MSLEEP NANOSLEEP/1000000
int main (void)
{
unsigned long t1, t2, jitter, freq;
double accum;
int ret;
struct sched_param sp;
struct timespec ts,rem;
/* Set the scheduling priority to the real time */
sp.sched_priority = sched_get_priority_max(SCHED_RR);
sched_setscheduler(getpid(), SCHED_RR, &sp);
mlockall(MCL_FUTURE|MCL_CURRENT);
rem.tv_sec = 0;
ret = GetClockFreq (&freq);
if (ret)
{
/* error condition */
return -1;
}
rem.tv_sec = 0;
rem.tv_nsec = NANOSLEEP;
t1 = get_cycles();
do {
ts.tv_sec = rem.tv_sec;
ts.tv_nsec = rem.tv_nsec;
rem.tv_nsec = 0;
ret = nanosleep(&ts, &rem);
} while (rem.tv_nsec != 0);
t2 = get_cycles();
jitter = t2 - t1;
/* How much time elapsed. Number of ticks
* divided by frequency of the clock
*/
accum = (double)jitter/freq;
return 0;
}
|
Dynamic link library (DLL) calls
Dynamic linking defers much of the linking process until a program starts running. It provides a variety of benefits that are hard to get otherwise: it permits a program to load and unload routines at runtime, a facility that is otherwise very difficult to provide.
In Linux, dynamic link libraries (DLL) are known as shared libraries
(.so). The system's dynamic loader looks for shared libraries in
system-specified directories (such as /lib, /usr/lib, /usr/X11/lib, and so on).
When you build a new shared library that is not part of the system, use
the LD_LIBRARY_PATH environment variable to
tell the dynamic loader to look in other directories. Supply the -ldl command-line option when
linking the modules that have dlopen, dlsym, and like calls.
Table 3. DLL calls mapping table
| OS/2 | Linux | Classification |
| DosLoadModule | dlopen | Mappable |
| DosQueryProcAddr | dlsym | Mappable |
| DosFreeModule | dlclose | Mappable |
In OS/2, you can use DosLoadModule() to
load a dynamic link library explicitly:
APIRET DosLoadModule(PSZ pszName, ULONG cbName, PSZ pszModname,
PHMODULE phmod);
pszModnameis a pointer to a variable that contains the dynamic link module name.phmodis a pointer to a variable in which the handle for the dynamic link module is returned.
In Linux, you use the dlopen() library function to load a dynamic library. The function returns a handle for the
dynamic link library:
void * dlopen(const char *pathname, int mode);
pathnametakes the name of the library to be loaded. If it is NULL, then the handle for the main program is returned.modecan be eitherRTLD_LAZY, meaning resolve undefined symbols as code from the dynamic library, orRTLD_NOW, meaning resolve all undefined symbols beforedlopenreturns, and fail if this cannot be done. Optionally, you can "or"RTLD_GLOBALwith a flag, in which case the external symbols defined in the library are made available to subsequently loaded libraries.
Getting references to DLL functions
In OS/2, DosQueryProcAddr() gets
the address of the specified procedure within a dynamic link module:
APIRET DosQueryProcAddr(HMODULE hmod, ULONG ordinal, PSZ pszName, PFN
ppfn);
hmodrefers to the module handle returned byDosLoadModule.pszNameis the name of the function.ppfnis the function pointer that is returned.
In Linux, dlsym() returns the address of a
symbol when a handle of a dynamic library returned by dlopen and the null terminated symbol name are
supplied as parameters:
void * dlsym(void *handle, char *symbol);
handleis the handle of the loaded library.symbolis the symbol name. If the symbol is not found,dlsymreturns NULL.
Note that C++ function names are mangled to support function
overloading, so the function may have a different name in the library. You can figure out the mangling scheme and search for the mangled symbol
instead. The compiler uses C-style linkage when an extern "C" qualifier is specified in the declaration.
In OS/2, DosFreeModule() frees
the reference to the dynamic link module for this process. If no process
uses the dynamic link module, the module is freed from system memory. The
module identified by the handle must have been loaded using DosLoadModule. If the handle is invalid, an error is
returned:
APIRET DosFreeModule (HMODULE hmod);
In Linux, dlclose() disassociates a shared
object previously opened by dlopen from the
current process. Once an object has been closed using dlclose, its symbols are no longer available to dlsym:
int dlclose(void *handle);
handlerefers to the handle returned bydlopen. If the referenced object is successfully closed,dlclosereturns 0. If the object could not be closed, or if the handle does not refer to an open object,dlclosereturns a non-zero value.
Note that in Linux, the library function dlerror returns a null-terminated character string
(with no trailing newline) that describes the last error that occurred
during dynamic linking processing:
const char *dlerror(void);
The code in Listing 6 loads the dynamic link module DISPLAY.DLL, gets a reference
to function draw(), and then unloads it. It does
not show error handling.
Listing 6. OS/2 example for loading DLLs
int main(VOID) {
PSZ ModuleName = "C:\\OS2\\DLL\\DISPLAY.DLL"; /* Name of module */
UCHAR LoadError[256] = ""; /* Area for Load failure information */
HMODULE ModuleHandle = NULLHANDLE; /* Module handle */
PFN ModuleAddr = 0; /* Pointer to a system function */
ULONG ModuleType = 0; /* Module type */
APIRET rc = NO_ERROR; /* Return code */
/* Load the DLL */
rc = DosLoadModule(LoadError, /* Failure information buffer */
sizeof(LoadError), /* Size of buffer */
ModuleName, /* Module to load */
&ModuleHandle); /* Module handle returned */
/* Get the handle to the function draw() */
rc = DosQueryProcAddr(ModuleHandle, /* Handle to module */
1L, /* No ProcName specified */
"draw", /* ProcName (not specified) */
&ModuleAddr); /* Address returned */
/* Unload the DLL */
rc = DosFreeModule(ModuleHandle);
}
|
The code in Listing 7 loads the shared library libdisplay.so, gets a reference
to function draw(), and then unloads it.
Listing 7. Linux example for loading shared libraries
void* handle, *handle2; /* Handle to the symbols */
/* Get the handle to the shared library. Passing 0 or NULL as
* first parameter to dlopen returns the handle to "main" program
*/
handle = dlopen("libdisplay.so", RTLD_LAZY);
if (handle != NULL)
{
/* Get the handle to the symbol "draw" */
handle2 = dlsym(handle, "draw");
if (handle2 != NULL)
{
/* use the function */
}
/* When finished, unload the shared library */
dlclose(handle);
}
|
This article, the third in a series, covered the mapping of OS/2 to Linux with respect to interval timers and shared libraries. Use this series as a reference when you undertake any migration activity involving OS/2 to Linux. With these tips and caveats, you can simplify your migration activity and arrive at a suitable migration design. Refer to the Linux man pages for more details on the Linux calls mentioned here.
Be sure to read the previous articles in this series, and do also send us news of your own migration worries, stories, triumphs, and questions.
- Be sure to read the first two installments in this series, "Migrate
your apps from OS/2 to Linux: Part 1. Threads, mutexes, and
semaphores" (developerWorks, February 2004), and "Migrate
your apps from OS/2 to Linux: Part 2. Memory management, IPC, and file
handling" (developerWorks, May 2004).
- The Design of
OS/2 by H.M. Deitel and M.S. Kogan (Addison-Wesley, 1992) can
still be found at used book sites; the ISBN is 0-201-54889-5.
- Don't forget to check the Linux "info" and man pages for specific
calls for more details on programming calls in Linux.
- C++ programmers can refer to "Comparing
IBM Open Collection Classes and STL Collection Classes"
(developerWorks, April 2003), which covers the mapping between IBM Open
Collection Classes and Standard Template Library (STL) Collection Classes.
- IBM's OS/2
Strategy for 2004 recommends a phased transition to the WebSphere software
platform.
- Most of the IBM eServer
servers now come bundled with Linux.
- IBM Redbooks offers a OS/2
Server Transition guide for OS/2 administrators who are planning a
transition to Windows or Linux.
- See Migrate / Port your application to Linux with IBM for additional information.
- "Porting
OS/2 applications to Linux (in C)" (developerWorks, March 2002)
covers issues encountered by the LAN Distributed Platform (LANDP) for
Linux team while porting LANDP from OS/2 to Linux.
- You can also use OS/2 and Linux together on the same machine. Check
out How to
use Linux and OS/2 Together for a list of resources from the Southern
California OS/2 User Group, and the SUSE Linux portal's OS/2 and
Linux with the OS/2 Boot Manager for easy directions on dual-booting.
-
Find more resources for Linux developers in the developerWorks Linux
section.
- Browse for books on these and other technical topics.
- Develop and test your Linux applications using the latest IBM tools and middleware with a developerWorks Subscription: you get IBM software from WebSphere®, DB2®, Lotus®, Rational®, and Tivoli®, and a license to use the software for 12 months, all for less money than you might think.
- Download no-charge trial versions of selected developerWorks Subscription products that run on Linux, including WebSphere Studio Site Developer, WebSphere SDK for Web services, WebSphere Application Server, DB2 Universal Database Personal Developers Edition, Tivoli Access Manager, and Lotus Domino Server, from the Speed-start your Linux app section of developerWorks. For an even speedier start, help yourself to a product-by-product collection of how-to articles and tech support.
Dinakar Guniguntala holds a B.Eng. degree in Computer Engineering from REC Surat. He has been employed with IBM Global Services, India, since February, 1998, where he works on operating system internals. He has worked on the OS/2 kernel, graphics engine, and filesytems, as well as on embedded Linux, the Linux kernel, and Linux thread libraries. He can be reached at dgunigun-at-in.ibm.com.
Sathyan Doraiswamy holds a B.Eng. degree in Electronics and Communications from University Visvesvaraya College of Engineering, Bangalore. He joined IBM India in June, 1997. He works for Engineering & Technology Services and specializes in firmware for embedded and real time systems. He has vast programming experience on Windows and Linux device drivers and on VxWorks. You can contact him at dsathyan-at-in.ibm.com.
Anand K. Santhanam has a B.Eng. in Computer Science from Madras University, India. He has been in IBM Global Services (Software Labs), India, since July, 1999. He is a member of the Linux Group at IBM, where he has worked with ARM-Linux, character/X-based device drivers, power management in embedded systems, PCI device drivers, and multithreaded programming in Linux. Other areas of interest are OS internals and networking. You can contact him at asanthan-at-in.ibm.com.
Srinivasan S. Muthuswamy has a B.Eng. in Computer Engineering from the Government College of Technology, Coimbatore, India. He has been in IBM Global Services, India since Aug 2000. He has worked on multithreaded applications in Linux. He has worked on Web applications using WSBCC/Java technologies/Websphere/MQSeries. He has also worked on Crystal Reports and Lotus Domino. You can contact him at smuthusw-at-in.ibm.com.
Rinson Antony has a Bachelor of Engineering degree in Computer Engineering from Bombay University, India. He has been in IBM Global Services, India since July 2000. He has worked on multithreaded applications in Linux and Web applications using Java technologies/Websphere/XML. Other areas of interest are PCI device drivers and networking. You can contact him at arinson-at-in.ibm.com.
Brahmaiah Vallabhaneni has a B.Eng. degree from BITS, Pilani, India. He has been in IBM Global Services, India, since August, 2002. He has worked on GNU C Compiler porting, character device drivers, power management in embedded systems, PCI device drivers, and multithreaded programming in Linux. Other areas of interest are Linux internals and networking. You can contact him at bvallabh-at-in.ibm.com.
Comments (Undergoing maintenance)





