Title: Thread-Sicherheit unter Apache 2.0
Dokumentation für Entwickler Wird eines der Threading verwendenden MPMs unter Apache 2.0 benutzt, dann ist es wichtig, dass jede vom Apache aufgerufene Funktion Thread-sicher ist. Beim Einbinden von Erweiterungen anderer Hersteller kann es schwierig werden, festzustellen, ob der Server am Ende Thread-sicher ist. Ein oberflächlicher Test gibt darüber keinen Aufschluss, da Probleme der Thread-Sicherheit zu subtilen Konkurrenzverhältnissen führen können, die nur bei sehr starker Serverauslastung erkennbar sind.
Globale und statische Variablen Wenn Sie Ihre Module programmieren und dabei feststellen möchten, ob ein Modul oder eine Bibliothek eines anderen Herstellers Thread-sicher ist, müssen Sie einige allgemeine Dinge beachten.
Sie müssen sich zuerst klar machen, dass in einem Thread-Modell jeder einzelne Thread seinen eigenen Programmzähler, Stack sowie eigene Register hat. Lokale Variablen befinden sich im Stack und breiten keine Probleme. Aufpassen müssen Sie bei statischen und globalen Variablen. Prinzipiell ist es nicht unzulässig, statische oder globale Variablen zu benutzen. Manchmal sind tatsächlich alle Threads betroffen, aber im Allgemeinen müssen sie vermieden werden, wenn der Code Thread-sicher sein soll.
In einer Situation, in der eine Variable global und für alle Threads zugänglich sein muss, sollten Sie vorsichtig sein, wenn Sie sie aktualisieren. Handelt es sich beispielsweise um einen Zähler, der erhöht wird, dann müssen Sie ihn abgekoppelt erhöhen, um konkurrierende Zugriffe durch andere Threads zu vermeiden. Benutzen Sie hierfür einen Mutex (gegenseitiger Ausschluss). Blockieren Sie den Mutex, lesen Sie den aktuellen Wert, erhöhen Sie ihn, schreiben Sie ihn zurück und heben Sie anschließend die Blockade des Mutex auf. Jeder andere Thread, der den Wert verändern möchte, muss zuerst den Mutex überprüfen und ist bis zu dessen Freigabe blockiert.
Wenn Sie das APR verwenden, dann achten Sie auf die Funktionen
apr_atomic_*undapr_thread_mutex_*.errno Diese allgemein gebräuchliche globale Variable speichert die Fehlernummer des zuletzt aufgetretenen Fehlers. Ruft ein Thread eine maschinenorientierte Funktion auf, die
errnosetzt und die Variable wird anschließend von einem anderen Thread überprüft, dann gehen Fehlernummern von einem Thread an den anderen über. Um dieses Problem zu lösen, müssen Sie sicherstellen, dass Modul oder Bibliothek_REENTRANTdefinieren oder mit-D_REENTRANTkompiliert werden. Dadurch wirderrnozu eine Thread-bezogenen Variablen und sollte für den Code transparent sein. Das kann ungefähr wie folgt geschehen:#define errno (*(__errno_location())) Beim Zugriff auf
errnowird die Funktion__errno_location()aus der Bibliotheklibcaufgerufen. Wird_REENTRANTgesetzt, müssen auch einige andere Funktionen in ihre*_r-Äquivalente umdefiniert werden; manchmal sind auch Änderungen der allgemeinen Makrosgusw/putcin sicherere Funktionsaufrufe erforderlich. Überprüfen Sie Dokumentation Ihrelibc-Bibliothek bezüglich der Einzelheiten. Anstatt oder zusätzlich zu_REENTRANTbewirken dies auch die Symbole_POSIX_C_SOURCE,_THREAD_SAFE,_SVID_SOURCEund_BSD_SOURCE.Problematische Standardfunktionen Funktionen müssen nicht nur Thread-sicher sondern auch ablaufvariant sein. Die Funktion
strtok()ist ein Beispiel dafür. Sie können sie zum ersten Mal mit dem Begrenzer aufrufen, den sich die Funktion merkt und die bei jedem späteren Aufruf das nächste Element zurückgibt. Wird sie von mehreren Threads aufgerufen, dann führt das eindeutig zu Problemen. Die meisten Systeme verfügen über eine ablaufvariante Version der Funktion mit dem Namenstrtok_r(), der ein zusätzliches allokierteschar *-Argument übergeben wird, welches die Funktion an Stelle des eigenen statischen Speichers für die Statusüberwachung verwendet. Wenn Sie das APR verwenden, können Sieapr_strtok()benutzen.
crypt()ist eine weitere Funktion, die nicht unbedingt ablaufvariant ist, so dass bei Aufrufen dieser Funktion aus einer Bibliothek Vorsicht geboten ist. Bei einigen Systemen ist sie ablaufvariant, so dass sie nicht immer ein Problem darstellt. Verfügt Ihr System übercrypt_r(), dann sollten Sie diese Funktion benutzen oder gegebenenfalls den Aufruf mit md5 ganz umgehen.Verbreitete Bibliotheken anderer Hersteller Die folgende Liste führt allgemein verbreitete Bibliotheken anderer Hersteller von Apache-Modulen auf. Anhand dieser Liste können Sie überprüfen, ob Ihr Modul eine möglicherweise unsichere Bibliothek mit Funktionen wie
ldd(1)undnm(1)benutzt. Für PHP können Sie beispielsweise folgendes ausprobieren:% ldd libphp4.so
libsablot.so.0 => /usr/local/lib/libsablot.so.0 (0x401f6000)
libexpat.so.0 => /usr/lib/libexpat.so.0 (0x402da000)
libsnmp.so.0 => /usr/lib/libsnmp.so.0 (0x402f9000)
libpdf.so.1 => /usr/local/lib/libpdf.so.1 (0x40353000)
libz.so.1 => /usr/lib/libz.so.1 (0x403e2000)
libpng.so.2 => /usr/lib/libpng.so.2 (0x403f0000)
libmysqlclient.so.11 => /usr/lib/libmysqlclient.so.11 (0x40411000)
libming.so => /usr/lib/libming.so (0x40449000)
libm.so.6 => /lib/libm.so.6 (0x40487000)
libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x404a8000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x404e7000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x40505000)
libssl.so.2 => /lib/libssl.so.2 (0x40532000)
libcrypto.so.2 => /lib/libcrypto.so.2 (0x40560000)
libresolv.so.2 => /lib/libresolv.so.2 (0x40624000)
libdl.so.2 => /lib/libdl.so.2 (0x40634000)
libnsl.so.1 => /lib/libnsl.so.1 (0x40637000)
libc.so.6 => /lib/libc.so.6 (0x4064b000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)Neben diesen Bibliotheken müssen Sie auch alle statisch in das Modul eingebundenen Bibliotheken beachten. Mit
nm(1)können Sie nach einzelnen Symbolen im Modul suchen.Liste der Bibliotheken Bitte senden Sie eine Nachricht an [email protected], falls Ergänzungen oder Korrekturen an dieser Liste erforderlich sind.
Bibliothek Version Thread-sicher? Anmerkungen ASpell/PSpell ? Berkeley DB 3.x, 4.x Ja Seien Sie vorsichtig bei der gemeinsamen Nutzung einer Verbindung durch Threads. bzip2 Ja APIs auf höherer und unterer Ebene sind Thread-sicher. Auf höherer Ebene wird aber Thread-sicherer Zugriff auf errnobenötigt.cdb ? C-Client Vielleicht C-Client benutzt die Funktionen strtok()undgethostbyname(), die bei den meisten Implementierungen von C-Bibliotheken nicht Thread-sicher sind. Die statischen Daten von C-Client sollen von den Threads gemeinsam benutzt werden. Wennstrtok()undgethostbyname()unter Ihrem Betriebssystem Thread-sicher sind, ist C-Client vielleicht Thread-sicher.cpdflib ? libcrypt ? Expat Ja Benötigt eine eigene Parser-Instanz pro Thread. FreeTDS ? FreeType ? GD 1.8.x ? GD 2.0.x ? gdbm Nein Fehlerrückgabe über eine statische gdbm_error-VariableImageMagick 5.2.2 Ja Die ImageMagick-Dokumentationen behaupten, es sei seit Version 5.2.2 Thread-sicher (siehe Change log).Imlib2 ? libjpeg v6b ? libmysqlclient Ja Benutzen Sie die Variante mysqlclient_rder Bibliothek, um Thread-Sicherheit zu gewährleisten. Weiter Informationen finden Sie unter http://www.mysql.com/doc/en/Threaded_clients.html.Ming 0.2a ? Net-SNMP 5.0.x ? OpenLDAP 2.1.x Ja Benutzen Sie die Variante ldap_rder Bibliothek, um Thread-Sicherheit zu gewährleisten.OpenSSL 0.9.6g Ja Erfordert eine saubere Verwendung von CRYPTO_num_locks,CRYPTO_set_locking_callbackundCRYPTO_set_id_callbackliboci8 (Oracle 8+) 8.x,9.x ? pdflib 5.0.x Ja Die PDFLib-Dokumentationen behaupten, die Bibliothek sei Thread-sicher. In der Dateichanges.txtsteht, sie sei seit Version 1.91 partiell Thread-sicher: http://www.pdflib.com/products/pdflib/index.html.libpng 1.0.x ? libpng 1.2.x ? libpq (PostgreSQL) 7.x Ja Benutzen Sie keine Verbindungen gemeinsam mit mehreren Threads und achten Sie auf crypt()-Aufrufe.Sablotron 0.95 ? zlib 1.1.4 Ja Basiert auf den Thread-sicheren Funktionen zallocundzfree. Standardmäßig werden die Funktionencallocundfreebenutzt, die Thread-sicher sind.--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
