I need to develop a milter for Sendmail and have thought a long time about which language / framework I should use. Finally, I have decided to do it in plain C directly using the milter API.
I have studied the milter API documentation and think I have grasped the concepts. But there is one thing which worries me heavily. From this section:
A single filter process may handle any number of connections simultaneously. All filtering callbacks must therefore be reentrant, and use some appropriate external synchronization methods to access global data [...].
While I very well understand why the callbacks must be thread-safe, I cannot understand why they must be re-entrant. I cannot imagine that those callbacks could be called from an interrupt or a signal handler (perhaps except the abort callback, I'll have to re-read this).
The problem with the requirement to be re-entrant is that a re-entrant function must not call non-re-entrant code. Therefore, if the callbacks really had to be re-entrant, I couldn't use malloc()
and most other library functions in there; from man 3 malloc
:
To avoid corruption in multithreaded applications, mutexes are used internally to protect the memory-management data structures employed by these functions [...]
This for sure means that malloc()
is thread-safe, and it probably means that malloc()
is not re-entrant, and thus no function which uses it.
So I have got two questions:
1) Do the milter callbacks really need to be re-entrant, or is this actually a very odd wording for "need to be thread-safe" in the milter API documentation?
2) If they really need to be re-entrant, how can I circumvent the problems mentioned above? Due to the characteristics of the milter API, I can hardly imagine how to do something reasonable in the callbacks without using malloc()
and other non-re-entrant library functions.
In the context of the Milter-API (which also stresses that it's using posix threads, internally), a 'reentrant' function is defined as one that can safely executed from multiple threads, concurrently. That means without yielding a race condition.
This usage of the term 'reentrant' is consistent with other UNIX/Linux API documentation such as
strtok
:See also other
*_r()
functions such asctime_r()
,gmtime_r()
etc.