root/OpenSceneGraph/trunk/src/OpenThreads/win32/Win32ConditionPrivateData.h @ 9059

Revision 9059, 4.0 kB (checked in by robert, 5 years ago)

From Blasius Czink, "Among other things I added support for atomic operations on BSD-like systems and additional methods (for "and", "or", "xor").
"

and a later post the same osg-submissions thread:

"it's been a while since I have made the changes but I think it was due to problems with static builds of OpenThreads? on windows. I was using
OpenThreads? in a communication/synchronisation library (without
OpenSceneGraph). It seems I forgot to post a small change in the CMakeLists file of OpenThreads?. If a user turns DYNAMIC_OPENTHREADS to OFF (static build) OT_LIBRARY_STATIC will be defined in the Config.
Without these changes a windows user will always end up with a "declspec(dllexport)" or "declspec(dllimport)" which is a problem for static builds."

And another post from Blasius on this topic:

"I tested with VS2005 and VS2008. For 32 bit everything works as expected. For x64 and VS2008 I could successfully do the cmake-configure and then the compilation but I had occasional crashes of cmTryCompileExec.exe (during the cmake-configure phase) which seems to be a cmake bug. With VS2005 and 64bit cmake does not set _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED although the interlocked functionality should be there. If I place the source snippet from the CHECK_CXX_SOURCE_RUNS macro to a separate sourcefile I can compile and run the resulting executable successfully. Forcing OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED (on VS2005/x64) reveals a bug in "intrin.h" which seems to be fixed in VS2008 but not in VS2005.

In case anyone is interested the lines:
MACHINEI(unsigned char _interlockedbittestandset(long *a, long b))
MACHINEI(unsigned char _interlockedbittestandreset(long *a, long b))
MACHINEX64(unsigned char _interlockedbittestandset64(int64 *a, int64 b))
MACHINEX64(unsigned char _interlockedbittestandreset64(int64 *a, int64 b))

should be changed to:
MACHINEI(unsigned char _interlockedbittestandset(long volatile *a, long b))
MACHINEI(unsigned char _interlockedbittestandreset(long volatile *a, long b))
MACHINEX64(unsigned char _interlockedbittestandset64(int64 volatile *a, int64 b))
MACHINEX64(unsigned char _interlockedbittestandreset64(int64 volatile *a, int64 b))

The worst thing that can happen is that interlocked funtionality is not detected during cmake-configure and the mutex fallback is used.
Which reminds me another small glitch in the Atomic header so I attached a corrected version.

Why is the OT_LIBRARY_STATIC added to the config file? It is not needed anywhere.

OT_LIBRARY_STATIC is needed if you are doing static-builds on Windows. See my previous post on that.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007  The Open Thread Group
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14//
15//
16// WIN32ConditionPrivateData.h - Private data structure for Condition
17// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18//
19#ifndef _WIN32CONDITIONPRIVATEDATA_H_
20#define _WIN32CONDITIONPRIVATEDATA_H_
21
22#ifndef _WINDOWS_
23#define WIN32_LEAN_AND_MEAN
24#define _WIN32_WINNT 0x0400
25#include <windows.h>
26#endif
27
28#include <OpenThreads/ScopedLock>
29
30#include "Win32ThreadPrivateData.h"
31#include "HandleHolder.h"
32
33#define InterlockedGet(x) InterlockedExchangeAdd(x,0)
34
35namespace OpenThreads {
36
37class Condition;
38
39class Win32ConditionPrivateData {
40public:
41    friend class Condition;
42    /// number of waiters.
43    long waiters_;
44
45    Win32ConditionPrivateData ()
46        :waiters_(0),
47         was_broadcast_(0),
48         sema_(CreateSemaphore(NULL,0,0x7fffffff,NULL)),
49         waiters_done_(CreateEvent(NULL,FALSE,FALSE,NULL))
50    {
51    }
52
53    ~Win32ConditionPrivateData ();
54
55    inline int broadcast ()
56    {
57        int have_waiters = 0;
58        long w = InterlockedGet(&waiters_);
59
60        if (w > 0)
61        {
62          // we are broadcasting. 
63          was_broadcast_ = 1;
64          have_waiters = 1;
65        }
66
67        int result = 0;
68        if (have_waiters)
69        {
70            // Wake up all the waiters.
71            ReleaseSemaphore(sema_.get(),waiters_,NULL);
72
73            cooperativeWait(waiters_done_.get(), INFINITE);
74
75            //end of broadcasting
76            was_broadcast_ = 0;
77        }
78        return result;
79    }
80
81    inline int signal()
82    {
83        long w = InterlockedGet(&waiters_);
84        int have_waiters = w > 0;
85 
86        int result = 0;
87
88        if (have_waiters)
89        {
90            if( !ReleaseSemaphore(sema_.get(),1,NULL) )
91                result = -1;
92        }
93        return result;
94    }
95
96    inline int wait (Mutex& external_mutex, long timeout_ms)
97    {
98   
99        // Prevent race conditions on the <waiters_> count.
100        InterlockedIncrement(&waiters_);
101
102        int result = 0;
103
104        ReverseScopedLock<Mutex> lock(external_mutex);
105
106        // wait in timeslices, giving testCancel() a change to
107        // exit the thread if requested.
108        try {
109              DWORD dwResult = cooperativeWait(sema_.get(), timeout_ms);
110            if(dwResult != WAIT_OBJECT_0)
111                result = (int)dwResult;
112        }
113        catch(...){
114            // thread is canceled in cooperative wait , do cleanup
115            InterlockedDecrement(&waiters_);
116            long w = InterlockedGet(&waiters_);
117            int last_waiter = was_broadcast_ && w == 0;
118
119            if (last_waiter)  SetEvent(waiters_done_.get());
120            // rethrow
121            throw;
122        }
123
124       
125        // We're ready to return, so there's one less waiter.
126        InterlockedDecrement(&waiters_);
127        long w = InterlockedGet(&waiters_);
128        int last_waiter = was_broadcast_ && w == 0;
129
130        if (result != -1 && last_waiter)
131            SetEvent(waiters_done_.get());
132
133        return result;
134    }
135
136protected:
137
138  /// Serialize access to the waiters count.
139  /// Mutex waiters_lock_;
140  /// Queue up threads waiting for the condition to become signaled.
141  HandleHolder sema_;
142  /**
143   * An auto reset event used by the broadcast/signal thread to wait
144   * for the waiting thread(s) to wake up and get a chance at the
145   * semaphore.
146   */
147  HandleHolder waiters_done_;
148  /// Keeps track of whether we were broadcasting or just signaling.
149  size_t was_broadcast_;
150};
151
152#undef InterlockedGet
153
154}
155
156
157
158
159
160
161
162#endif // !_WIN32CONDITIONPRIVATEDATA_H_
163
164
Note: See TracBrowser for help on using the browser.