~ubuntu-branches/ubuntu/quantal/uclibc/quantal

« back to all changes in this revision

Viewing changes to libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c

  • Committer: Bazaar Package Importer
  • Author(s): Hector Oron
  • Date: 2011-06-11 03:06:20 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110611030620-ywjfvyuqvrpsm282
Tags: 0.9.32-1
* New upstream release
* Add myself as maintainer
* Bump standards version 
* Add Vcs-Git, Vcs-Browser and Homepage fields
* Add watch file 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
 
2
   This file is part of the GNU C Library.
 
3
 
 
4
   The GNU C Library is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU Lesser General Public
 
6
   License as published by the Free Software Foundation; either
 
7
   version 2.1 of the License, or (at your option) any later version.
 
8
 
 
9
   The GNU C Library is distributed in the hope that it will be useful,
 
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
   Lesser General Public License for more details.
 
13
 
 
14
   You should have received a copy of the GNU Lesser General Public
 
15
   License along with the GNU C Library; if not, write to the Free
 
16
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 
17
   02111-1307 USA.  */
 
18
 
 
19
#include "pthreadP.h"
 
20
#include <lowlevellock.h>
 
21
 
 
22
 
 
23
unsigned long int __fork_generation attribute_hidden;
 
24
 
 
25
static void
 
26
clear_once_control (void *arg)
 
27
{
 
28
  pthread_once_t *once_control = (pthread_once_t *) arg;
 
29
 
 
30
  *once_control = 0;
 
31
  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
 
32
}
 
33
 
 
34
int
 
35
attribute_protected
 
36
__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
 
37
{
 
38
  for (;;)
 
39
    {
 
40
      int oldval;
 
41
      int newval;
 
42
      int tmp;
 
43
 
 
44
      /* Pseudo code:
 
45
         newval = __fork_generation | 1;
 
46
         oldval = *once_control;
 
47
         if ((oldval & 2) == 0)
 
48
           *once_control = newval;
 
49
         Do this atomically.
 
50
      */
 
51
      newval = __fork_generation | 1;
 
52
      __asm__ __volatile__ (
 
53
                "1:     ldl_l   %0, %2\n"
 
54
                "       and     %0, 2, %1\n"
 
55
                "       bne     %1, 2f\n"
 
56
                "       mov     %3, %1\n"
 
57
                "       stl_c   %1, %2\n"
 
58
                "       beq     %1, 1b\n"
 
59
                "2:     mb"
 
60
                : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control)
 
61
                : "r" (newval), "m" (*once_control));
 
62
 
 
63
      /* Check if the initializer has already been done.  */
 
64
      if ((oldval & 2) != 0)
 
65
        return 0;
 
66
 
 
67
      /* Check if another thread already runs the initializer.  */
 
68
      if ((oldval & 1) == 0)
 
69
        break;
 
70
 
 
71
      /* Check whether the initializer execution was interrupted by a fork.  */
 
72
      if (oldval != newval)
 
73
        break;
 
74
 
 
75
      /* Same generation, some other thread was faster. Wait.  */
 
76
      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
 
77
    }
 
78
 
 
79
  /* This thread is the first here.  Do the initialization.
 
80
     Register a cleanup handler so that in case the thread gets
 
81
     interrupted the initialization can be restarted.  */
 
82
  pthread_cleanup_push (clear_once_control, once_control);
 
83
 
 
84
  init_routine ();
 
85
 
 
86
  pthread_cleanup_pop (0);
 
87
 
 
88
  /* Add one to *once_control to take the bottom 2 bits from 01 to 10.  */
 
89
  atomic_increment (once_control);
 
90
 
 
91
  /* Wake up all other threads.  */
 
92
  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
 
93
 
 
94
  return 0;
 
95
}
 
96
weak_alias (__pthread_once, pthread_once)
 
97
strong_alias (__pthread_once, __pthread_once_internal)