Skip to main content

Porting OS/2 applications to Linux (in C)

What are the key programming issues when porting from OS/2 to Linux?

Kevin Bowkett (kevin_bowkett@uk.ibm.com), IBM software engineer, IBM 
Kevin Bowkett is Software Engineer working within the LANDP development group and has a good foundation in Linux, Windows, and OS/2 operating systems. Over the last year Kevin has led the LANDP group to deliver LANDP for Linux to the market place. Kevin is also a IBM Certified Solutions Expert for DB2 Application Development. If you are embarking on a porting exercise from OS/2 to Linux and you have questions, then feel free to contact him at kevin_bowkett@uk.ibm.com.

Summary:  Look before you leap into Linux by discovering the pitfalls ahead of time. The LANDP team guides you through the differences between OS/2 and Linux so that your porting project can go more smoothly.

Date:  10 Feb 2005
Level:  Introductory
Activity:  259 views

Introduction

This paper is a summary of problems encountered by the LAN Distributed Platform (LANDP) for Linux team whilst porting LANDP from OS/2 to Linux. This paper should be useful to other teams that are porting OS/2 applications to Linux.

When the decision was made to port the OS/2 version of LANDP to Linux, the team already had experience in porting from OS/2 to NT. The NT port contains two main approaches:

  • A mapping layer
  • An abstraction layer

The abstraction layer is a little less complex than the mapping layer. The abstraction layer is a thin layer of software abstraction that abstracts function names, parameters, and their return codes, whereas the mapping layer attempts to mimic the behaviour of OS/2.

For the Linux port, we began by developing an abstraction layer. It became apparent early on that the layer would require a lot of additional function. The abstraction layer evolved into a mapping layer. The mapping layer is a shared object that has an interface exactly like the OS/2 interface and tries to mimic the exact behaviour of OS/2. However, LANDP requires only a subset of the OS/2 functionality and therefore the mapping layer is not a full implementation.

The following sections outline most of the areas where the two operating systems are functionally different and provide some suggestions for handling the differences.


Obvious differences

System calls are the most obvious difference between OS/2 and Linux. Some calls can easily be mapped, such as DosOpen, and others cannot, such as DosCreateQueue. In addition to the system calls, the return values and their meanings are different. Again, some return values can be exactly matched, like File not Found, but other return values require approximations.

Types are another area where differences occur. The differences are brought about because OS/2 renames C types and uses structures for function parameters. For example, on OS/2 the type UINT is defined as an unsigned integer. We had to redefine most of these types for the Linux environment.


Operational differences

Even more important than porting the system calls and redefining the types, the big difference is the behaviour of the concepts. Most operating systems have the same concepts, memory, files, inter-process communication (IPC), and so on. OS/2 and NT have very similar concepts and their differences are not extensive (except for shared memory). Linux and OS/2, however, show many conceptual differences. The following subsections outline these differences and offer some solutions for dealing with them.

Threads

A thread in the Linux environment is a special type of process. Therefore, for every thread you use, a new process is created. Also, threads are implemented by the use of the clone function or by a separate library called pthreads. Other forms of threads exist, but pthreads are a POSIX defined standard.

Linux is not as thread safe as other operating systems because threads are a relatively new concept to this operating system. Therefore, some standard libraries are not really thread safe. In addition, threads affect the behaviours of signals. The specific thread that will receive a signal sent to a process is not known. Note that pthreads have their own away of passing signals between each thread within a process.

The use of getpid and getppid are affected. For instance, a thread that calls getpid will have its process ID returned (not the process ID of the application) because a thread is implemented as a process.

Memory

The use of process memory in Linux is very similar to that in other operating systems, but the mechanism to share memory between processes is different. Linux provides a set of APIs based on the System V IPC mechanism. Shared memory is handled within this set of APIs. The shared memory mechanism defines limits for the number of segments a process can have and the number of segments for the entire system. Unfortunately, this limit restricts the number of shared memory segments an application can use.

For instance, if an OS/2 application creates 500 shared memory areas, you cannot use a direct mapping to the System V shared memory API. Although you can re-compile the kernel and set new levels, you must consider whether this change is acceptable for your customers.

You can allocate a huge shared memory segment and then allocate smaller chunks from this segment. However, there is no boundary checking. Without boundary checking, applications can damage segments allocated to other processes.

Another way to implement a behaviour similar to OS/2 that provides some boundary checking is to use file mapping. File mapping maps a file into the memory space of a process in order to allow access to the file as though it were memory. The mapping is not necessarily a whole file to memory, but it can be part of a file to a memory area.

