pthread-once.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  16. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  17. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  18. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  19. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  21. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  22. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  23. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  25. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. */
  28. #include <errno.h>
  29. #include <pthread.h>
  30. #include <unistd.h>
  31. #if defined(__arm__)
  32. /* The file only exists for ARM, for now */
  33. #include <machine/cpu-features.h>
  34. #endif
  35. /* Adapted from bionic_atomic_inline.h */
  36. static inline void ANDROID_MEMBAR_FULL(void) {
  37. #if defined(__arm__) && __ARM_ARCH__ >= 7
  38. __asm__ __volatile__ ("dmb" ::: "memory");
  39. #elif defined(__arm__) && __ARM_ARCH__ == 6
  40. /*
  41. * See "Accessing the Data Memory Barrier operation" :
  42. * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211i/I1014942.html
  43. *
  44. * From: https://casper.berkeley.edu/svn/trunk/roach/sw/linux/include/asm-arm/system.h
  45. */
  46. __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" :: "r" (0) : "memory");
  47. #elif (defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)
  48. __asm__ __volatile__ ("mfence" ::: "memory");
  49. #else
  50. /*
  51. * Implementation not defined for this platform. Hopefully we're building
  52. * in uniprocessor mode.
  53. *
  54. * For example: MIPS, PowerPC, ARMv5, etc
  55. */
  56. __asm__ __volatile__ ("" ::: "memory");
  57. #endif
  58. }
  59. /* NOTE: this implementation doesn't support a init function that throws a C++ exception
  60. * or calls fork()
  61. */
  62. int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) )
  63. {
  64. if( once_control == NULL || init_routine == NULL )
  65. return EINVAL;
  66. static pthread_mutex_t once_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
  67. volatile pthread_once_t* ocptr = once_control;
  68. pthread_once_t tmp = *ocptr;
  69. ANDROID_MEMBAR_FULL();
  70. if (tmp == PTHREAD_ONCE_INIT) {
  71. pthread_mutex_lock( &once_lock );
  72. if (*ocptr == PTHREAD_ONCE_INIT) {
  73. (*init_routine)();
  74. ANDROID_MEMBAR_FULL();
  75. *ocptr = ~PTHREAD_ONCE_INIT;
  76. }
  77. pthread_mutex_unlock( &once_lock );
  78. }
  79. return 0;
  80. }