Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions cppad_lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ print_variable(soversion)
#
# BEGIN_SORT_THIS_LINE_PLUS_2
SET(source_list
cpp_graph_op.cpp
cppad_colpack.cpp
csrc_writer.cpp
json_lexer.cpp
json_parser.cpp
json_writer.cpp
link_dll_lib.cpp
temp_file.cpp
cpp_graph_op.cpp
cppad_colpack.cpp
csrc_writer.cpp
json_lexer.cpp
json_parser.cpp
json_writer.cpp
link_dll_lib.cpp
tape_storage.cpp
temp_file.cpp
thread_alloc_storage.cpp
)
# END_SORT_THIS_LINE_MINUS_2
IF( cppad_has_cppadcg )
Expand Down
32 changes: 32 additions & 0 deletions cppad_lib/tape_storage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-25 Bradley M. Bell
// ----------------------------------------------------------------------------
# include <cppad/cppad.hpp>

namespace CppAD { // BEGIN_CPPAD_NAMESPACE

/*!
Storage for the tape identifier table.

This non-template function provides a single definition point for the
per-thread tape ID storage, avoiding duplicate function-local statics
when CppAD templates are instantiated across multiple shared libraries.
*/
tape_id_t* tape_storage_id_ptr(size_t thread)
{ static tape_id_t table[CPPAD_MAX_NUM_THREADS] = {};
return table + thread;
}

/*!
Storage for the tape handle table.

Uses void* to avoid depending on the template parameter Base.
The caller (tape_link.hpp) casts back to local::ADTape<Base>**.
*/
void** tape_storage_handle(size_t thread)
{ static void* table[CPPAD_MAX_NUM_THREADS] = {};
return table + thread;
}

} // END_CPPAD_NAMESPACE
124 changes: 124 additions & 0 deletions cppad_lib/thread_alloc_storage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-25 Bradley M. Bell
// ----------------------------------------------------------------------------
// Definitions of thread_alloc static member functions with function-local
// statics. Moved from the header to avoid duplicate statics when CppAD
// templates are instantiated across multiple shared libraries (DLLs).
//
// Note: we include configure.hpp directly (not cppad.hpp) because
// thread_alloc.hpp #undefs some macros we need at end-of-file.
# include <cppad/configure.hpp>
# include <cppad/utility/thread_alloc.hpp>

namespace CppAD { // BEGIN_CPPAD_NAMESPACE

// ---------------------------------------------------------------------------
// set_get_hold_memory
// ---------------------------------------------------------------------------
bool thread_alloc::set_get_hold_memory(bool set, bool new_value)
{ static bool value = false;
if( set )
value = new_value;
return value;
}

// ---------------------------------------------------------------------------
// thread_info
// ---------------------------------------------------------------------------
thread_alloc::thread_alloc_info* thread_alloc::thread_info(
size_t thread ,
bool clear )
{ static thread_alloc_info* all_info[CPPAD_MAX_NUM_THREADS] = {};
static thread_alloc_info zero_info;

CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;

CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS );

thread_alloc_info* info = all_info[thread];
if( clear )
{ if( info != nullptr )
{
# ifndef NDEBUG
CPPAD_ASSERT_UNKNOWN(
info->count_inuse_ == 0 &&
info->count_available_ == 0
);
// Use sizeof to determine array length (macro CPPAD_MAX_NUM_CAPACITY
// is #undef'd at end of thread_alloc.hpp)
for(size_t c = 0; c < sizeof(info->root_inuse_) / sizeof(info->root_inuse_[0]); c++)
{ CPPAD_ASSERT_UNKNOWN(
info->root_inuse_[c].next_ == nullptr &&
info->root_available_[c].next_ == nullptr
);
}
# endif
if( thread != 0 )
::operator delete( reinterpret_cast<void*>(info) );
info = nullptr;
all_info[thread] = info;
}
}
else if( info == nullptr )
{ if( thread == 0 )
info = &zero_info;
else
{ size_t size = sizeof(thread_alloc_info);
void* v_ptr = ::operator new(size);
info = reinterpret_cast<thread_alloc_info*>(v_ptr);
}
all_info[thread] = info;

// initialize the information record
for(size_t c = 0; c < sizeof(info->root_inuse_) / sizeof(info->root_inuse_[0]); c++)
{ info->root_inuse_[c].next_ = nullptr;
info->root_available_[c].next_ = nullptr;
}
info->count_inuse_ = 0;
info->count_available_ = 0;
}
return info;
}

// ---------------------------------------------------------------------------
// set_get_num_threads
// ---------------------------------------------------------------------------
size_t thread_alloc::set_get_num_threads(size_t number_new)
{ static size_t number_user = 1;

CPPAD_ASSERT_UNKNOWN( number_new <= CPPAD_MAX_NUM_THREADS );
CPPAD_ASSERT_UNKNOWN( ! in_parallel() || (number_new == 0) );

// case where we are changing the number of threads
if( number_new != 0 )
number_user = number_new;

return number_user;
}

// ---------------------------------------------------------------------------
// set_get_thread_num
// ---------------------------------------------------------------------------
size_t thread_alloc::set_get_thread_num(
size_t (*thread_num_new)(void) ,
bool set )
{ static size_t (*thread_num_user)(void) = nullptr;

if( set )
{ thread_num_user = thread_num_new;
return 0;
}

if( thread_num_user == nullptr )
return 0;

size_t thread = thread_num_user();
CPPAD_ASSERT_KNOWN(
thread < set_get_num_threads(0) ,
"parallel_setup: thread_num() >= num_threads"
);
return thread;
}

} // END_CPPAD_NAMESPACE
28 changes: 16 additions & 12 deletions include/cppad/core/tape_link.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ The routines that connect the AD<Base> class to the corresponding tapes
(one for each thread).
*/

// Non-template storage functions — defined in cppad_lib/tape_storage.cpp
// to avoid duplicate function-local statics across shared-library boundaries.
// Windows export is handled by WINDOWS_EXPORT_ALL_SYMBOLS on cppad_lib.
tape_id_t* tape_storage_id_ptr(size_t thread);
void** tape_storage_handle(size_t thread);

/*!
Pointer to the tape identifier for this AD<Base> class and the specific thread.

Expand All @@ -38,12 +44,11 @@ is a pointer to the tape identifier for this thread and AD<Base> class.
*/
template <class Base>
tape_id_t* AD<Base>::tape_id_ptr(size_t thread)
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
static tape_id_t tape_id_table[CPPAD_MAX_NUM_THREADS];
CPPAD_ASSERT_UNKNOWN(
(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num()
);
return tape_id_table + thread;
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
CPPAD_ASSERT_UNKNOWN(
(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num()
);
return tape_storage_id_ptr(thread);
}

/*!
Expand All @@ -64,12 +69,11 @@ is a handle for the tape for this AD<Base> class and the specified thread.
*/
template <class Base>
local::ADTape<Base>** AD<Base>::tape_handle(size_t thread)
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
static local::ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS];
CPPAD_ASSERT_UNKNOWN(
(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num()
);
return tape_table + thread;
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
CPPAD_ASSERT_UNKNOWN(
(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num()
);
return reinterpret_cast<local::ADTape<Base>**>(tape_storage_handle(thread));
}

/*!
Expand Down
Loading