Another difference in the shared memory mechanism is that Linux does not guarantee that the same memory address will be used when a segment is loaded into a process. On OS/2, you can allocate a piece of memory and pass that same memory to another process. The memory is located at the same address in each process. This is not necessarily the case on Linux. Also, in order to access a shared memory segment that another process has created, you need to know its ID. The ID is a unique number that can be calculated by using a name (if the name exists as a file). OS/2 provides several systems calls to enable processes to give and get access to shared memory segments based on names or memory addresses.

Queues

An OS/2 queue is a mechanism that allows a process to pass a memory pointer to another process. The passing process must give the receiving process access to the memory segment by means of DosGiveSharedMemory and then pass the memory location within the segment to the receiving process. As the mechanism name implies, the queue can hold a number of these memory locations whilst waiting for another process to read them. Linux does not have this concept.

Among the possible solutions, one is to use a System V shared memory segment. The problem with the System V shared memory segment is the restrictions on the number of segments allowed.

An alternative is to use file mapping and to use control structures that set the order of the elements (memory locations) and the access rights to the files.

Semaphores

OS/2 provides three main types of semaphores: events, mutexes, and multiple waits. Linux provides a semaphore mechanism based on the System V IPC and supports semaphores as part of the pthread library. An OS/2 semaphore is a single entity that provides you with a well-defined behaviour. However, the System V semaphores are defined in sets, which are configurable. Each set can have up to 250 semaphores (2.4 kernel) without recompiling the kernel. The system can have only a certain number of semaphore sets within the system (this number can be changed with a kernel recompile).

System V semaphores are basically counting variables, which you can increment or decrement, and this provides enough functionality for you to imitate the behaviour for event and mutex semaphores. The only problem is performing timed waits. On Linux, you can only try/wait or wait. No timeout is allowed. To mimic a timeout, you need to build some timing mechanism that can send a signal to interrupt the thread that is waiting for an event.

Multiple wait semaphores are a collection of defined semaphores that can be waited on as a group. The System V mechanism utilitises groups and can wait for a number of operations relating to the same set. However, unless the application has carefully planned its usage of semaphores, such that all the semaphores within a multiple wait come from the same semaphore set, then you will not get the desired result. We implemented a mechanism that enables a thread to wait on each semaphore within the set to simulate this behaviour.

The pthread library provides semaphores and mutexes (and condition variables) that can mimic OS/2 behaviour reasonably well. However, there is a drawback. Note that pthread semaphores and mutexes are not shareable. In other words, they are only guaranteed within that process. If your application uses only private semaphores or if no other process needs access to its semaphores, then using the pthread mutexes and semaphores is probably the best plan. However, if your application shares these IPC mechanisms, then you need to implement them using the System V mechanism, shared memory and threads.

Signals

On OS/2, exceptions are thrown to indicate certain erroneous conditions. On Linux, these are called signals. Like exceptions, signals can be caught with the exception of SIGKILL and SIGSTOP. On OS/2, you can define a list of functions that need to be executed upon receipt of an exception. An application can define more than one exception handler on OS/2. On Linux, you can define only one because the functions are overlaid.

Pipes

On OS/2, pipes are bi-directional, whereas a pipe on Linux is uni-directional. To mimic the behaviour of an OS/2 pipe, you need to create two pipes indexed by a single file handle.

Shared objects

Linux shared objects are very similar to DLLs, but a few pitfalls require caution. An application can overwrite a function in a shared object. If a shared object has the function print_hello and the application has a function called print_hello, then whenever the application calls print_hello, the application's version is used. This may not sound like a problem until you have a function in the shared object called, for example, so_print that calls print_hello. The print_hello that is used in this case is the one defined in the application.

Perceived standard function

You should exercise caution in making assumptions about the standard C functions. For example, kbhit and strupr are not standard functions. Even though they may be part of a C standard library for one compiler, it is not safe to assume that these and other functions exist on all platforms.


Wrap-up

The preceding differences do not comprise a definitive list by any means. Such a list would contain enough information for a whole book. However, the differences should give you a head start in finding the areas you need to address when porting an application to Linux from OS/2.

The LANDP for Linux team designed a mapping layer to aid our port from OS/2 to Linux. The mapping layer is a shared object that is used to port the individual LANDP servers from OS/2. Perhaps the mapping layer will provide a starting place for other projects, perhaps not.


Resources

About the author

Kevin Bowkett is Software Engineer working within the LANDP development group and has a good foundation in Linux, Windows, and OS/2 operating systems. Over the last year Kevin has led the LANDP group to deliver LANDP for Linux to the market place. Kevin is also a IBM Certified Solutions Expert for DB2 Application Development. If you are embarking on a porting exercise from OS/2 to Linux and you have questions, then feel free to contact him at kevin_bowkett@uk.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=12997
ArticleTitle=Porting OS/2 applications to Linux (in C)
publish-date=02102005
author1-email=kevin_bowkett@uk.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers