# Apache 2.0 Thread Safety Issues
When using any of the threaded mpms in Apache 2.0 it is important that every function called from Apache be thread safe. When linking in 3rd party extensions it can be difficult to determine whether the resulting server will be thread safe. Casual testing generally won't tell you this either as thread safety problems can lead to subtle race conditons that may only show up in certain conditions under heavy load.
## Global and static variables
When writing your module or when trying to determine if a module or 3rd party library is thread safe there are some common things to keep in mind.
First, you need to recognize that in a threaded model each individual thread has its own program counter, stack and registers. Local variables live on the stack, so those are fine. You need to watch out for any static or global variables. This doesn't mean that you are absolutely not allowed to use static or global variables. There are times when you actually want something to affect all threads, but generally you need to avoid using them if you want your code to be thread safe.
In the case where you have a global variable that needs to be global and accessed by all threads, be very careful when you update it. If, for example, it is an incrementing counter, you need to atomically increment it to avoid race conditions with other threads. You do this using a mutex (mutual exclusion). Lock the mutex, read the current value, increment it and write it back and then unlock the mutex. Any other thread that wants to modify the value has to first check the mutex and block until it is cleared.
If you are using [APR](http://apr.apache.org/), have a look at the `apr_atomic_*` functions and the `apr_thread_mutex_*` functions.
## errno
This is a common global variable that holds the error number of the last error that occurred. If one thread calls a low-level function that sets errno and then another thread checks it, we are bleeding error numbers from one thread into another. To solve this, make sure your module or library defines `_REENTRANT` or is compiled with `-D_REENTRANT`. This will make errno a per-thread variable and should hopefully be transparent to the code. It does this by doing something like this:
```
#define errno (*(__errno_location()))
```
which means that accessing errno will call `__errno_location()` which is provided by the libc. Setting `_REENTRANT` also forces redefinition of some other functions to their `*_r` equivalents and sometimes changes the common `getc`/`putc` macros into safer function calls. Check your libc documentation for specifics. Instead of, or in addition to `_REENTRANT` the symbols that may affect this are `_POSIX_C_SOURCE`, `_THREAD_SAFE`, `_SVID_SOURCE`, and `_BSD_SOURCE`.
## Common standard troublesome functions
Not only do things have to be thread safe, but they also have to be reentrant. `strtok()` is an obvious one. You call it the first time with your delimiter which it then remembers and on each subsequent call it returns the next token. Obviously if multiple threads are calling it you will have a problem. Most systems have a reentrant version of of the function called `strtok_r()` where you pass in an extra argument which contains an allocated `char *` which the function will use instead of its own static storage for maintaining the tokenizing state. If you are using [APR](http://apr.apache.org/) you can use `apr_strtok()`.
`crypt()` is another function that tends to not be reentrant, so if you run across calls to that function in a library, watch out. On some systems it is reentrant though, so it is not always a problem. If your system has `crypt_r()` chances are you should be using that, or if possible simply avoid the whole mess by using md5 instead.
## Common 3rd Party Libraries
The following is a list of common libraries that are used by 3rd party Apache modules. You can check to see if your module is using a potentially unsafe library by using tools such as `ldd(1)`和`nm(1)`. For [PHP](http://www.php.net/), for example, try this:
```
% 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)
```
In addition to these libraries you will need to have a look at any libraries linked statically into the module. You can use `nm(1)` to look for individual symbols in the module.
## Library List
Please drop a note to [dev@httpd.apache.org](http://httpd.apache.org/lists.html#http-dev) if you have additions or corrections to this list.
| Library | Version | Thread Safe? | Notes |
| --- | --- | --- | --- |
| [ASpell/PSpell](http://aspell.sourceforge.net/) | ? |
| [Berkeley DB](http://www.sleepycat.com/) | 3.x, 4.x | Yes | Be careful about sharing a connection across threads. |
| [bzip2](http://sources.redhat.com/bzip2/index.html) | Yes | Both low-level and high-level APIs are thread-safe. However, high-level API requires thread-safe access to errno. |
| [cdb](http://cr.yp.to/cdb.html) | ? |
| [C-Client](http://www.washington.edu/imap/) | Perhaps | c-client uses `strtok()`和`gethostbyname()` which are not thread-safe on most C library implementations. c-client's static data is meant to be shared across threads. If `strtok()`和`gethostbyname()` are thread-safe on your OS, c-client _may_ be thread-safe. |
| [cpdflib](http://www.fastio.com/) | ? |
| [libcrypt](http://www.ijg.org/files/) | ? |
| [Expat](http://expat.sourceforge.net/) | Yes | Need a separate parser instance per thread |
| [FreeTDS](http://www.freetds.org/) | ? |
| [FreeType](http://www.freetype.org/) | ? |
| [GD 1.8.x](http://www.boutell.com/gd/) | ? |
| [GD 2.0.x](http://www.boutell.com/gd/) | ? |
| [gdbm](http://www.gnu.org/software/gdbm/gdbm.html) | No | Errors returned via a static `gdbm_error` variable |
| [ImageMagick](http://www.imagemagick.org/) | 5.2.2 | Yes | ImageMagick docs claim it is thread safe since version 5.2.2 (see [Change log](http://www.cise.ufl.edu/depot/www/ImageMagick/www/Changelog.html)). |
| [Imlib2](http://www.enlightenment.org/pages/imlib2.html) | ? |
| [libjpeg](http://www.ijg.org/files/) | v6b | ? |
| [libmysqlclient](http://mysql.com) | Yes | Use mysqlclient_r library variant to ensure thread-safety. For more information, please read [http://www.mysql.com/doc/en/Threaded_clients.html](http://www.mysql.com/doc/en/Threaded_clients.html). |
| [Ming](http://www.opaque.net/ming/) | 0.2a | ? |
| [Net-SNMP](http://net-snmp.sourceforge.net/) | 5.0.x | ? |
| [OpenLDAP](http://www.openldap.org/) | 2.1.x | Yes | Use `ldap_r` library variant to ensure thread-safety. |
| [OpenSSL](http://www.openssl.org/) | 0.9.6g | Yes | Requires proper usage of `CRYPTO_num_locks`, `CRYPTO_set_locking_callback`, `CRYPTO_set_id_callback` |
| [liboci8 (Oracle 8+)](http://www.oracle.com/) | 8.x,9.x | ? |
| [pdflib](http://pdflib.com/) | 5.0.x | Yes | PDFLib docs claim it is thread safe; changes.txt indicates it has been partially thread-safe since V1.91: [http://www.pdflib.com/products/pdflib/index.html](http://www.pdflib.com/products/pdflib/index.html). |
| [libpng](http://www.libpng.org/pub/png/libpng.html) | 1.0.x | ? |
| [libpng](http://www.libpng.org/pub/png/libpng.html) | 1.2.x | ? |
| [libpq (PostgreSQL)](http://www.postgresql.org/idocs/index.php?libpq-threading.html) | 7.x | Yes | Don't share connections across threads and watch out for `crypt()` calls |
| [Sablotron](http://www.gingerall.com/charlie/ga/xml/p_sab.xml) | 0.95 | ? |
| [zlib](http://www.gzip.org/zlib/) | 1.1.4 | Yes | Relies upon thread-safe zalloc and zfree functions Default is to use libc's calloc/free which are thread-safe. |
- Apache HTTP Server Version 2.2 文档 [最后更新:2006年3月21日]
- 版本说明
- 从1.3升级到2.0
- 从2.0升级到2.2
- Apache 2.2 新特性概述
- Apache 2.0 新特性概述
- The Apache License, Version 2.0
- 参考手册
- 编译与安装
- 启动Apache
- 停止和重启
- 配置文件
- 配置段(容器)
- 缓冲指南
- 服务器全局配置
- 日志文件
- 从URL到文件系统的映射
- 安全方面的提示
- 动态共享对象(DSO)支持
- 内容协商
- 自定义错误响应
- 地址和端口的绑定(Binding)
- 多路处理模块
- Apache的环境变量
- Apache处理器的使用
- 过滤器(Filter)
- suEXEC支持
- 性能方面的提示
- URL重写指南
- Apache虚拟主机文档
- 基于主机名的虚拟主机
- 基于IP地址的虚拟主机
- 大批量虚拟主机的动态配置
- 虚拟主机示例
- 深入研究虚拟主机的匹配
- 文件描述符限制
- 关于DNS和Apache
- 常见问题
- 经常问到的问题
- Apache的SSL/TLS加密
- SSL/TLS高强度加密:绪论
- SSL/TLS高强度加密:兼容性
- SSL/TLS高强度加密:如何...?
- SSL/TLS Strong Encryption: FAQ
- 如何.../指南
- 认证、授权、访问控制
- CGI动态页面
- 服务器端包含入门
- .htaccess文件
- 用户网站目录
- 针对特定平台的说明
- 在Microsoft Windows中使用Apache
- 在Microsoft Windows上编译Apache
- Using Apache With Novell NetWare
- Running a High-Performance Web Server on HPUX
- The Apache EBCDIC Port
- 服务器和支持程序
- httpd - Apache超文本传输协议服务器
- ab - Apache HTTP服务器性能测试工具
- apachectl - Apache HTTP服务器控制接口
- apxs - Apache 扩展工具
- configure - 配置源代码树
- dbmmanage - 管理DBM格式的用户认证文件
- htcacheclean - 清理磁盘缓冲区
- htdbm - 操作DBM密码数据库
- htdigest - 管理用于摘要认证的用户文件
- httxt2dbm - 生成RewriteMap指令使用的dbm文件
- htpasswd - 管理用于基本认证的用户文件
- logresolve - 解析Apache日志中的IP地址为主机名
- rotatelogs - 滚动Apache日志的管道日志程序
- suexec - 在执行外部程序之前切换用户
- 其他程序
- 杂项文档
- 与Apache相关的标准
- Apache模块
- 描述模块的术语
- 描述指令的术语
- Apache核心(Core)特性
- Apache MPM 公共指令
- Apache MPM beos
- Apache MPM event
- Apache MPM netware
- Apache MPM os2
- Apache MPM prefork
- Apache MPM winnt
- Apache MPM worker
- Apache模块 mod_actions
- Apache模块 mod_alias
- Apache模块 mod_asis
- Apache模块 mod_auth_basic
- Apache模块 mod_auth_digest
- Apache模块 mod_authn_alias
- Apache模块 mod_authn_anon
- Apache模块 mod_authn_dbd
- Apache模块 mod_authn_dbm
- Apache模块 mod_authn_default
- Apache模块 mod_authn_file
- Apache模块 mod_authnz_ldap
- Apache模块 mod_authz_dbm
- Apache模块 mod_authz_default
- Apache模块 mod_authz_groupfile
- Apache模块 mod_authz_host
- Apache模块 mod_authz_owner
- Apache模块 mod_authz_user
- Apache模块 mod_autoindex
- Apache模块 mod_cache
- Apache模块 mod_cern_meta
- Apache模块 mod_cgi
- Apache模块 mod_cgid
- Apache模块 mod_charset_lite
- Apache模块 mod_dav
- Apache模块 mod_dav_fs
- Apache模块 mod_dav_lock
- Apache模块 mod_dbd
- Apache模块 mod_deflate
- Apache模块 mod_dir
- Apache模块 mod_disk_cache
- Apache模块 mod_dumpio
- Apache模块 mod_echo
- Apache模块 mod_env
- Apache模块 mod_example
- Apache模块 mod_expires
- Apache模块 mod_ext_filter
- Apache模块 mod_file_cache
- Apache模块 mod_filter
- Apache模块 mod_headers
- Apache模块 mod_ident
- Apache模块 mod_imagemap
- Apache模块 mod_include
- Apache模块 mod_info
- Apache模块 mod_isapi
- Apache模块 mod_ldap
- Apache模块 mod_log_config
- Apache模块 mod_log_forensic
- Apache模块 mod_logio
- Apache模块 mod_mem_cache
- Apache模块 mod_mime
- Apache模块 mod_mime_magic
- Apache模块 mod_negotiation
- Apache模块 mod_nw_ssl
- Apache模块 mod_proxy
- Apache模块 mod_proxy_ajp
- Apache模块 mod_proxy_balancer
- Apache模块 mod_proxy_connect
- Apache模块 mod_proxy_ftp
- Apache模块 mod_proxy_http
- Apache模块 mod_rewrite
- Apache模块 mod_setenvif
- Apache模块 mod_so
- Apache模块 mod_speling
- Apache模块 mod_ssl
- Apache模块 mod_status
- Apache模块 mod_suexec
- Apache模块 mod_unique_id
- Apache模块 mod_userdir
- Apache模块 mod_usertrack
- Apache模块 mod_version
- Apache模块 mod_vhost_alias
- Developer Documentation for Apache 2.0
- Apache 1.3 API notes
- Debugging Memory Allocation in APR
- Documenting Apache 2.0
- Apache 2.0 Hook Functions
- Converting Modules from Apache 1.3 to Apache 2.0
- Request Processing in Apache 2.0
- How filters work in Apache 2.0
- Apache 2.0 Thread Safety Issues
- 词汇和索引
- 词汇表
- 指令索引
- 指令速查
- 模块索引
- 站点导航