source: trunk/cppad/utility/thread_alloc.hpp @ 3938

Last change on this file since 3938 was 3938, checked in by bradbell, 2 years ago

merge to branch: trunk
from repository: https://github.com/coin-or/CppAD
start hash code: 78ba7f801a6fec0dbdaa887c01ea58a9ccb59817
end hash code: bd9a72f2ccec67a9773cd2ecd536df8fe09860da

commit bd9a72f2ccec67a9773cd2ecd536df8fe09860da
Author: Brad Bell <bradbell@…>
Date: Mon May 22 06:14:34 2017 -0700

  1. Add the cppad_extra_debug option to cmake command.
  2. Advance to cppad-20170522.

commit 8f832650db029dd1df2f302b3e6a7f39cb83078f
Author: Brad Bell <bradbell@…>
Date: Sun May 21 07:16:35 2017 -0700

CMakeLists.txt: change type of cppad_deprecated to BOOL (must be NO).
configure.hpp.in: fix comment about CPPAD_DEPRECATED.
ad_ctor.hpp: remove comment about old use of cppad_deprecated.
cmake.omh: remove description of old deprecated case.

commit 9a0a0705f7c44e5a93c136c3bd1e56ab39bb809f
Author: Brad Bell <bradbell@…>
Date: Sun May 21 06:34:38 2017 -0700

Add test that fails when release.cpp is compiled for release.
CMakeLists.txt: improve command line argument comments.

commit bfbc481d68256d71217a1d9a439bc2b2e07f90c2
Author: Brad Bell <bradbell@…>
Date: Sun May 21 04:15:26 2017 -0700

Advance to cppad-20170521.
check_example.sh: simplify.

commit 163044ceea186505229e59770b263fe00b12726d
Author: Brad Bell <bradbell@…>
Date: Sat May 20 09:07:15 2017 -0700

Create test_more/debug_rel (Under construction).

commit 9d90a176a0fc75faff28c0cb2034218d8a3b2f6a
Author: Brad Bell <bradbell@…>
Date: Sat May 20 07:04:52 2017 -0700

readme.md: add link to new directory structure page.

  • Property svn:keywords set to Id
