Subject: Using threads and Xlib: a simple patch to linuxthreads!
From: Tristan Savatier <[email-masked]>
Date: Fri, 23 Jan 1998 14:48:54 -0800
Newsgroups: comp.os.linux.development.apps

r.columbia.edu!news.indiana.edu!news1.chicago.iagnet.net!iagnet.net!news.idt.net
!news-peer-east.sprintlink.net!news.sprintlink.net!Sprint!nntp.abs.net!out2.nntp
.cais.net!news2.cais.com!not-for-mail
Lines: 133
Message-ID: <[email-masked]>
NNTP-Posting-Host: port27.creative.net
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Mozilla 3.01 (X11; I; Linux 2.0.27 i586)
Xref: pubxfer.news.psi.net comp.os.linux.development.apps:49177
X-Cache: nntpcache 1.0.7.1 (see ftp://suburbia.net/pub/nntpcache)

I believe that this message is interesting for people
using posix threads on systems like Linux, specially in applications
using non-thread-safe libraries or libraries not compiled
with -D_REENTRANT in most distributions, like Xlib.

One of the most ennoying problem with using threads on systems
like Linux is that most libraries (including Xlib) are generally
not compiled to work with threads, which makes it difficult
to use threads in applications that interact with them.

I typical problem when using threads in an application using Xlib
is the famous:

XIO:  fatal IO error 0 (Unknown error) on X server ":0.0"

See details on http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html#H

It should be no problem as long as all the non-thread-safe
libraries are called from the main thread, provided that
the address of "errno" of the main thread is the
same as address of the "int errno" defined in libc.

When a program is compiled to use threads, the macro
_REENTRANT is defined, causing errno to become
a macro defined as (* __errno_location()), i.e. the address
of errno is returned by a routine, and is different
for each thread.

In case some routines (maybe part of a library) were compiled with
-D_REENTRANT (but are not explicitely using threads),
libc takes care of defining a dummy
__errno_location() routine that returns the address of
"int errno". Until then, all is fine...

But the problem start when linking with
-lpthread: libpthread redefines __errno_location() to return
an address different for each thread, unfortunately
always different from the address of "int errno",
even in the main thread! This causes havoc if the
main thread is using a mix of things compiled with
and without -D_REENTRANT, which is often the case
(because of libraries).

Because of that, the meer fact of adding -lpthead when linking
an application that uses Xlib (but does not use threads!) causes the
application to die with the famous:

XIO:  fatal IO error 0 (Unknown error) on X server ":0.0"

I found an easy way to solve this problem with the very small
change in the way __errno_location() is defined 
in the thread library.

I implemented this minuscule change
in linuxthread-0.71, and was able to run a large and complex
Xlib application while using threads (as long as all the
Xlib calls were made from the main threads), and I did
not have to recompile any other library!!!

Here is the patch:

==================== old version of errno.c (from linuxthreads-0.71):
#define _REENTRANT
#include <errno.h>
#include "pthread.h"
#include "internals.h"

int * __errno_location()
{
  pthread_descr self = thread_self();
  return &(self->p_errno);
}

int * __h_errno_location()
{
  pthread_descr self = thread_self();
  return &(self->p_h_errno);
}

==================== my patched version:
#include <errno.h>
#define _REENTRANT
#include "pthread.h"
#include "internals.h"

int * __errno_location()
{
  pthread_descr self = thread_self();
  if (self == __pthread_main_thread) return &errno;
  return &(self->p_errno);
}

int * __h_errno_location()
{
  pthread_descr self = thread_self();
  return &(self->p_h_errno);
}
=======================

explanation:

The patch guarantees that errno, even when
defined as the macro (* __errno_location()),
will correspond to the "int errno" declared in
libc, as long as we are in the main thread.

NOTE the important change in the order of the first 2 lines!
errno.h must be included BEFORE defining _REENTRANT,
to make sure that errno is defined as "extern int errno",
not as (* __errno_location()).

This patch allows using Xlib in a multithreaded program,
(or using threads in a program that uses Xlib)
with one restriction: all the Xlib calls have to be made
from the main thread.

I tested it sucessfully with a very complex X11 application (namely
the MpegTV Player, a real-time MPEG player).

I was to start a few other threads, without any problem, while the
main thread is using the Xlib library.

I believe this patch should be included in the
linuxthread distribution and in other thread packages.
In any case, it took 5 minutes
to patch the linuxthreads distribution, so anyone
interested can try it.

-- 
Regards, -- Tristan Savatier (President, MpegTV LLC)

MpegTV:   http://www.mpegtv.com