104e0dc4aSTimo Kreuzer /***
204e0dc4aSTimo Kreuzer *localref.c - Contains the __[add|remove]localeref() functions.
304e0dc4aSTimo Kreuzer *
404e0dc4aSTimo Kreuzer *       Copyright (c) Microsoft Corporation.  All rights reserved.
504e0dc4aSTimo Kreuzer *
604e0dc4aSTimo Kreuzer *Purpose:
704e0dc4aSTimo Kreuzer *       Contains the __[add|remove]localeref() functions.
804e0dc4aSTimo Kreuzer *
904e0dc4aSTimo Kreuzer *******************************************************************************/
1004e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
1104e0dc4aSTimo Kreuzer #include <locale.h>
1204e0dc4aSTimo Kreuzer 
1304e0dc4aSTimo Kreuzer 
1404e0dc4aSTimo Kreuzer 
1504e0dc4aSTimo Kreuzer /***
1604e0dc4aSTimo Kreuzer * __acrt_add_locale_ref(__crt_locale_data* ptloci)
1704e0dc4aSTimo Kreuzer *
1804e0dc4aSTimo Kreuzer * Purpose:
1904e0dc4aSTimo Kreuzer *       Increment the refrence count for each element in the localeinfo struct.
2004e0dc4aSTimo Kreuzer *
2104e0dc4aSTimo Kreuzer *******************************************************************************/
__acrt_add_locale_ref(__crt_locale_data * ptloci)2204e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_add_locale_ref(__crt_locale_data* ptloci)
2304e0dc4aSTimo Kreuzer {
2404e0dc4aSTimo Kreuzer     _InterlockedIncrement(&ptloci->refcount);
2504e0dc4aSTimo Kreuzer 
2604e0dc4aSTimo Kreuzer     if (ptloci->lconv_intl_refcount != nullptr)
2704e0dc4aSTimo Kreuzer     {
2804e0dc4aSTimo Kreuzer         _InterlockedIncrement(ptloci->lconv_intl_refcount);
2904e0dc4aSTimo Kreuzer     }
3004e0dc4aSTimo Kreuzer 
3104e0dc4aSTimo Kreuzer     if (ptloci->lconv_mon_refcount != nullptr)
3204e0dc4aSTimo Kreuzer     {
3304e0dc4aSTimo Kreuzer         _InterlockedIncrement(ptloci->lconv_mon_refcount);
3404e0dc4aSTimo Kreuzer     }
3504e0dc4aSTimo Kreuzer 
3604e0dc4aSTimo Kreuzer     if (ptloci->lconv_num_refcount != nullptr)
3704e0dc4aSTimo Kreuzer     {
3804e0dc4aSTimo Kreuzer         _InterlockedIncrement(ptloci->lconv_num_refcount);
3904e0dc4aSTimo Kreuzer     }
4004e0dc4aSTimo Kreuzer 
4104e0dc4aSTimo Kreuzer     if (ptloci->ctype1_refcount != nullptr)
4204e0dc4aSTimo Kreuzer     {
4304e0dc4aSTimo Kreuzer         _InterlockedIncrement(ptloci->ctype1_refcount);
4404e0dc4aSTimo Kreuzer     }
4504e0dc4aSTimo Kreuzer 
4604e0dc4aSTimo Kreuzer     for (int category = LC_MIN; category <= LC_MAX; ++category)
4704e0dc4aSTimo Kreuzer     {
4804e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].wlocale != __acrt_wide_c_locale_string &&
4904e0dc4aSTimo Kreuzer             ptloci->lc_category[category].wrefcount != nullptr)
5004e0dc4aSTimo Kreuzer         {
5104e0dc4aSTimo Kreuzer             _InterlockedIncrement(ptloci->lc_category[category].wrefcount);
5204e0dc4aSTimo Kreuzer         }
5304e0dc4aSTimo Kreuzer 
5404e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].locale != nullptr &&
5504e0dc4aSTimo Kreuzer             ptloci->lc_category[category].refcount != nullptr)
5604e0dc4aSTimo Kreuzer         {
5704e0dc4aSTimo Kreuzer             _InterlockedIncrement(ptloci->lc_category[category].refcount);
5804e0dc4aSTimo Kreuzer         }
5904e0dc4aSTimo Kreuzer     }
6004e0dc4aSTimo Kreuzer 
6104e0dc4aSTimo Kreuzer     __acrt_locale_add_lc_time_reference(ptloci->lc_time_curr);
6204e0dc4aSTimo Kreuzer }
6304e0dc4aSTimo Kreuzer 
6404e0dc4aSTimo Kreuzer /***
6504e0dc4aSTimo Kreuzer * __acrt_release_locale_ref(__crt_locale_data* ptloci)
6604e0dc4aSTimo Kreuzer *
6704e0dc4aSTimo Kreuzer * Purpose:
6804e0dc4aSTimo Kreuzer *       Decrement the refrence count for each elemnt in the localeinfo struct.
6904e0dc4aSTimo Kreuzer *
7004e0dc4aSTimo Kreuzer ******************************************************************************/
__acrt_release_locale_ref(__crt_locale_data * ptloci)7104e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_release_locale_ref(__crt_locale_data* ptloci)
7204e0dc4aSTimo Kreuzer {
7304e0dc4aSTimo Kreuzer     if (ptloci == nullptr)
7404e0dc4aSTimo Kreuzer         return;
7504e0dc4aSTimo Kreuzer 
7604e0dc4aSTimo Kreuzer     _InterlockedDecrement(&ptloci->refcount);
7704e0dc4aSTimo Kreuzer 
7804e0dc4aSTimo Kreuzer     if (ptloci->lconv_intl_refcount != nullptr)
7904e0dc4aSTimo Kreuzer         _InterlockedDecrement(ptloci->lconv_intl_refcount);
8004e0dc4aSTimo Kreuzer 
8104e0dc4aSTimo Kreuzer     if (ptloci->lconv_mon_refcount != nullptr)
8204e0dc4aSTimo Kreuzer         _InterlockedDecrement(ptloci->lconv_mon_refcount);
8304e0dc4aSTimo Kreuzer 
8404e0dc4aSTimo Kreuzer     if (ptloci->lconv_num_refcount != nullptr)
8504e0dc4aSTimo Kreuzer         _InterlockedDecrement(ptloci->lconv_num_refcount);
8604e0dc4aSTimo Kreuzer 
8704e0dc4aSTimo Kreuzer     if (ptloci->ctype1_refcount != nullptr)
8804e0dc4aSTimo Kreuzer         _InterlockedDecrement(ptloci->ctype1_refcount);
8904e0dc4aSTimo Kreuzer 
9004e0dc4aSTimo Kreuzer     for (int category = LC_MIN; category <= LC_MAX; ++category)
9104e0dc4aSTimo Kreuzer     {
9204e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].wlocale != __acrt_wide_c_locale_string &&
9304e0dc4aSTimo Kreuzer             ptloci->lc_category[category].wrefcount != nullptr)
9404e0dc4aSTimo Kreuzer         {
9504e0dc4aSTimo Kreuzer             _InterlockedDecrement(ptloci->lc_category[category].wrefcount);
9604e0dc4aSTimo Kreuzer         }
9704e0dc4aSTimo Kreuzer 
9804e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].locale != nullptr &&
9904e0dc4aSTimo Kreuzer             ptloci->lc_category[category].refcount != nullptr)
10004e0dc4aSTimo Kreuzer         {
10104e0dc4aSTimo Kreuzer             _InterlockedDecrement(ptloci->lc_category[category].refcount);
10204e0dc4aSTimo Kreuzer         }
10304e0dc4aSTimo Kreuzer     }
10404e0dc4aSTimo Kreuzer 
10504e0dc4aSTimo Kreuzer     __acrt_locale_release_lc_time_reference(ptloci->lc_time_curr);
10604e0dc4aSTimo Kreuzer }
10704e0dc4aSTimo Kreuzer 
10804e0dc4aSTimo Kreuzer 
10904e0dc4aSTimo Kreuzer /***
11004e0dc4aSTimo Kreuzer *__acrt_free_locale() - free __crt_locale_data
11104e0dc4aSTimo Kreuzer *
11204e0dc4aSTimo Kreuzer *Purpose:
11304e0dc4aSTimo Kreuzer *       Free up the per-thread locale info structure specified by the passed
11404e0dc4aSTimo Kreuzer *       pointer.
11504e0dc4aSTimo Kreuzer *
11604e0dc4aSTimo Kreuzer *Entry:
11704e0dc4aSTimo Kreuzer *       __crt_locale_data* ptloci
11804e0dc4aSTimo Kreuzer *
11904e0dc4aSTimo Kreuzer *Exit:
12004e0dc4aSTimo Kreuzer *
12104e0dc4aSTimo Kreuzer *Exceptions:
12204e0dc4aSTimo Kreuzer *
12304e0dc4aSTimo Kreuzer *******************************************************************************/
12404e0dc4aSTimo Kreuzer 
__acrt_free_locale(__crt_locale_data * ptloci)12504e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_free_locale(__crt_locale_data* ptloci)
12604e0dc4aSTimo Kreuzer {
12704e0dc4aSTimo Kreuzer     /*
12804e0dc4aSTimo Kreuzer      * Free up lconv struct
12904e0dc4aSTimo Kreuzer      */
13004e0dc4aSTimo Kreuzer     if (ptloci->lconv != nullptr &&
13104e0dc4aSTimo Kreuzer         ptloci->lconv != &__acrt_lconv_c &&
13204e0dc4aSTimo Kreuzer         ptloci->lconv_intl_refcount != nullptr &&
13304e0dc4aSTimo Kreuzer         *ptloci->lconv_intl_refcount == 0)
13404e0dc4aSTimo Kreuzer     {
13504e0dc4aSTimo Kreuzer         if (ptloci->lconv_mon_refcount != nullptr && *ptloci->lconv_mon_refcount == 0)
13604e0dc4aSTimo Kreuzer         {
13704e0dc4aSTimo Kreuzer             _free_crt(ptloci->lconv_mon_refcount);
13804e0dc4aSTimo Kreuzer             __acrt_locale_free_monetary(ptloci->lconv);
13904e0dc4aSTimo Kreuzer         }
14004e0dc4aSTimo Kreuzer 
14104e0dc4aSTimo Kreuzer         if (ptloci->lconv_num_refcount != nullptr && *ptloci->lconv_num_refcount == 0)
14204e0dc4aSTimo Kreuzer         {
14304e0dc4aSTimo Kreuzer             _free_crt(ptloci->lconv_num_refcount);
14404e0dc4aSTimo Kreuzer             __acrt_locale_free_numeric(ptloci->lconv);
14504e0dc4aSTimo Kreuzer         }
14604e0dc4aSTimo Kreuzer 
14704e0dc4aSTimo Kreuzer         _free_crt(ptloci->lconv_intl_refcount);
14804e0dc4aSTimo Kreuzer         _free_crt(ptloci->lconv);
14904e0dc4aSTimo Kreuzer     }
15004e0dc4aSTimo Kreuzer 
15104e0dc4aSTimo Kreuzer     /*
15204e0dc4aSTimo Kreuzer      * Free up ctype tables
15304e0dc4aSTimo Kreuzer      */
15404e0dc4aSTimo Kreuzer     if (ptloci->ctype1_refcount != nullptr && *ptloci->ctype1_refcount == 0)
15504e0dc4aSTimo Kreuzer     {
15604e0dc4aSTimo Kreuzer         _free_crt(ptloci->ctype1 - _COFFSET);
15704e0dc4aSTimo Kreuzer         _free_crt(const_cast<unsigned char*>(ptloci->pclmap - _COFFSET - 1));
15804e0dc4aSTimo Kreuzer         _free_crt(const_cast<unsigned char*>(ptloci->pcumap - _COFFSET - 1));
15904e0dc4aSTimo Kreuzer         _free_crt(ptloci->ctype1_refcount);
16004e0dc4aSTimo Kreuzer     }
16104e0dc4aSTimo Kreuzer 
16204e0dc4aSTimo Kreuzer     __acrt_locale_free_lc_time_if_unreferenced(ptloci->lc_time_curr);
16304e0dc4aSTimo Kreuzer 
16404e0dc4aSTimo Kreuzer     for (int category = LC_MIN; category <= LC_MAX; ++category)
16504e0dc4aSTimo Kreuzer     {
16604e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].wlocale != __acrt_wide_c_locale_string &&
16704e0dc4aSTimo Kreuzer             ptloci->lc_category[category].wrefcount != nullptr &&
16804e0dc4aSTimo Kreuzer             *ptloci->lc_category[category].wrefcount == 0)
16904e0dc4aSTimo Kreuzer         {
17004e0dc4aSTimo Kreuzer             _free_crt(ptloci->lc_category[category].wrefcount);
17104e0dc4aSTimo Kreuzer             _free_crt(ptloci->locale_name[category]);
17204e0dc4aSTimo Kreuzer         }
17304e0dc4aSTimo Kreuzer 
17404e0dc4aSTimo Kreuzer         _ASSERTE((ptloci->lc_category[category].locale != nullptr && ptloci->lc_category[category].refcount != nullptr) ||
17504e0dc4aSTimo Kreuzer                  (ptloci->lc_category[category].locale == nullptr && ptloci->lc_category[category].refcount == nullptr));
17604e0dc4aSTimo Kreuzer 
17704e0dc4aSTimo Kreuzer         if (ptloci->lc_category[category].locale != nullptr &&
17804e0dc4aSTimo Kreuzer             ptloci->lc_category[category].refcount != nullptr &&
17904e0dc4aSTimo Kreuzer             *ptloci->lc_category[category].refcount == 0)
18004e0dc4aSTimo Kreuzer         {
18104e0dc4aSTimo Kreuzer             _free_crt(ptloci->lc_category[category].refcount);
18204e0dc4aSTimo Kreuzer         }
18304e0dc4aSTimo Kreuzer     }
18404e0dc4aSTimo Kreuzer 
18504e0dc4aSTimo Kreuzer     /*
18604e0dc4aSTimo Kreuzer      * Free up the __crt_locale_data struct
18704e0dc4aSTimo Kreuzer      */
18804e0dc4aSTimo Kreuzer     _free_crt(ptloci);
18904e0dc4aSTimo Kreuzer }
19004e0dc4aSTimo Kreuzer 
19104e0dc4aSTimo Kreuzer 
19204e0dc4aSTimo Kreuzer /***
19304e0dc4aSTimo Kreuzer *
19404e0dc4aSTimo Kreuzer * _updatelocinfoEx_nolock(__crt_locale_data* *pptlocid, __crt_locale_data* ptlocis)
19504e0dc4aSTimo Kreuzer *
19604e0dc4aSTimo Kreuzer * Purpose:
19704e0dc4aSTimo Kreuzer *       Update *pptlocid to ptlocis. This might include freeing contents of *pptlocid.
19804e0dc4aSTimo Kreuzer *
19904e0dc4aSTimo Kreuzer ******************************************************************************/
_updatetlocinfoEx_nolock(__crt_locale_data ** pptlocid,__crt_locale_data * ptlocis)20004e0dc4aSTimo Kreuzer extern "C" __crt_locale_data* __cdecl _updatetlocinfoEx_nolock(
20104e0dc4aSTimo Kreuzer     __crt_locale_data** pptlocid,
20204e0dc4aSTimo Kreuzer     __crt_locale_data*  ptlocis
20304e0dc4aSTimo Kreuzer     )
20404e0dc4aSTimo Kreuzer {
20504e0dc4aSTimo Kreuzer     if (ptlocis == nullptr || pptlocid == nullptr)
20604e0dc4aSTimo Kreuzer         return nullptr;
20704e0dc4aSTimo Kreuzer 
20804e0dc4aSTimo Kreuzer     __crt_locale_data* const ptloci = *pptlocid;
20904e0dc4aSTimo Kreuzer     if (ptloci == ptlocis)
21004e0dc4aSTimo Kreuzer         return ptlocis;
21104e0dc4aSTimo Kreuzer 
21204e0dc4aSTimo Kreuzer     /*
21304e0dc4aSTimo Kreuzer     * Update to the current locale info structure and increment the
21404e0dc4aSTimo Kreuzer     * reference counts.
21504e0dc4aSTimo Kreuzer     */
21604e0dc4aSTimo Kreuzer     *pptlocid = ptlocis;
21704e0dc4aSTimo Kreuzer     __acrt_add_locale_ref(ptlocis);
21804e0dc4aSTimo Kreuzer 
21904e0dc4aSTimo Kreuzer     /*
22004e0dc4aSTimo Kreuzer     * Decrement the reference counts in the old locale info
22104e0dc4aSTimo Kreuzer     * structure.
22204e0dc4aSTimo Kreuzer     */
22304e0dc4aSTimo Kreuzer     if (ptloci != nullptr)
22404e0dc4aSTimo Kreuzer     {
22504e0dc4aSTimo Kreuzer         __acrt_release_locale_ref(ptloci);
22604e0dc4aSTimo Kreuzer     }
22704e0dc4aSTimo Kreuzer 
22804e0dc4aSTimo Kreuzer     /*
22904e0dc4aSTimo Kreuzer     * Free the old locale info structure, if necessary.  Must be done
23004e0dc4aSTimo Kreuzer     * after incrementing reference counts in current locale in case
23104e0dc4aSTimo Kreuzer     * any refcounts are shared with the old locale.
23204e0dc4aSTimo Kreuzer     */
23304e0dc4aSTimo Kreuzer     if (ptloci != nullptr &&
23404e0dc4aSTimo Kreuzer         ptloci->refcount == 0 &&
23504e0dc4aSTimo Kreuzer         ptloci != &__acrt_initial_locale_data)
23604e0dc4aSTimo Kreuzer     {
23704e0dc4aSTimo Kreuzer         __acrt_free_locale(ptloci);
23804e0dc4aSTimo Kreuzer     }
23904e0dc4aSTimo Kreuzer 
24004e0dc4aSTimo Kreuzer     return ptlocis;
24104e0dc4aSTimo Kreuzer }
24204e0dc4aSTimo Kreuzer 
24304e0dc4aSTimo Kreuzer 
24404e0dc4aSTimo Kreuzer /***
24504e0dc4aSTimo Kreuzer *__acrt_update_thread_locale_data() - refresh the thread's locale info
24604e0dc4aSTimo Kreuzer *
24704e0dc4aSTimo Kreuzer *Purpose:
24804e0dc4aSTimo Kreuzer *       If this thread does not have it's ownlocale which means that either
24904e0dc4aSTimo Kreuzer *       ownlocale flag in ptd is not set or ptd->ptloci == nullptr, then Update
25004e0dc4aSTimo Kreuzer *       the current thread's reference to the locale information to match the
25104e0dc4aSTimo Kreuzer *       current global locale info. Decrement the reference on the old locale
25204e0dc4aSTimo Kreuzer *       information struct and if this count is now zero (so that no threads
25304e0dc4aSTimo Kreuzer *       are using it), free it.
25404e0dc4aSTimo Kreuzer *
25504e0dc4aSTimo Kreuzer *Entry:
25604e0dc4aSTimo Kreuzer *
25704e0dc4aSTimo Kreuzer *Exit:
25804e0dc4aSTimo Kreuzer *
25904e0dc4aSTimo Kreuzer *       if (!_getptd()->ownlocale || _getptd()->ptlocinfo == nullptr)
26004e0dc4aSTimo Kreuzer *           _getptd()->ptlocinfo == __acrt_current_locale_data
26104e0dc4aSTimo Kreuzer *       else
26204e0dc4aSTimo Kreuzer *           _getptd()->ptlocinfo
26304e0dc4aSTimo Kreuzer *
26404e0dc4aSTimo Kreuzer *Exceptions:
26504e0dc4aSTimo Kreuzer *
26604e0dc4aSTimo Kreuzer *******************************************************************************/
__acrt_update_thread_locale_data()26704e0dc4aSTimo Kreuzer extern "C" __crt_locale_data* __cdecl __acrt_update_thread_locale_data()
26804e0dc4aSTimo Kreuzer {
26904e0dc4aSTimo Kreuzer     __crt_locale_data* ptloci = nullptr;
27004e0dc4aSTimo Kreuzer     __acrt_ptd* const ptd = __acrt_getptd();
27104e0dc4aSTimo Kreuzer 
27204e0dc4aSTimo Kreuzer     if (__acrt_should_sync_with_global_locale(ptd) || ptd->_locale_info == nullptr)
27304e0dc4aSTimo Kreuzer     {
27404e0dc4aSTimo Kreuzer         __acrt_lock(__acrt_locale_lock);
27504e0dc4aSTimo Kreuzer         __try
27604e0dc4aSTimo Kreuzer         {
27704e0dc4aSTimo Kreuzer             ptloci = _updatetlocinfoEx_nolock(&ptd->_locale_info, __acrt_current_locale_data.value());
27804e0dc4aSTimo Kreuzer         }
27904e0dc4aSTimo Kreuzer         __finally
28004e0dc4aSTimo Kreuzer         {
28104e0dc4aSTimo Kreuzer             __acrt_unlock(__acrt_locale_lock);
28204e0dc4aSTimo Kreuzer         }
283*e98e9000STimo Kreuzer         __endtry
28404e0dc4aSTimo Kreuzer     }
28504e0dc4aSTimo Kreuzer     else
28604e0dc4aSTimo Kreuzer     {
28704e0dc4aSTimo Kreuzer         ptloci = ptd->_locale_info;
28804e0dc4aSTimo Kreuzer     }
28904e0dc4aSTimo Kreuzer 
29004e0dc4aSTimo Kreuzer     if (!ptloci)
29104e0dc4aSTimo Kreuzer     {
29204e0dc4aSTimo Kreuzer         abort();
29304e0dc4aSTimo Kreuzer     }
29404e0dc4aSTimo Kreuzer 
29504e0dc4aSTimo Kreuzer     return ptloci;
29604e0dc4aSTimo Kreuzer }
29704e0dc4aSTimo Kreuzer 
29804e0dc4aSTimo Kreuzer 
29904e0dc4aSTimo Kreuzer 
30004e0dc4aSTimo Kreuzer //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30104e0dc4aSTimo Kreuzer //
30204e0dc4aSTimo Kreuzer // __crt_lc_time_data reference counting
30304e0dc4aSTimo Kreuzer //
30404e0dc4aSTimo Kreuzer //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30504e0dc4aSTimo Kreuzer // The C locale lc_time data is immutable and persistent.  The lc_time data for
30604e0dc4aSTimo Kreuzer // any other locale is dynamically allocated (and thus not actually immutable).
30704e0dc4aSTimo Kreuzer // The lc_time_curr data member of __crt_locale_data is declared const to help
30804e0dc4aSTimo Kreuzer // ensure that code does not accidentally attempt to modify the C locale lc_time
30904e0dc4aSTimo Kreuzer // data.
31004e0dc4aSTimo Kreuzer //
31104e0dc4aSTimo Kreuzer // These functions encapsulate all mutation of the lc_time_curr.  They accept a
31204e0dc4aSTimo Kreuzer // __crt_lc_time_data const*, handle the C locale as a special case, then cast
31304e0dc4aSTimo Kreuzer // away constness to mutate the lc_time data.
__acrt_locale_add_lc_time_reference(__crt_lc_time_data const * const lc_time)31404e0dc4aSTimo Kreuzer extern "C" long __cdecl __acrt_locale_add_lc_time_reference(
31504e0dc4aSTimo Kreuzer     __crt_lc_time_data const* const lc_time
31604e0dc4aSTimo Kreuzer     )
31704e0dc4aSTimo Kreuzer {
31804e0dc4aSTimo Kreuzer     if (lc_time == nullptr || lc_time == &__lc_time_c)
31904e0dc4aSTimo Kreuzer     {
32004e0dc4aSTimo Kreuzer         return LONG_MAX;
32104e0dc4aSTimo Kreuzer     }
32204e0dc4aSTimo Kreuzer 
32304e0dc4aSTimo Kreuzer     return _InterlockedIncrement(&const_cast<__crt_lc_time_data*>(lc_time)->refcount);
32404e0dc4aSTimo Kreuzer }
32504e0dc4aSTimo Kreuzer 
__acrt_locale_release_lc_time_reference(__crt_lc_time_data const * const lc_time)32604e0dc4aSTimo Kreuzer extern "C" long __cdecl __acrt_locale_release_lc_time_reference(
32704e0dc4aSTimo Kreuzer     __crt_lc_time_data const* const lc_time
32804e0dc4aSTimo Kreuzer     )
32904e0dc4aSTimo Kreuzer {
33004e0dc4aSTimo Kreuzer     if (lc_time == nullptr || lc_time == &__lc_time_c)
33104e0dc4aSTimo Kreuzer     {
33204e0dc4aSTimo Kreuzer         return LONG_MAX;
33304e0dc4aSTimo Kreuzer     }
33404e0dc4aSTimo Kreuzer 
33504e0dc4aSTimo Kreuzer     return _InterlockedDecrement(&const_cast<__crt_lc_time_data*>(lc_time)->refcount);
33604e0dc4aSTimo Kreuzer }
33704e0dc4aSTimo Kreuzer 
__acrt_locale_free_lc_time_if_unreferenced(__crt_lc_time_data const * const lc_time)33804e0dc4aSTimo Kreuzer extern "C" void __cdecl __acrt_locale_free_lc_time_if_unreferenced(
33904e0dc4aSTimo Kreuzer     __crt_lc_time_data const* const lc_time
34004e0dc4aSTimo Kreuzer     )
34104e0dc4aSTimo Kreuzer {
34204e0dc4aSTimo Kreuzer     if (lc_time == nullptr || lc_time == &__lc_time_c)
34304e0dc4aSTimo Kreuzer     {
34404e0dc4aSTimo Kreuzer         return;
34504e0dc4aSTimo Kreuzer     }
34604e0dc4aSTimo Kreuzer 
34704e0dc4aSTimo Kreuzer     if (__crt_interlocked_read(&lc_time->refcount) != 0)
34804e0dc4aSTimo Kreuzer     {
34904e0dc4aSTimo Kreuzer         return;
35004e0dc4aSTimo Kreuzer     }
35104e0dc4aSTimo Kreuzer 
35204e0dc4aSTimo Kreuzer     __acrt_locale_free_time(const_cast<__crt_lc_time_data*>(lc_time));
35304e0dc4aSTimo Kreuzer     _free_crt(const_cast<__crt_lc_time_data*>(lc_time));
35404e0dc4aSTimo Kreuzer }
355