.. highlight:: none


.. index::
   pair: threads; testing

.. _design-testthr:


Multi-threaded testing
======================

.. mps:prefix:: design.mps.testthr


Introduction
------------

:mps:tag:`intro` This is the design of the multi-threaded testing module
in the Memory Pool System.

:mps:tag:`readership` Any MPS developer.

:mps:tag:`overview` The MPS is designed to work in a multi-threaded
environment (see design.mps.thread-safety_) and this needs to be
tested on all supported platforms. The multi-threaded testing module
provides an interface for creating and joining threads, so that
multi-threaded test cases are portable to all platforms on which the
MPS runs.

.. _design.mps.thread-safety: thread-safety.html


Requirements
------------

:mps:tag:`req.create` The module must provide an interface for creating
threads and running code in them. (Because there is no such interface
in the Standard C Library.)

:mps:tag:`req.join` The module must provide an interface for joining a
running thread: that is, waiting for the thread to finish and
collecting a result. (Because we want to be able to test that the MPS
behaves correctly when interacting with a finished thread.)

:mps:tag:`req.portable` The module must be easily portable to all the
platforms on which the MPS runs.

:mps:tag:`req.usable` The module must be simple to use, not requiring
elaborate setup or tear-down or error handling. (Because we want test
cases to be easy to write.)


Implementation
--------------

:mps:tag:`impl.posix` To meet :mps:ref:`.req.portable` and :mps:ref:`.req.usable`, the
module presents an interface that is essentially identical to the
POSIX Threads interface [pthreads]_, except for the names. On POSIX
platforms the implementation is trivial; on Windows it is
necessary to translate the concepts back and forth.

:mps:tag:`impl.storage` To meet :mps:ref:`.req.usable`, the module defines the
``testthr_t`` type in the header ``testthr.h`` (even though this
requires an ``#if``), so that test cases can easily declare variables
and allocate storage for thread identifiers.

:mps:tag:`impl.error` To meet :mps:ref:`.req.usable`, the module does not propagate
error codes, but calls :c:func:`error()` from the test library if anything
goes wrong. There is thus no need for the test cases to check result
codes.


Interface
---------

.. c:type:: testthr_t

The type of thread identifiers.

.. c:type:: void *(*testthr_routine_t)(void *)

The type of a function that can be called when a thread is created.

.. c:function:: void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg)

Create a thread. Store the identifier of the newly created thread in
``*thread_o``, and call :c:func:`start()`, passing ``arg`` as the single
parameter.

.. c:function:: void testthr_join(testthr_t *thread, void **result_o)

Wait for a thread to complete. Suspend execution of the calling thread
until the target thread terminates (if necessary), and if ``result_o``
is non-NULL, update ``*result_o`` with the return value of the
thread's :c:func:`start()` function.


References
----------

.. [pthreads]
   The Open Group;
   "The Single UNIX Specification, Version 2---Threads";
   <https://pubs.opengroup.org/onlinepubs/7990989775/xsh/threads.html>