Skip to content

Commit

Permalink
PERL_SET_CONTEXT(t) needs to set PL_current_context from C++ too
Browse files Browse the repository at this point in the history
We want to use C11 thread local storage where possible, as its read overhead
is lower. However C++ uses incompatible syntax for TLS, so we have to hide
the variable from C++ extensions, and have the read code "fall back" to the
pthread_getspecific() approach.

However, C++ extensions also need to be able to call PERL_SET_CONTEXT(t) and
have everything still work the same as C extensions. Hence they *also* need
to set PL_current_context - a variable that has to be hidden from them.
Hence change the version of the PERL_SET_CONTEXT macro used by C++
extensions from inline code to a call to Perl_set_context(), and have that
set PL_current_context (when used).

Technically this commit also fixes a bug in that Perl_set_context() is API
and should have been setting PL_current_context since that variable was
first introduced. In practice, likely nothing uses this API, as there is no
code on CPAN that calls it, and the macro PERL_SET_CONTEXT() is much more
prominent.
  • Loading branch information
nwc10 committed Jan 8, 2022
1 parent 7b21363 commit f140784
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 10 deletions.
18 changes: 10 additions & 8 deletions thread.h
Expand Up @@ -387,7 +387,9 @@ extern PERL_THREAD_LOCAL void *PL_current_context;

# define PERL_GET_CONTEXT PL_current_context

/* Set our thread-specific value anyway, in case code is reading it directly. */
/* We must also call pthread_setspecific() always, as C++ code has to read it
* with pthreads (the #else side just below) */

# define PERL_SET_CONTEXT(t) \
STMT_START { \
int _eC_; \
Expand All @@ -403,14 +405,14 @@ extern PERL_THREAD_LOCAL void *PL_current_context;
# define PERL_GET_CONTEXT PTHREAD_GETSPECIFIC(PL_thr_key)
# endif

/* For C++ extensions built on a system where the C compiler provides thread
* local storage that call PERL_SET_CONTEXT() also need to set
* PL_current_context, so need to call into C code to do this.
* To avoid exploding code complexity, do this also on C platforms that don't
* support thread local storage. PERL_SET_CONTEXT is not called that often. */

# ifndef PERL_SET_CONTEXT
# define PERL_SET_CONTEXT(t) \
STMT_START { \
int _eC_; \
if ((_eC_ = pthread_setspecific(PL_thr_key, (void *)(t)))) \
Perl_croak_nocontext("panic: pthread_setspecific (%d) [%s:%d]", \
_eC_, __FILE__, __LINE__); \
} STMT_END
# define PERL_SET_CONTEXT(t) Perl_set_context((void*)t)
# endif /* PERL_SET_CONTEXT */
#endif /* PERL_THREAD_LOCAL */

Expand Down
9 changes: 7 additions & 2 deletions util.c
Expand Up @@ -3762,13 +3762,18 @@ Perl_get_context(void)
void
Perl_set_context(void *t)
{
#if defined(USE_ITHREADS)
#endif
PERL_ARGS_ASSERT_SET_CONTEXT;
#if defined(USE_ITHREADS)
# ifdef PERL_USE_THREAD_LOCAL
PL_current_context = t;
# endif
# ifdef I_MACH_CTHREADS
cthread_set_data(cthread_self(), t);
# else
/* We set thread-specific value always, as C++ code has to read it with
* pthreads, beacuse the declaration syntax for thread local storage for C11
* is incompatible with C++, meaning that we can't expose the thread local
* variable to C++ code. */
{
const int error = pthread_setspecific(PL_thr_key, t);
if (error)
Expand Down

0 comments on commit f140784

Please sign in to comment.