File size: 42.5 KB
Line 
1# ifndef CPPAD_UTILITY_THREAD_ALLOC_HPP
2# define CPPAD_UTILITY_THREAD_ALLOC_HPP
3
4/* --------------------------------------------------------------------------
5CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
6
7CppAD is distributed under multiple licenses. This distribution is under
8the terms of the
9                    Eclipse Public License Version 1.0.
10
11A copy of this license is included in the COPYING file of this distribution.
12Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
13-------------------------------------------------------------------------- */
14
15# include <sstream>
16# include <limits>
17# include <memory>
18
19
20# ifdef _MSC_VER
21// Supress warning that Microsoft compiler changed its behavior and is now
22// doing the correct thing at the statement:
23//                      new(array + i) Type();
24# pragma warning(disable:4345)
25# endif
26
27# include <cppad/core/cppad_assert.hpp>
28# include <cppad/core/define.hpp>
29# include <cppad/local/set_get_in_parallel.hpp>
30namespace CppAD { // BEGIN_CPPAD_NAMESPACE
31/*!
32\file thread_alloc.hpp
33File used to define the CppAD multi-threading allocator class
34*/
35
36/*!
37\def CPPAD_MAX_NUM_CAPACITY
38Maximum number of different capacities the allocator will attempt.
39This must be larger than the log base two of numeric_limit<size_t>::max().
40*/
41# define CPPAD_MAX_NUM_CAPACITY 100
42
43/*!
44\def CPPAD_MIN_DOUBLE_CAPACITY
45Minimum number of double values that will fit in an allocation.
46*/
47# define CPPAD_MIN_DOUBLE_CAPACITY 16
48
49/*!
50\def CPPAD_TRACE_CAPACITY
51If NDEBUG is not defined, print all calls to \c get_memory and \c return_memory
52that correspond to this capacity and thread CPPAD_TRACE_THREAD.
53(Note that if CPPAD_TRACE_CAPACITY is zero, or any other value not in the list
54of capacities, no tracing will be done.)
55*/
56# define CPPAD_TRACE_CAPACITY 0
57
58/*!
59\def CPPAD_TRACE_THREAD
60If NDEBUG is not defined, print all calls to \c get_memory and \c return_memory
61that correspond to this thead and capacity CPPAD_TRACE_CAPACITY.
62*/
63# define CPPAD_TRACE_THREAD 0
64
65/*
66Note that Section 3.6.2 of ISO/IEC 14882:1998(E) states: "The storage for
67objects with static storage duration (3.7.1) shall be zero-initialized
68(8.5) before any other initialization takes place."
69*/
70
71/*!
72Capacity vector for memory allocation block sizes.
73
74Only one of these objects should be created and used as a
75static variable inside of the \c thread_alloc::capacity_info function.
76*/
77
78/*!
79Allocator class that works well with an multi-threading environment.
80*/
81class thread_alloc{
82// ============================================================================
83private:
84
85        class capacity_t {
86        public:
87                /// number of capacity values actually used
88                size_t number;
89                /// the different capacity values
90                size_t value[CPPAD_MAX_NUM_CAPACITY];
91                /// ctor
92                capacity_t(void)
93                {       // Cannot figure out how to call thread_alloc::in_parallel here.
94                        // CPPAD_ASSERT_UNKNOWN(
95                        //      ! thread_alloc::in_parallel() , "thread_alloc: "
96                        //      "parallel mode and parallel_setup not yet called."
97                        // );
98                        number           = 0;
99                        size_t capacity  = CPPAD_MIN_DOUBLE_CAPACITY * sizeof(double);
100                        while( capacity < std::numeric_limits<size_t>::max() / 2 )
101                        {       CPPAD_ASSERT_UNKNOWN( number < CPPAD_MAX_NUM_CAPACITY );
102                                value[number++] = capacity;
103                                // next capactiy is 3/2 times the current one
104                                capacity        = 3 * ( (capacity + 1) / 2 );
105                        }
106                        CPPAD_ASSERT_UNKNOWN( number > 0 );
107                }
108        };
109
110        class block_t {
111        public:
112                /// extra information (currently used by create and delete array)
113                size_t             extra_;
114                /// an index that uniquely idenfifies both thread and capacity
115                size_t             tc_index_;
116                /// pointer to the next memory allocation with the same tc_index_
117                void*              next_;
118                // -----------------------------------------------------------------
119                /// make default constructor private. It is only used by constructor
120                /// for `root arrays below.
121                block_t(void) : extra_(0), tc_index_(0), next_(CPPAD_NULL)
122                { }
123        };
124
125        // ---------------------------------------------------------------------
126        /// Vector of fixed capacity values for this allocator
127        static const capacity_t* capacity_info(void)
128        {       CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
129                static const capacity_t capacity;
130                return &capacity;
131        }
132        // ---------------------------------------------------------------------
133        /// Structure of information for each thread
134        struct thread_alloc_info {
135                /// count of available bytes for this thread
136                size_t  count_inuse_;
137                /// count of inuse bytes for this thread
138                size_t  count_available_;
139                /// root of available list for this thread and each capacity
140                block_t root_available_[CPPAD_MAX_NUM_CAPACITY];
141                /*!
142                root of inuse list for this thread and each capacity
143                If NDEBUG is defined or CPPAD_EXTRA_DEBUG is false, this memory is not
144                used, but it still helps to separate this structure from the structure
145                for the next thread.
146                */
147                block_t root_inuse_[CPPAD_MAX_NUM_CAPACITY];
148        };
149        // ---------------------------------------------------------------------
150        /*!
151        Set and Get hold available memory flag.
152
153        \param set [in]
154        if true, the value returned by this return is changed.
155
156        \param new_value [in]
157        if \a set is true, this is the new value returned by this routine.
158        Otherwise, \c new_value is ignored.
159
160        \return
161        the current setting for this routine (which is initially false).
162        */
163        static bool set_get_hold_memory(bool set, bool new_value = false)
164        {       static bool value = false;
165                if( set )
166                        value = new_value;
167                return value;
168        }
169        // ---------------------------------------------------------------------
170        /*!
171        Get pointer to the information for this thread.
172
173        \param thread [in]
174        Is the thread number for this information pointer.
175
176        \param clear
177        If \a clear is true, then the information pointer for this thread
178        is deleted and the \c CPPAD_NULL pointer is returned.
179        There must be no memory currently in either the inuse or avaialble
180        lists when this routine is called.
181
182        \return
183        is the current informaiton pointer for this thread.
184        If \a clear is false, and the current pointer is CPPAD_NULL,
185        a new infromation record is allocated and its pointer returned.
186        In this case, if \c info is the retured pointer,
187        <code>info->count_inuse == 0</code> and
188        <code>info->count_available == 0</code>.
189        In addition,
190        for <code>c = 0 , ... , CPPAD_MAX_NUM_CAPACITY-1</code>
191        <code>info->root_inuse_[c].next_ == CPPAD_NULL</code> and
192        <code>info->root_available_[c].next_ == CPPAD_NULL</code>.
193        */
194        static thread_alloc_info* thread_info(
195                size_t             thread          ,
196                bool               clear = false   )
197        {       static thread_alloc_info* all_info[CPPAD_MAX_NUM_THREADS];
198                static thread_alloc_info  zero_info;
199
200                CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
201
202                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS );
203
204                thread_alloc_info* info = all_info[thread];
205                if( clear )
206                {       if( info != CPPAD_NULL )
207                        {
208# ifndef NDEBUG
209                                CPPAD_ASSERT_UNKNOWN(
210                                        info->count_inuse_     == 0 &&
211                                        info->count_available_ == 0
212                                );
213                                for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++)
214                                {       CPPAD_ASSERT_UNKNOWN(
215                                                info->root_inuse_[c].next_     == CPPAD_NULL &&
216                                                info->root_available_[c].next_ == CPPAD_NULL
217                                        );
218                                }
219# endif
220                                if( thread != 0 )
221                                        ::operator delete( reinterpret_cast<void*>(info) );
222                                info             = CPPAD_NULL;
223                                all_info[thread] = info;
224                        }
225                }
226                else if( info == CPPAD_NULL )
227                {       if( thread == 0 )
228                                info = &zero_info;
229                        else
230                        {       size_t size = sizeof(thread_alloc_info);
231                                void* v_ptr = ::operator new(size);
232                                info        = reinterpret_cast<thread_alloc_info*>(v_ptr);
233                        }
234                        all_info[thread] = info;
235
236                        // initialize the information record
237                        for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++)
238                        {       info->root_inuse_[c].next_       = CPPAD_NULL;
239                                info->root_available_[c].next_   = CPPAD_NULL;
240                        }
241                        info->count_inuse_     = 0;
242                        info->count_available_ = 0;
243                }
244                return info;
245        }
246        // -----------------------------------------------------------------------
247        /*!
248        Increase the number of bytes of memory that are currently in use; i.e.,
249        that been obtained with \c get_memory and not yet returned.
250
251        \param inc [in]
252        amount to increase memory in use.
253
254        \param thread [in]
255        Thread for which we are increasing the number of bytes in use
256        (must be less than \c num_threads).
257        Durring parallel execution, this must be the thread
258        that is currently executing.
259        */
260        static void inc_inuse(size_t inc, size_t thread)
261        {
262                CPPAD_ASSERT_UNKNOWN( thread < num_threads() );
263                CPPAD_ASSERT_UNKNOWN(
264                        thread == thread_num() || (! in_parallel())
265                );
266                thread_alloc_info* info = thread_info(thread);
267
268                // do the addition
269                size_t result = info->count_inuse_ + inc;
270                CPPAD_ASSERT_UNKNOWN( result >= info->count_inuse_ );
271
272                info->count_inuse_ = result;
273        }
274        // -----------------------------------------------------------------------
275        /*!
276        Increase the number of bytes of memory that are currently avaialble; i.e.,
277        have been obtained obtained from the system and are being held future use.
278
279        \copydetails inc_inuse
280        */
281        static void inc_available(size_t inc, size_t thread)
282        {
283                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS);
284                CPPAD_ASSERT_UNKNOWN(
285                        thread == thread_num() || (! in_parallel())
286                );
287                thread_alloc_info* info = thread_info(thread);
288                // do the addition
289                size_t result = info->count_available_ + inc;
290                CPPAD_ASSERT_UNKNOWN( result >= info->count_available_ );
291
292                info->count_available_ = result;
293        }
294        // -----------------------------------------------------------------------
295        /*!
296        Decrease the number of bytes of memory that are currently in use; i.e.,
297        that been obtained with \c get_memory and not yet returned.
298
299        \param dec [in]
300        amount to decrease number of bytes in use.
301
302        \param thread [in]
303        Thread for which we are decreasing the number of bytes in use
304        (must be less than \c num_threads).
305        Durring parallel execution, this must be the thread
306        that is currently executing.
307        */
308        static void dec_inuse(size_t dec, size_t thread)
309        {
310                CPPAD_ASSERT_UNKNOWN(
311                        thread < num_threads() || (! in_parallel())
312                );
313                CPPAD_ASSERT_UNKNOWN(
314                        thread == thread_num() || (! in_parallel())
315                );
316                thread_alloc_info* info = thread_info(thread);
317
318                // do the subtraction
319                CPPAD_ASSERT_UNKNOWN( info->count_inuse_ >= dec );
320                info->count_inuse_ = info->count_inuse_ - dec;
321        }
322        // -----------------------------------------------------------------------
323        /*!
324        Decrease the number of bytes of memory that are currently avaialble; i.e.,
325        have been obtained obtained from the system and are being held future use.
326
327        \copydetails dec_inuse
328        */
329        static void dec_available(size_t dec, size_t thread)
330        {
331                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS);
332                CPPAD_ASSERT_UNKNOWN(
333                        thread == thread_num() || (! in_parallel())
334                );
335                thread_alloc_info* info = thread_info(thread);
336                // do the subtraction
337                CPPAD_ASSERT_UNKNOWN( info->count_available_ >= dec );
338                info->count_available_ =  info->count_available_ - dec;
339        }
340
341        // ----------------------------------------------------------------------
342        /*!
343        Set and get the number of threads that are sharing memory.
344
345        \param number_new
346        If \c number is zero, we are only retreiving the current maximum
347        number of threads. Otherwise, we are setting and retreiving
348        maximum number of threads.
349
350        \return
351        the number of threads that are sharing memory.
352        If \c number_new is non-zero, the return value is equal to
353        \c number_new.
354        */
355        static size_t set_get_num_threads(size_t number_new)
356        {       static size_t number_user = 1;
357
358                CPPAD_ASSERT_UNKNOWN( number_new <= CPPAD_MAX_NUM_THREADS );
359                CPPAD_ASSERT_UNKNOWN( ! in_parallel() || (number_new == 0) );
360
361                // case where we are changing the number of threads
362                if( number_new != 0 )
363                        number_user = number_new;
364
365                return number_user;
366        }
367        /*!
368        Set and call the routine that determine the current thread number.
369
370        \return
371        returns value for the most recent setting for \a thread_num_new.
372        If \a set is true,
373        or the most recent setting is \c CPPAD_NULL (its initial value),
374        the return value is zero.
375        Otherwise the routine corresponding to the most recent setting
376        is called and its value returned by \c set_get_thread_num.
377
378        \param thread_num_new [in]
379        If \a set is false, \a thread_num_new it is not used.
380        Otherwise, the current value of \c thread_num_new becomes the
381        most recent setting for thread_num.
382
383        \param set
384        If \a set is true, then \a thread_num_new is becomes the most
385        recent setting for this \c set_get_thread_num.
386        */
387        static size_t set_get_thread_num(
388                size_t (*thread_num_new)(void)  ,
389                bool set = false                )
390        {       static size_t (*thread_num_user)(void) = CPPAD_NULL;
391
392                if( set )
393                {       thread_num_user = thread_num_new;
394                        return 0;
395                }
396
397                if( thread_num_user == CPPAD_NULL )
398                        return 0;
399
400                size_t thread = thread_num_user();
401                CPPAD_ASSERT_KNOWN(
402                        thread < set_get_num_threads(0) ,
403                        "parallel_setup: thread_num() >= num_threads"
404                );
405                return thread;
406        }
407// ============================================================================
408public:
409/*
410$begin ta_parallel_setup$$
411$spell
412        alloc
413        num
414        bool
415$$
416$section Setup thread_alloc For Use in Multi-Threading Environment$$
417$mindex parallel initialize$$
418
419
420
421
422$head Syntax$$
423$codei%thread_alloc::parallel_setup(%num_threads%, %in_parallel%, %thread_num%)
424%$$
425
426$head Purpose$$
427By default there is only one thread and all execution is in sequential mode,
428i.e., multiple threads are not sharing the same memory; i.e.
429not in parallel mode.
430
431$head Speed$$
432It should be faster, even when $icode num_thread$$ is equal to one,
433for $code thread_alloc$$ to hold onto memory.
434This can be accomplished using the function call
435$codei%
436        thread_alloc::hold_memory(true)
437%$$
438see $cref/hold_memory/ta_hold_memory/$$.
439
440$head num_threads$$
441This argument has prototype
442$codei%
443        size_t %num_threads%
444%$$
445and must be greater than zero.
446It specifies the number of threads that are sharing memory.
447The case $icode%num_threads% == 1%$$ is a special case that is
448used to terminate a multi-threading environment.
449
450$head in_parallel$$
451This function has prototype
452$codei%
453        bool %in_parallel%(void)
454%$$
455It must return $code true$$ if there is more than one thread
456currently executing.
457Otherwise it can return false.
458$pre
459
460$$
461In the special case where $icode%num_threads% == 1%$$,
462the routine $icode in_parallel$$ is not used.
463
464$head thread_num$$
465This function has prototype
466$codei%
467        size_t %thread_num%(void)
468%$$
469It must return a thread number that uniquely identifies the
470currently executing thread.
471Furthermore
472$codei%
473        0 <= %thread_num%() < %num_threads%
474%$$.
475In the special case where $icode%num_threads% == 1%$$,
476the routine $icode thread_num$$ is not used.
477$pre
478
479$$
480Note that this function is called by other routines so,
481as soon as a new thread is executing,
482one must be certain that $icode thread_num()$$ will
483work for that thread.
484
485$head Restrictions$$
486The function $code parallel_setup$$ must be called before
487the program enters $cref/parallel/ta_in_parallel/$$ execution mode.
488In addition, this function cannot be called while in parallel mode.
489
490$head Example$$
491The files
492$cref simple_ad_openmp.cpp$$,
493$cref simple_ad_bthread.cpp$$, and
494$cref simple_ad_pthread.cpp$$,
495contain examples and tests that use this function.
496
497$end
498*/
499        /*!
500        Set thread_alloc up for parallel mode usage.
501
502        \param num_threads [in]
503        Is the number of thread that may be executing at the same time.
504
505        \param in_parallel [in]
506        Is the routine that determines if we are in parallel mode or not.
507
508        \param thread_num [in]
509        Is the routine that determines the current thread number
510        (between zero and num_threads minus one).
511        */
512        static void parallel_setup(
513                size_t num_threads         ,
514                bool (*in_parallel)(void)  ,
515                size_t (*thread_num)(void) )
516        {
517                // Special case where we go back to single thread mode right away
518                // (previous settings may no longer be valid)
519                if( num_threads == 1 )
520                {       bool set = true;
521                        set_get_num_threads(num_threads);
522                        // emphasize that this routine is outside thread_alloc class
523                        CppAD::local::set_get_in_parallel(CPPAD_NULL, set);
524                        set_get_thread_num(CPPAD_NULL, set);
525                        return;
526                }
527
528                CPPAD_ASSERT_KNOWN(
529                        num_threads <= CPPAD_MAX_NUM_THREADS ,
530                        "parallel_setup: num_threads is too large"
531                );
532                CPPAD_ASSERT_KNOWN(
533                        num_threads != 0 ,
534                        "parallel_setup: num_threads == zero"
535                );
536                CPPAD_ASSERT_KNOWN(
537                        in_parallel != CPPAD_NULL ,
538                        "parallel_setup: num_threads != 1 and in_parallel == CPPAD_NULL"
539                );
540                CPPAD_ASSERT_KNOWN(
541                        thread_num != CPPAD_NULL ,
542                        "parallel_setup: num_threads != 1 and thread_num == CPPAD_NULL"
543                );
544
545                // Make sure that constructors for all static variables in this file
546                // are called in sequential mode.
547                for(size_t thread = 0; thread < num_threads; thread++)
548                        thread_info(thread);
549                capacity_info();
550                size_t cap_bytes;
551                void* v_ptr = get_memory(0, cap_bytes);
552
553                // free memory allocated by call to get_memory above
554                return_memory(v_ptr);
555                free_available( set_get_thread_num(CPPAD_NULL) );
556
557                // delay this so thread_num() call above is in previous mode
558                // (current setings may not yet be valid)
559                if( num_threads > 1 )
560                {       bool set = true;
561                        set_get_num_threads(num_threads);
562                        // emphasize that this routine is outside thread_alloc class
563                        CppAD::local::set_get_in_parallel(in_parallel, set);
564                        set_get_thread_num(thread_num, set);
565                }
566        }
567/*
568$begin ta_num_threads$$
569$spell
570        inv
571        CppAD
572        num
573        alloc
574$$
575$section Get Number of Threads$$
576
577
578$head Syntax$$
579$icode%number% = thread_alloc::num_threads()%$$
580
581$head Purpose$$
582Determine the number of threads as set during $cref/parallel_setup/ta_parallel_setup/$$.
583
584$head number$$
585The return value $icode number$$ has prototype
586$codei%
587        size_t %number%
588%$$
589and is equal to the value of
590$cref/num_threads/ta_parallel_setup/num_threads/$$
591in the previous call to $icode parallel_setup$$.
592If there was no such previous call, the value one is returned.
593
594$head Example$$
595The example and test $cref thread_alloc.cpp$$ uses this routine.
596
597$end
598*/
599        /*!
600        Get the current number of threads that thread_alloc can use.
601        */
602        static size_t num_threads(void)
603        {       return set_get_num_threads(0); }
604/* -----------------------------------------------------------------------
605$begin ta_in_parallel$$
606
607$section Is The Current Execution in Parallel Mode$$
608$mindex sequential$$
609$spell
610        thread_alloc
611        bool
612$$
613
614
615$head Syntax$$
616$icode%flag% = thread_alloc::in_parallel()%$$
617
618$head Purpose$$
619Some of the $cref thread_alloc$$ allocation routines have different
620specifications for parallel (not sequential) execution mode.
621This routine enables you to determine if the current execution mode
622is sequential or parallel.
623
624$head flag$$
625The return value has prototype
626$codei%
627        bool %flag%
628%$$
629It is true if the current execution is in parallel mode
630(possibly multi-threaded) and false otherwise (sequential mode).
631
632$head Example$$
633$cref thread_alloc.cpp$$
634
635$end
636*/
637        /// Are we in a parallel execution state; i.e., is it possible that
638        /// other threads are currently executing.
639        static bool in_parallel(void)
640        {       // emphasize that this routine is outside thread_alloc class
641                return CppAD::local::set_get_in_parallel(0);
642        }
643/* -----------------------------------------------------------------------
644$begin ta_thread_num$$
645$spell
646        CppAD
647        num
648        thread_alloc
649        cppad.hpp
650$$
651
652$section Get the Current Thread Number$$
653
654
655$head Syntax$$
656$icode%thread% = thread_alloc::thread_num()%$$
657
658$head Purpose$$
659Some of the $cref thread_alloc$$ allocation routines have a thread number.
660This routine enables you to determine the current thread.
661
662$head thread$$
663The return value $icode thread$$ has prototype
664$codei%
665        size_t %thread%
666%$$
667and is the currently executing thread number.
668
669$head Example$$
670$cref thread_alloc.cpp$$
671
672$end
673*/
674        /// Get current thread number
675        static size_t thread_num(void)
676        {       return set_get_thread_num(CPPAD_NULL); }
677/* -----------------------------------------------------------------------
678$begin ta_get_memory$$
679$spell
680        std
681        num
682        ptr
683        thread_alloc
684$$
685
686$section Get At Least A Specified Amount of Memory$$
687$mindex allocate$$
688
689
690$head Syntax$$
691$icode%v_ptr% = thread_alloc::get_memory(%min_bytes%, %cap_bytes%)%$$
692
693$head Purpose$$
694Use $cref thread_alloc$$ to obtain a minimum number of bytes of memory
695(for use by the $cref/current thread/ta_thread_num/$$).
696
697$head min_bytes$$
698This argument has prototype
699$codei%
700        size_t %min_bytes%
701%$$
702It specifies the minimum number of bytes to allocate.
703This value must be less than
704$codep
705        std::numeric_limits<size_t>::max() / 2
706$$
707
708$head cap_bytes$$
709This argument has prototype
710$codei%
711        size_t& %cap_bytes%
712%$$
713It's input value does not matter.
714Upon return, it is the actual number of bytes (capacity)
715that have been allocated for use,
716$codei%
717        %min_bytes% <= %cap_bytes%
718%$$
719
720$head v_ptr$$
721The return value $icode v_ptr$$ has prototype
722$codei%
723        void* %v_ptr%
724%$$
725It is the location where the $icode cap_bytes$$ of memory
726that have been allocated for use begins.
727
728$head Allocation Speed$$
729This allocation should be faster if the following conditions hold:
730$list number$$
731The memory allocated by a previous call to $code get_memory$$
732is currently available for use.
733$lnext
734The current $icode min_bytes$$ is between
735the previous $icode min_bytes$$ and previous $icode cap_bytes$$.
736$lend
737
738$head Alignment$$
739We call a memory allocation aligned if the address is a multiple
740of the number of bytes in a $code size_t$$ value.
741If the system $code new$$ allocator is aligned, then $icode v_ptr$$
742pointer is also aligned.
743
744$head Example$$
745$cref thread_alloc.cpp$$
746
747$end
748*/
749        /*!
750        Use thread_alloc to get a specified amount of memory.
751
752        If the memory allocated by a previous call to \c get_memory is now
753        avaialable, and \c min_bytes is between its previous value
754        and the previous \c cap_bytes, this memory allocation will have
755        optimal speed. Otherwise, the memory allocation is more complicated and
756        may have to wait for other threads to complete an allocation.
757
758        \param min_bytes [in]
759        The minimum number of bytes of memory to be obtained for use.
760
761        \param cap_bytes [out]
762        The actual number of bytes of memory obtained for use.
763
764        \return
765        pointer to the beginning of the memory allocated for use.
766        */
767        static void* get_memory(size_t min_bytes, size_t& cap_bytes)
768        {       // see first_trace below
769                CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
770
771                // check that number of requested bytes is not to large
772                CPPAD_ASSERT_KNOWN(
773                        min_bytes < std::numeric_limits<size_t>::max() / 2 ,
774                        "get_memory(min_bytes, cap_bytes): min_bytes is too large"
775                );
776
777                size_t num_cap = capacity_info()->number;
778                using std::cout;
779                using std::endl;
780
781                // determine the capacity for this request
782                size_t c_index   = 0;
783                const size_t* capacity_vec = capacity_info()->value;
784                while( capacity_vec[c_index] < min_bytes )
785                {       ++c_index;
786                        CPPAD_ASSERT_UNKNOWN(c_index < num_cap );
787                }
788                cap_bytes = capacity_vec[c_index];
789
790                // determine the thread, capacity, and info for this thread
791                size_t thread            = thread_num();
792                size_t tc_index          = thread * num_cap + c_index;
793                thread_alloc_info* info  = thread_info(thread);
794
795# ifndef NDEBUG
796                // trace allocation
797                static bool first_trace = true;
798                if(     cap_bytes == CPPAD_TRACE_CAPACITY &&
799                     thread    ==  CPPAD_TRACE_THREAD  && first_trace )
800                {       cout << endl;
801                        cout << "thread_alloc: Trace for Thread = " << thread;
802                        cout << " and capacity = " << cap_bytes << endl;
803                        if( first_trace )
804                                first_trace = false;
805                }
806
807# if CPPAD_EXTRA_DEBUG
808                // Root nodes for both lists. Note these are different for different
809                // threads because tc_index is different for different threads.
810                block_t* inuse_root     = info->root_inuse_ + c_index;
811# endif
812# endif
813                block_t* available_root = info->root_available_ + c_index;
814
815                // check if we already have a node we can use
816                void* v_node              = available_root->next_;
817                block_t* node             = reinterpret_cast<block_t*>(v_node);
818                if( node != CPPAD_NULL )
819                {       CPPAD_ASSERT_UNKNOWN( node->tc_index_ == tc_index );
820
821                        // remove node from available list
822                        available_root->next_ = node->next_;
823
824                        // return value for get_memory
825                        void* v_ptr = reinterpret_cast<void*>(node + 1);
826# ifndef NDEBUG
827# if CPPAD_EXTRA_DEBUG
828                        // add node to inuse list
829                        node->next_           = inuse_root->next_;
830                        inuse_root->next_     = v_node;
831# endif
832
833                        // trace allocation
834                        if(     cap_bytes == CPPAD_TRACE_CAPACITY &&
835                             thread    ==  CPPAD_TRACE_THREAD   )
836                        {       cout << "get_memory:    v_ptr = " << v_ptr << endl; }
837# endif
838
839                        // adjust counts
840                        inc_inuse(cap_bytes, thread);
841                        dec_available(cap_bytes, thread);
842
843                        // return pointer to memory, do not inclue thread_alloc information
844                        return v_ptr;
845                }
846
847                // Create a new node with thread_alloc information at front.
848                // This uses the system allocator, which is thread safe, but slower,
849                // because the thread might wait for a lock on the allocator.
850                v_node          = ::operator new(sizeof(block_t) + cap_bytes);
851                node            = reinterpret_cast<block_t*>(v_node);
852                node->tc_index_ = tc_index;
853                void* v_ptr     = reinterpret_cast<void*>(node + 1);
854
855# ifndef NDEBUG
856# if CPPAD_EXTRA_DEBUG
857                // add node to inuse list
858                node->next_       = inuse_root->next_;
859                inuse_root->next_ = v_node;
860# endif
861
862                // trace allocation
863                if( cap_bytes == CPPAD_TRACE_CAPACITY &&
864                    thread    == CPPAD_TRACE_THREAD    )
865                {       cout << "get_memory:    v_ptr = " << v_ptr << endl; }
866# endif
867
868                // adjust counts
869                inc_inuse(cap_bytes, thread);
870
871                return v_ptr;
872        }
873
874/* -----------------------------------------------------------------------
875$begin ta_return_memory$$
876$spell
877        num
878        ptr
879        thread_alloc
880$$
881
882$section Return Memory to thread_alloc$$
883$mindex return_memory available$$
884
885
886$head Syntax$$
887$codei%thread_alloc::return_memory(%v_ptr%)%$$
888
889$head Purpose$$
890If $cref/hold_memory/ta_hold_memory/$$ is false,
891the memory is returned to the system.
892Otherwise, the memory is retained by $cref thread_alloc$$ for quick future use
893by the thread that allocated to memory.
894
895$head v_ptr$$
896This argument has prototype
897$codei%
898        void* %v_ptr%
899%$$.
900It must be a pointer to memory that is currently in use; i.e.
901obtained by a previous call to
902$cref/get_memory/ta_get_memory/$$ and not yet returned.
903
904$head Thread$$
905Either the $cref/current thread/ta_thread_num/$$ must be the same as during
906the corresponding call to $cref/get_memory/ta_get_memory/$$,
907or the current execution mode must be sequential
908(not $cref/parallel/ta_in_parallel/$$).
909
910$head NDEBUG$$
911If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster).
912Otherwise, a list of in use pointers is searched to make sure
913that $icode v_ptr$$ is in the list.
914
915$head Example$$
916$cref thread_alloc.cpp$$
917
918$end
919*/
920        /*!
921        Return memory that was obtained by \c get_memory.
922        If  <code>num_threads() == 1</code>,
923        the memory is returned to the system.
924        Otherwise, it is retained by \c thread_alloc and available for use by
925        \c get_memory for this thread.
926
927        \param v_ptr [in]
928        Value of the pointer returned by \c get_memory and still in use.
929        After this call, this pointer will available (and not in use).
930
931        \par
932        We must either be in sequential (not parallel) execution mode,
933        or the current thread must be the same as for the corresponding call
934        to \c get_memory.
935        */
936        static void return_memory(void* v_ptr)
937        {       size_t num_cap   = capacity_info()->number;
938
939                block_t* node    = reinterpret_cast<block_t*>(v_ptr) - 1;
940                size_t tc_index  = node->tc_index_;
941                size_t thread    = tc_index / num_cap;
942                size_t c_index   = tc_index % num_cap;
943                size_t capacity  = capacity_info()->value[c_index];
944
945                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS );
946                CPPAD_ASSERT_KNOWN(
947                        thread == thread_num() || (! in_parallel()),
948                        "Attempt to return memory for a different thread "
949                        "while in parallel mode"
950                );
951
952                thread_alloc_info* info = thread_info(thread);
953# ifndef NDEBUG
954# if CPPAD_EXTRA_DEBUG
955                // remove node from inuse list
956                void* v_node         = reinterpret_cast<void*>(node);
957                block_t* inuse_root  = info->root_inuse_ + c_index;
958                block_t* previous    = inuse_root;
959                while( (previous->next_ != CPPAD_NULL) & (previous->next_ != v_node) )
960                        previous = reinterpret_cast<block_t*>(previous->next_);
961
962                // check that v_ptr is valid
963                if( previous->next_ != v_node )
964                {       using std::endl;
965                        std::ostringstream oss;
966                        oss << "return_memory: attempt to return memory not in use";
967                        oss << endl;
968                        oss << "v_ptr    = " << v_ptr    << endl;
969                        oss << "thread   = " << thread   << endl;
970                        oss << "capacity = " << capacity << endl;
971                        oss << "See CPPAD_TRACE_THREAD & CPPAD_TRACE_CAPACITY in";
972                        oss << endl << "%# include <cppad/utility/thread_alloc.hpp>" << endl;
973                        // oss.str() returns a string object with a copy of the current
974                        // contents in the stream buffer.
975                        std::string msg_str       = oss.str();
976                        // msg_str.c_str() returns a pointer to the c-string
977                        // representation of the string object's value.
978                        const char* msg_char_star = msg_str.c_str();
979                        CPPAD_ASSERT_KNOWN(false, msg_char_star );
980                }
981                // remove v_ptr from inuse list
982                previous->next_  = node->next_;
983# endif
984                // trace option
985                if( capacity==CPPAD_TRACE_CAPACITY && thread==CPPAD_TRACE_THREAD )
986                {       std::cout << "return_memory: v_ptr = " << v_ptr << std::endl; }
987
988# endif
989                // capacity bytes are removed from the inuse pool
990                dec_inuse(capacity, thread);
991
992                // check for case where we just return the memory to the system
993                if( ! set_get_hold_memory(false) )
994                {       ::operator delete( reinterpret_cast<void*>(node) );
995                        return;
996                }
997
998                // add this node to available list for this thread and capacity
999                block_t* available_root = info->root_available_ + c_index;
1000                node->next_             = available_root->next_;
1001                available_root->next_   = reinterpret_cast<void*>(node);
1002
1003                // capacity bytes are added to the available pool
1004                inc_available(capacity, thread);
1005        }
1006/* -----------------------------------------------------------------------
1007$begin ta_free_available$$
1008$spell
1009        num
1010        thread_alloc
1011$$
1012
1013$section Free Memory Currently Available for Quick Use by a Thread$$
1014$mindex free_available$$
1015$spell
1016        inuse
1017$$
1018
1019
1020$head Syntax$$
1021$codei%thread_alloc::free_available(%thread%)%$$
1022
1023$head Purpose$$
1024Return to the system all the memory that is currently being
1025$cref/held/ta_hold_memory/$$ for quick use by the specified thread.
1026
1027$subhead Extra Memory$$
1028In the case where $icode%thread% > 0%$$,
1029some extra memory is used to track allocations by the specified thread.
1030If
1031$codei%
1032        thread_alloc::inuse(%thread%) == 0
1033%$$
1034the extra memory is also returned to the system.
1035
1036$head thread$$
1037This argument has prototype
1038$codei%
1039        size_t %thread%
1040%$$
1041Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$,
1042or the current execution mode must be sequential
1043(not $cref/parallel/ta_in_parallel/$$).
1044
1045$head Example$$
1046$cref thread_alloc.cpp$$
1047
1048$end
1049*/
1050        /*!
1051        Return all the memory being held as available for a thread to the system.
1052
1053        \param thread [in]
1054        this thread that will no longer have any available memory after this call.
1055        This must either be the thread currently executing, or we must be
1056        in sequential (not parallel) execution mode.
1057        */
1058        static void free_available(size_t thread)
1059        {       CPPAD_ASSERT_KNOWN(
1060                        thread < CPPAD_MAX_NUM_THREADS,
1061                        "Attempt to free memory for a thread >= CPPAD_MAX_NUM_THREADS"
1062                );
1063                CPPAD_ASSERT_KNOWN(
1064                        thread == thread_num() || (! in_parallel()),
1065                        "Attempt to free memory for a different thread "
1066                        "while in parallel mode"
1067                );
1068
1069                size_t num_cap = capacity_info()->number;
1070                if( num_cap == 0 )
1071                        return;
1072                const size_t*     capacity_vec  = capacity_info()->value;
1073                size_t c_index;
1074                thread_alloc_info* info = thread_info(thread);
1075                for(c_index = 0; c_index < num_cap; c_index++)
1076                {       size_t capacity = capacity_vec[c_index];
1077                        block_t* available_root = info->root_available_ + c_index;
1078                        void* v_ptr             = available_root->next_;
1079                        while( v_ptr != CPPAD_NULL )
1080                        {       block_t* node = reinterpret_cast<block_t*>(v_ptr);
1081                                void* next    = node->next_;
1082                                ::operator delete(v_ptr);
1083                                v_ptr         = next;
1084
1085                                dec_available(capacity, thread);
1086                        }
1087                        available_root->next_ = CPPAD_NULL;
1088                }
1089                CPPAD_ASSERT_UNKNOWN( available(thread) == 0 );
1090                if( inuse(thread) == 0 )
1091                {       // clear the information for this thread
1092                        thread_info(thread, true);
1093                }
1094        }
1095/* -----------------------------------------------------------------------
1096$begin ta_hold_memory$$
1097$spell
1098        alloc
1099        num
1100$$
1101
1102$section Control When Thread Alloc Retains Memory For Future Use$$
1103$mindex hold$$
1104
1105$head Syntax$$
1106$codei%thread_alloc::hold_memory(%value%)%$$
1107
1108$head Purpose$$
1109It should be faster, even when $icode num_thread$$ is equal to one,
1110for $code thread_alloc$$ to hold onto memory.
1111Calling $icode hold_memory$$ with $icode value$$ equal to true,
1112instructs $code thread_alloc$$ to hold onto memory,
1113and put it in the $cref/available/ta_available/$$ pool,
1114after each call to $cref/return_memory/ta_return_memory/$$.
1115
1116$head value$$
1117If $icode value$$ is true,
1118$code thread_alloc$$ with hold onto memory for future quick use.
1119If it is false, future calls to $cref/return_memory/ta_return_memory/$$
1120will return the corresponding memory to the system.
1121By default (when $code hold_memory$$ has not been called)
1122$code thread_alloc$$ does not hold onto memory.
1123
1124$head free_available$$
1125Memory that is being held by $code thread_alloc$$ can be returned
1126to the system using $cref/free_available/ta_free_available/$$.
1127
1128$end
1129*/
1130        /*!
1131        Change the thread_alloc hold memory setting.
1132
1133        \param value [in]
1134        New value for the thread_alloc hold memory setting.
1135        */
1136        static void hold_memory(bool value)
1137        {       bool set = true;
1138                set_get_hold_memory(set, value);
1139        }
1140
1141/* -----------------------------------------------------------------------
1142$begin ta_inuse$$
1143$spell
1144        num
1145        inuse
1146        thread_alloc
1147$$
1148
1149$section Amount of Memory a Thread is Currently Using$$
1150$mindex inuse$$
1151
1152
1153$head Syntax$$
1154$icode%num_bytes% = thread_alloc::inuse(%thread%)%$$
1155
1156$head Purpose$$
1157Memory being managed by $cref thread_alloc$$ has two states,
1158currently in use by the specified thread,
1159and quickly available for future use by the specified thread.
1160This function informs the program how much memory is in use.
1161
1162$head thread$$
1163This argument has prototype
1164$codei%
1165        size_t %thread%
1166%$$
1167Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$,
1168or the current execution mode must be sequential
1169(not $cref/parallel/ta_in_parallel/$$).
1170
1171$head num_bytes$$
1172The return value has prototype
1173$codei%
1174        size_t %num_bytes%
1175%$$
1176It is the number of bytes currently in use by the specified thread.
1177
1178$head Example$$
1179$cref thread_alloc.cpp$$
1180
1181$end
1182*/
1183        /*!
1184        Determine the amount of memory that is currently inuse.
1185
1186        \param thread [in]
1187        Thread for which we are determining the amount of memory
1188        (must be < CPPAD_MAX_NUM_THREADS).
1189        Durring parallel execution, this must be the thread
1190        that is currently executing.
1191
1192        \return
1193        The amount of memory in bytes.
1194        */
1195        static size_t inuse(size_t thread)
1196        {
1197                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS);
1198                CPPAD_ASSERT_UNKNOWN(
1199                        thread == thread_num() || (! in_parallel())
1200                );
1201                thread_alloc_info* info = thread_info(thread);
1202                return info->count_inuse_;
1203        }
1204/* -----------------------------------------------------------------------
1205$begin ta_available$$
1206$spell
1207        num
1208        thread_alloc
1209$$
1210
1211$section Amount of Memory Available for Quick Use by a Thread$$
1212
1213
1214$head Syntax$$
1215$icode%num_bytes% = thread_alloc::available(%thread%)%$$
1216
1217$head Purpose$$
1218Memory being managed by $cref thread_alloc$$ has two states,
1219currently in use by the specified thread,
1220and quickly available for future use by the specified thread.
1221This function informs the program how much memory is available.
1222
1223$head thread$$
1224This argument has prototype
1225$codei%
1226        size_t %thread%
1227%$$
1228Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$,
1229or the current execution mode must be sequential
1230(not $cref/parallel/ta_in_parallel/$$).
1231
1232$head num_bytes$$
1233The return value has prototype
1234$codei%
1235        size_t %num_bytes%
1236%$$
1237It is the number of bytes currently available for use by the specified thread.
1238
1239$head Example$$
1240$cref thread_alloc.cpp$$
1241
1242$end
1243*/
1244        /*!
1245        Determine the amount of memory that is currently available for use.
1246
1247        \copydetails inuse
1248        */
1249        static size_t available(size_t thread)
1250        {
1251                CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS);
1252                CPPAD_ASSERT_UNKNOWN(
1253                        thread == thread_num() || (! in_parallel())
1254                );
1255                thread_alloc_info* info = thread_info(thread);
1256                return info->count_available_;
1257        }
1258/* -----------------------------------------------------------------------
1259$begin ta_create_array$$
1260$spell
1261        inuse
1262        thread_alloc
1263        sizeof
1264$$
1265
1266$section Allocate An Array and Call Default Constructor for its Elements$$
1267$mindex create_array$$
1268
1269
1270$head Syntax$$
1271$icode%array% = thread_alloc::create_array<%Type%>(%size_min%, %size_out%)%$$.
1272
1273$head Purpose$$
1274Create a new raw array using $cref thread_alloc$$ memory allocator
1275(works well in a multi-threading environment)
1276and call default constructor for each element.
1277
1278$head Type$$
1279The type of the elements of the array.
1280
1281$head size_min$$
1282This argument has prototype
1283$codei%
1284        size_t %size_min%
1285%$$
1286This is the minimum number of elements that there can be
1287in the resulting $icode array$$.
1288
1289$head size_out$$
1290This argument has prototype
1291$codei%
1292        size_t& %size_out%
1293%$$
1294The input value of this argument does not matter.
1295Upon return, it is the actual number of elements
1296in $icode array$$
1297($icode% size_min %<=% size_out%$$).
1298
1299$head array$$
1300The return value $icode array$$ has prototype
1301$codei%
1302        %Type%* %array%
1303%$$
1304It is array with $icode size_out$$ elements.
1305The default constructor for $icode Type$$ is used to initialize the
1306elements of $icode array$$.
1307Note that $cref/delete_array/ta_delete_array/$$
1308should be used to destroy the array when it is no longer needed.
1309
1310$head Delta$$
1311The amount of memory $cref/inuse/ta_inuse/$$ by the current thread,
1312will increase $icode delta$$ where
1313$codei%
1314        sizeof(%Type%) * (%size_out% + 1) > %delta% >= sizeof(%Type%) * %size_out%
1315%$$
1316The $cref/available/ta_available/$$ memory will decrease by $icode delta$$,
1317(and the allocation will be faster)
1318if a previous allocation with $icode size_min$$ between its current value
1319and $icode size_out$$ is available.
1320
1321$head Alignment$$
1322We call a memory allocation aligned if the address is a multiple
1323of the number of bytes in a $code size_t$$ value.
1324If the system $code new$$ allocator is aligned, then $icode array$$
1325pointer is also aligned.
1326
1327$head Example$$
1328$cref thread_alloc.cpp$$
1329
1330$end
1331*/
1332        /*!
1333        Use thread_alloc to allocate an array, then call default construtor
1334        for each element.
1335
1336        \tparam Type
1337        The type of the elements of the array.
1338
1339        \param size_min [in]
1340        The minimum number of elements in the array.
1341
1342        \param size_out [out]
1343        The actual number of elements in the array.
1344
1345        \return
1346        pointer to the first element of the array.
1347        The default constructor is used to initialize
1348        all the elements of the array.
1349
1350        \par
1351        The \c extra_ field, in the \c thread_alloc node before the return value,
1352        is set to size_out.
1353        */
1354        template <class Type>
1355        static Type* create_array(size_t size_min, size_t& size_out)
1356        {       // minimum number of bytes to allocate
1357                size_t min_bytes = size_min * sizeof(Type);
1358                // do the allocation
1359                size_t num_bytes;
1360                void*  v_ptr     = get_memory(min_bytes, num_bytes);
1361                // This is where the array starts
1362                Type*  array     = reinterpret_cast<Type*>(v_ptr);
1363                // number of Type values in the allocation
1364                size_out         = num_bytes / sizeof(Type);
1365                // store this number in the extra field
1366                block_t* node    = reinterpret_cast<block_t*>(v_ptr) - 1;
1367                node->extra_     = size_out;
1368
1369                // call default constructor for each element
1370                size_t i;
1371                for(i = 0; i < size_out; i++)
1372                        new(array + i) Type();
1373
1374                return array;
1375        }
1376/* -----------------------------------------------------------------------
1377$begin ta_delete_array$$
1378$spell
1379        inuse
1380        thread_alloc
1381        sizeof
1382        deallocate
1383$$
1384
1385$section Deallocate An Array and Call Destructor for its Elements$$
1386$mindex delete_array$$
1387
1388
1389$head Syntax$$
1390$codei%thread_alloc::delete_array(%array%)%$$.
1391
1392$head Purpose$$
1393Returns memory corresponding to an array created by
1394(create by $cref/create_array/ta_create_array/$$) to the
1395$cref/available/ta_available/$$ memory pool for the current thread.
1396
1397$head Type$$
1398The type of the elements of the array.
1399
1400$head array$$
1401The argument $icode array$$ has prototype
1402$codei%
1403        %Type%* %array%
1404%$$
1405It is a value returned by $cref/create_array/ta_create_array/$$ and not yet deleted.
1406The $icode Type$$ destructor is called for each element in the array.
1407
1408$head Thread$$
1409The $cref/current thread/ta_thread_num/$$ must be the
1410same as when $cref/create_array/ta_create_array/$$ returned the value $icode array$$.
1411There is an exception to this rule:
1412when the current execution mode is sequential
1413(not $cref/parallel/ta_in_parallel/$$) the current thread number does not matter.
1414
1415$head Delta$$
1416The amount of memory $cref/inuse/ta_inuse/$$ will decrease by $icode delta$$,
1417and the $cref/available/ta_available/$$ memory will increase by $icode delta$$,
1418where $cref/delta/ta_create_array/Delta/$$
1419is the same as for the corresponding call to $code create_array$$.
1420
1421$head Example$$
1422$cref thread_alloc.cpp$$
1423
1424$end
1425*/
1426        /*!
1427        Return Memory Used for an Array to the Available Pool
1428        (include destructor call for each element).
1429
1430        \tparam Type
1431        The type of the elements of the array.
1432
1433        \param array [in]
1434        A value returned by \c create_array that has not yet been deleted.
1435        The \c Type destructor is used to destroy each of the elements
1436        of the array.
1437
1438        \par
1439        Durring parallel execution, the current thread must be the same
1440        as during the corresponding call to \c create_array.
1441        */
1442        template <class Type>
1443        static void delete_array(Type* array)
1444        {       // determine the number of values in the array
1445                block_t* node = reinterpret_cast<block_t*>(array) - 1;
1446                size_t size     = node->extra_;
1447
1448                // call destructor for each element
1449                size_t i;
1450                for(i = 0; i < size; i++)
1451                        (array + i)->~Type();
1452
1453                // return the memory to the available pool for this thread
1454                thread_alloc::return_memory( reinterpret_cast<void*>(array) );
1455        }
1456/* -----------------------------------------------------------------------
1457$begin ta_free_all$$
1458$spell
1459        alloc
1460        bool
1461        inuse
1462$$
1463
1464$section Free All Memory That Was Allocated for Use by thread_alloc$$
1465
1466
1467$head Syntax$$
1468$icode%ok% = thread_alloc::free_all()%$$.
1469
1470$head Purpose$$
1471Returns all memory that was used by $code thread_alloc$$ to the system.
1472
1473$head ok$$
1474The return value $icode ok$$ has prototype
1475$codei%
1476        bool %ok%
1477%$$
1478Its value will be $code true$$ if all the memory can be freed.
1479This requires that for all $icode thread$$ indices, there is no memory
1480$cref/inuse/ta_inuse/$$; i.e.,
1481$codei%
1482        0 == thread_alloc::inuse(%thread%)
1483%$$
1484Otherwise, the return value will be false.
1485
1486$head Restrictions$$
1487This function cannot be called while in parallel mode.
1488
1489$head Example$$
1490$cref thread_alloc.cpp$$
1491$end
1492*/
1493        /*!
1494        Return to the system all thread_alloc memory that is not currently inuse.
1495
1496        \return
1497        If no \c thread_alloc memory is currently inuse,
1498        all memory is returned to the system and the return value is true.
1499        Otherwise the return value is false.
1500        */
1501        static bool free_all(void)
1502        {       CPPAD_ASSERT_KNOWN(
1503                        ! in_parallel(),
1504                        "free_all cannot be used while in parallel execution"
1505                );
1506                bool ok = true;
1507                size_t thread = CPPAD_MAX_NUM_THREADS;
1508                while(thread--)
1509                {       ok &= inuse(thread) == 0;
1510                        free_available(thread);
1511                }
1512                return ok;
1513        }
1514};
1515
1516
1517} // END_CPPAD_NAMESPACE
1518
1519// preprocessor symbols local to this file
1520# undef CPPAD_MAX_NUM_CAPACITY
1521# undef CPPAD_MIN_DOUBLE_CAPACITY
1522# undef CPPAD_TRACE_CAPACITY
1523# undef CPPAD_TRACE_THREAD
1524# endif
Note: See TracBrowser for help on using the repository browser.