build/stlport/src/lock_free_slist.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright (c) 1997-1999
     3  * Silicon Graphics Computer Systems, Inc.
     4  *
     5  * Copyright (c) 1999
     6  * Boris Fomitchev
     7  *
     8  * This material is provided "as is", with absolutely no warranty expressed
     9  * or implied. Any use is at your own risk.
    10  *
    11  * Permission to use or copy this software for any purpose is hereby granted
    12  * without fee, provided the above notices are retained on all copies.
    13  * Permission to modify the code and to distribute modified code is granted,
    14  * provided the above notices are retained, and a notice that the code was
    15  * modified is included with the above copyright notice.
    16  *
    17  */
    19 #ifndef _STLP_LOCK_FREE_SLIST_H
    20 #define _STLP_LOCK_FREE_SLIST_H
    22 #if defined(_STLP_PTHREADS)
    23 #  include <pthread.h>
    25 #  if defined (__GNUC__) && defined (__i386__)
    27 #    define _STLP_HAS_ATOMIC_FREELIST
    28 /**
    29  * Class that implements a non-blocking and thread-safe freelist.
    30  * It is used for the lock-free node allocation engine.
    31  *
    32  * @author felixw@inin.com
    33  */
    34 class _STLP_atomic_freelist {
    35 public:
    36   /**
    37    * Type representing items of the freelist
    38    */
    39   struct item {
    40     item* _M_next;
    41   };
    43   _STLP_atomic_freelist() {
    44     // Statically assert layout of member is as expected by assembly code
    45     _STLP_STATIC_ASSERT(sizeof(_M) == 8)
    46     _M._M_data._M_top       = 0;
    47     _M._M_data._M_sequence  = 0;
    48   }
    50   /**
    51    * Atomically pushes the specified item onto the freelist.
    52    *
    53    * @param __item [in] Item to add to the front of the list
    54    */
    55   void push(item* __item) {
    56     // NOTE: GCC uses ebx as the PIC register for globals in shared libraries.
    57     //       The GCC version I'm using (3.4.1) won't temporarily spill it if it's
    58     //       used as input, output, or clobber.  Instead, it complains with a
    59     //       "can't find a register in class `BREG' while reloading `asm'" error.
    60     //       This is probably a compiler bug, but as the cmpxchg8b instruction
    61     //       requires ebx, I work around this here by using ecx for the '__item'
    62     //       input and spilling ebx into edi.  This also precludes us from using
    63     //       a "m" operand for the cmpxchg8b argument (GCC might think it can make
    64     //       it relative to ebx).  Instead, we're using esi for the address of _M_data.
    65     //
    66     int __tmp1;     // These dummy variables are used to tell GCC that the eax, ecx,
    67     int __tmp2;     // and edx registers will not have the same value as their input.
    68     int __tmp3;     // The optimizer will remove them as their values are not used.
    69     __asm__ __volatile__
    70       ("       movl       %%ebx, %%edi\n\t"
    71        "       movl       %%ecx, %%ebx\n\t"
    72        "L1_%=: movl       %%eax, (%%ebx)\n\t"     // __item._M_next = _M._M_data._M_top
    73        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
    74        "lock;  cmpxchg8b  (%%esi)\n\t"
    75        "       jne        L1_%=\n\t"              // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
    76        "       movl       %%edi, %%ebx"
    77       :"=a" (__tmp1), "=d" (__tmp2), "=c" (__tmp3)
    78       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "c" (__item), "S" (&_M._M_data)
    79       :"edi", "memory", "cc");
    80   }
    82   /**
    83    * Atomically removes the topmost item from the freelist and returns a
    84    * pointer to it.  Returns NULL if the list is empty.
    85    *
    86    * @return Item that was removed from front of list; NULL if list empty
    87    */
    88   item* pop() {
    89     item*   __result;
    90     int     __tmp;
    91     __asm__ __volatile__
    92       ("       movl       %%ebx, %%edi\n\t"
    93        "L1_%=: testl      %%eax, %%eax\n\t"       // _M_top == NULL?
    94        "       je         L2_%=\n\t"              // If yes, we're done
    95        "       movl       (%%eax), %%ebx\n\t"     // new top = _M._M_data._M_top->_M_next
    96        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
    97        "lock;  cmpxchg8b  (%%esi)\n\t"
    98        "       jne        L1_%=\n\t"              // We failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
    99        "L2_%=: movl       %%edi, %%ebx"
   100       :"=a" (__result), "=d" (__tmp)
   101       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
   102       :"edi", "ecx", "memory", "cc");
   103     return __result;
   104   }
   106   /**
   107    * Atomically detaches all items from the list and returns a pointer to the
   108    * topmost item.  The items are still chained and may be traversed safely as
   109    * they're now "owned" by the calling thread.
   110    *
   111    * @return Pointer to topmost item in the list; NULL if list empty
   112    */
   113   item* clear() {
   114     item*   __result;
   115     int     __tmp;
   116     __asm__ __volatile__
   117       ("       movl       %%ebx, %%edi\n\t"
   118        "L1_%=: testl      %%eax, %%eax\n\t"       // _M_top == NULL?
   119        "       je         L2_%=\n\t"              // If yes, we're done
   120        "       xorl       %%ebx, %%ebx\n\t"       // We're attempting to set _M_top to NULL
   121        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
   122        "lock;  cmpxchg8b  (%%esi)\n\t"
   123        "       jne        L1_%=\n\t"              // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
   124        "L2_%=: movl       %%edi, %%ebx"
   125       :"=a" (__result), "=d" (__tmp)
   126       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
   127       :"edi", "ecx", "memory", "cc");
   128     return __result;
   129   }
   131 private:
   132     union {
   133       long long   _M_align;
   134       struct {
   135         item*           _M_top;         // Topmost element in the freelist
   136         unsigned int    _M_sequence;    // Sequence counter to prevent "ABA problem"
   137       } _M_data;
   138     } _M;
   140   _STLP_atomic_freelist(const _STLP_atomic_freelist&);
   141   _STLP_atomic_freelist& operator=(const _STLP_atomic_freelist&);
   142 };
   144 #  endif /* if defined(__GNUC__) && defined(__i386__) */
   146 #elif defined (_STLP_WIN32THREADS)
   148 #  if !defined (_WIN64)
   149 #    define _STLP_USE_ASM_IMPLEMENTATION
   150 #  endif
   152 // Here are the compiler/platform requirements for the thread safe and
   153 // lock free singly linked list implementation:
   154 #  if defined (_STLP_USE_ASM_IMPLEMENTATION)
   155 // For the asm version:
   156 #    if defined (_STLP_MSVC) && defined (_M_IX86) && (_M_IX86 >= 500)
   157 #      define _STLP_HAS_ATOMIC_FREELIST
   158 #    endif
   159 #  else
   160 // For the API based version:
   161 #    if defined (_STLP_NEW_PLATFORM_SDK) && (!defined (WINVER) || (WINVER >= 0x0501)) && \
   162                                             (!defined (_WIN32_WINNT) || (_WIN32_WINNT >= 0x0501))
   163 #      define _STLP_HAS_ATOMIC_FREELIST
   164 #    endif
   165 #  endif
   167 #  if defined (_STLP_HAS_ATOMIC_FREELIST)
   168 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   169 #      if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
   170 #        pragma warning (push)
   171 #        pragma warning (disable : 4035) //function has no return value
   172 #      endif
   173 #    endif
   174 /**
   175  * Class that implements a non-blocking and thread-safe freelist.
   176  * It is used for the lock-free node allocation engine.
   177  *
   178  * @author felixw@inin.com
   179  */
   180 class _STLP_atomic_freelist {
   181 public:
   182   /**
   183    * Type representing items of the freelist
   184    */
   185 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   186   struct item {
   187       item*   _M_next;
   188   };
   189 #    else
   190   typedef SLIST_ENTRY item;
   191 #    endif
   193   _STLP_atomic_freelist() {
   194     // Statically assert layout of member is as expected by assembly code
   195 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   196     _STLP_STATIC_ASSERT((sizeof(item) == sizeof(item*)) && (sizeof(_M) == 8))
   197     _M._M_data._M_top       = 0;
   198     _M._M_data._M_sequence  = 0;
   199 #    else
   200     InitializeSListHead(&_M_head);
   201 #    endif
   202   }
   204   /**
   205    * Atomically pushes the specified item onto the freelist.
   206    *
   207    * @param __item [in] Item to add to the front of the list
   208    */
   209   void push(item* __item) {
   210 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   211     __asm
   212     {
   213         mov             esi, this
   214         mov             ebx, __item
   215         mov             eax, [esi]              // _M._M_data._M_top
   216         mov             edx, [esi+4]            // _M._M_data._M_sequence
   217     L1: mov             [ebx], eax              // __item._M_next = _M._M_data._M_top
   218         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
   219         lock cmpxchg8b  qword ptr [esi]
   220         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
   221     }
   222 #    else
   223     InterlockedPushEntrySList(&_M_head, __item);
   224 #    endif
   225   }
   227   /**
   228    * Atomically removes the topmost item from the freelist and returns a
   229    * pointer to it.  Returns NULL if the list is empty.
   230    *
   231    * @return Item that was removed from front of list; NULL if list empty
   232    */
   233   item* pop() {
   234 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   235     __asm
   236     {
   237         mov             esi, this
   238         mov             eax, [esi]              // _M._M_data._M_top
   239         mov             edx, [esi+4]            // _M._M_data._M_sequence
   240     L1: test            eax, eax                // _M_top == NULL?
   241         je              L2                      // Yes, we're done
   242         mov             ebx, [eax]              // new top = _M._M_data._M_top->_M_next
   243         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
   244         lock cmpxchg8b  qword ptr [esi]
   245         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
   246     L2:
   247     }
   248 #    else
   249     return InterlockedPopEntrySList(&_M_head);
   250 #    endif
   251   }
   253   /**
   254    * Atomically detaches all items from the list and returns pointer to the
   255    * topmost.  The items are still chained and may be traversed safely as
   256    * they're now "owned" by the calling thread.
   257    *
   258    * @return Pointer to topmost item in the list; NULL if list empty
   259    */
   260   item* clear() {
   261 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   262     __asm
   263     {
   264         mov             esi, this
   265         mov             eax, [esi]              // _M._M_data._M_top
   266         mov             edx, [esi+4]            // _M._M_data._M_sequence
   267     L1: test            eax, eax                // _M_top == NULL?
   268         je              L2                      // Yes, we're done
   269         xor             ebx,ebx                 // We're attempting to set _M._M_data._M_top to NULL
   270         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
   271         lock cmpxchg8b  qword ptr [esi]
   272         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
   273     L2:
   274     }
   275 #    else
   276     return InterlockedFlushSList(&_M_head);
   277 #    endif
   278   }
   280 private:
   281 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   282   union {
   283     __int64     _M_align;
   284     struct {
   285       item*           _M_top;         // Topmost element in the freelist
   286       unsigned int    _M_sequence;    // Sequence counter to prevent "ABA problem"
   287     } _M_data;
   288   } _M;
   289 #    else
   290   SLIST_HEADER _M_head;
   291 #    endif
   293   _STLP_atomic_freelist(const _STLP_atomic_freelist&);
   294   _STLP_atomic_freelist& operator = (const _STLP_atomic_freelist&);
   295 };
   297 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
   298 #      if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
   299 #        pragma warning (pop)
   300 #      endif
   301 #    endif
   303 #  endif /* _STLP_HAS_ATOMIC_FREELIST */
   305 #endif
   307 #endif /* _STLP_LOCK_FREE_SLIST_H */

mercurial