1 /*****************************************************************
2 |
3 |   Neptune - Threads
4 |
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 |     * Redistributions of source code must retain the above copyright
11 |       notice, this list of conditions and the following disclaimer.
12 |     * Redistributions in binary form must reproduce the above copyright
13 |       notice, this list of conditions and the following disclaimer in the
14 |       documentation and/or other materials provided with the distribution.
15 |     * Neither the name of Axiomatic Systems nor the
16 |       names of its contributors may be used to endorse or promote products
17 |       derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30  ****************************************************************/
31 
32 /*----------------------------------------------------------------------
33 |   includes
34 +---------------------------------------------------------------------*/
35 #include "NptThreads.h"
36 
37 /*----------------------------------------------------------------------
38 |   NPT_SingletonLock
39 +---------------------------------------------------------------------*/
40 NPT_Mutex NPT_SingletonLock::Instance;
41 
42 /*----------------------------------------------------------------------
43 |   NPT_ThreadCallbackSlot::NPT_ThreadCallbackSlot
44 +---------------------------------------------------------------------*/
NPT_ThreadCallbackSlot()45 NPT_ThreadCallbackSlot::NPT_ThreadCallbackSlot() :
46     m_CallbackArgs(NULL),
47     m_Shutdown(false),
48     m_NotificationHelper(NULL)
49 {
50 }
51 
52 /*----------------------------------------------------------------------
53 |   NPT_ThreadCallbackSlot::Shutdown
54 +---------------------------------------------------------------------*/
55 NPT_Result
Shutdown()56 NPT_ThreadCallbackSlot::Shutdown()
57 {
58     // protect against concurrent access
59     //FIXME: This will not work if another Thread has called ReceiveCallback with a timeout
60     NPT_AutoLock lock(m_ReadLock);
61 
62     // signal we are shut down
63     m_Shutdown = true;
64 
65     // clear up any pending callbacks
66     m_Pending.SetValue(0);
67     m_Ack.SetValue(1);
68 
69     return NPT_SUCCESS;
70 }
71 
72 /*----------------------------------------------------------------------
73 |   NPT_ThreadCallbackSlot::SetNotificationHelper
74 +---------------------------------------------------------------------*/
75 NPT_Result
SetNotificationHelper(NotificationHelper * helper)76 NPT_ThreadCallbackSlot::SetNotificationHelper(NotificationHelper* helper)
77 {
78     m_NotificationHelper = helper;
79     return NPT_SUCCESS;
80 }
81 
82 /*----------------------------------------------------------------------
83 |   NPT_ThreadCallbackSlot::ReceiveCallback
84 +---------------------------------------------------------------------*/
85 NPT_Result
ReceiveCallback(NPT_ThreadCallbackReceiver & receiver,NPT_Timeout timeout)86 NPT_ThreadCallbackSlot::ReceiveCallback(NPT_ThreadCallbackReceiver& receiver,
87                                         NPT_Timeout                 timeout)
88 {
89     // protect against concurrent access
90     //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - read locking, timeout=%d\n", timeout);
91     NPT_AutoLock lock(m_ReadLock);
92 
93     if (timeout) {
94         // wait until there is a pending callback
95         //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - waiting...\n");
96         NPT_Result result = m_Pending.WaitUntilEquals(1, timeout);
97         if (NPT_FAILED(result)) return result; // don't log here because the result
98                                                // could be NPT_ERROR_TIMEOUT which
99                                                // is an expected normal case.
100         //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - got it\n");
101     } else {
102         // see if something is pending
103         if (m_Pending.GetValue() == 0) {
104             //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - nothing pending\n");
105             return NPT_ERROR_CALLBACK_NOTHING_PENDING;
106         }
107     }
108 
109     // check if we have been shutdown
110     if (m_Shutdown) return NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN;
111 
112     // process the callback
113     //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - calling back\n");
114     receiver.OnCallback(const_cast<void*>(m_CallbackArgs));
115 
116     // signal that we've processed the callback
117     m_Pending.SetValue(0);
118     m_Ack.SetValue(1);
119 
120     return NPT_SUCCESS;
121 }
122 
123 /*----------------------------------------------------------------------
124 |   NPT_ThreadCallbackSlot::SendCallback
125 +---------------------------------------------------------------------*/
126 NPT_Result
SendCallback(void * args)127 NPT_ThreadCallbackSlot::SendCallback(void* args)
128 {
129     // protect against concurrent access
130     //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - write locking\n");
131     NPT_AutoLock lock(m_WriteLock);
132 
133     // there should be nothing pending
134 #if defined(NPT_DEBUG)
135     NPT_ASSERT(m_Pending.GetValue() == 0);
136 #endif
137 
138     // check if we have been shutdown
139     if (m_Shutdown) return NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN;
140 
141     // put the callback args
142     m_CallbackArgs = args;
143     //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - signalling\n");
144     m_Pending.SetValue(1);
145 
146     // call the helper before we wait
147     if (m_NotificationHelper) {
148         m_NotificationHelper->Notify();
149     }
150 
151     // wait until the callback has been process, or we've been shutdown
152     //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - waiting...\n");
153     m_Ack.WaitUntilEquals(1);
154     //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - got it\n");
155 
156     // done
157     m_Ack.SetValue(0);
158     m_CallbackArgs = NULL;
159 
160     return m_Shutdown?NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN:NPT_SUCCESS;
161 }
162