GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / SV_Semaphore_Complex.cpp
blobaa1a590bba19b667b5c9ecae50463383c96102a3
1 #include "ace/SV_Semaphore_Complex.h"
2 #include "ace/Log_Category.h"
3 #include "ace/OS_NS_Thread.h"
4 #if defined (ACE_HAS_ALLOC_HOOKS)
5 # include "ace/Malloc_Base.h"
6 #endif /* ACE_HAS_ALLOC_HOOKS */
8 #if !defined (__ACE_INLINE__)
9 #include "ace/SV_Semaphore_Complex.inl"
10 #endif /* __ACE_INLINE__ */
12 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
14 ACE_ALLOC_HOOK_DEFINE(ACE_SV_Semaphore_Complex)
16 void
17 ACE_SV_Semaphore_Complex::dump (void) const
19 #if defined (ACE_HAS_DUMP)
20 ACE_TRACE ("ACE_SV_Semaphore_Complex::dump");
21 #endif /* ACE_HAS_DUMP */
24 // initial value of process
25 const int ACE_SV_Semaphore_Complex::BIGCOUNT_ = 10000;
27 // Define the ACE_SV_Semaphore operation arrays for the semop() calls.
28 sembuf ACE_SV_Semaphore_Complex::op_lock_[2] =
30 {0, 0, 0}, // Wait for [0] (lock) to equal 0
31 {0, 1, SEM_UNDO}, // then increment [0] to 1 - this locks it.
32 // UNDO to release the lock if processes exit
33 // before explicitly unlocking.
36 sembuf ACE_SV_Semaphore_Complex::op_endcreate_[2] =
38 {1, -1, SEM_UNDO}, // Decrement [1] (proc counter) with undo on
39 // exit, UNDO to adjust proc counter if
40 // process exits before explicitly calling close()
41 {0, -1, SEM_UNDO}, // the decrement [0] (lock) back to 0
44 sembuf ACE_SV_Semaphore_Complex::op_open_[1] =
46 {1, -1, SEM_UNDO}, // Decrement [1] (proc counter) with undo on
47 // exit.
50 sembuf ACE_SV_Semaphore_Complex::op_close_[3] =
52 {0, 0, 0}, // Wait for [0] (lock) to equal 0
53 {0, 1, SEM_UNDO}, // then increment [0] to 1 - this lock it
54 {1, 1, SEM_UNDO}, // then increment [1] (proc counter)
57 sembuf ACE_SV_Semaphore_Complex::op_unlock_[1] =
59 {0, -1, SEM_UNDO}, // Decrement [0] (lock) back to 0
62 // Open or create an array of SV_Semaphores. We return 0 if all is OK, else -1.
64 int
65 ACE_SV_Semaphore_Complex::open (key_t k,
66 short create,
67 int initial_value,
68 u_short nsems,
69 mode_t perms)
71 ACE_TRACE ("ACE_SV_Semaphore_Complex::open");
72 #ifdef ACE_HAS_SYSV_IPC
73 if (k == IPC_PRIVATE)
74 return -1;
75 #endif
77 this->key_ = k;
79 // Must include a count for the 2 additional semaphores we use
80 // internally.
81 this->sem_number_ = nsems + 2;
83 if (create == ACE_SV_Semaphore_Complex::ACE_CREATE)
85 int result;
89 this->internal_id_ = ACE_OS::semget
90 (this->key_,
91 (u_short) 2 + nsems,
92 perms | ACE_SV_Semaphore_Complex::ACE_CREATE);
94 if (this->internal_id_ == -1)
95 return -1; // permission problem or tables full
97 // When the <ACE_SV_Semaphore_Complex> is created, we know
98 // that the value of all 3 members is 0. Get a lock on the
99 // <ACE_SV_Semaphore_Complex> by waiting for [0] to equal 0,
100 // then increment it.
102 // There is a race condition here. There is the possibility
103 // that between the <semget> above and the <semop> below,
104 // another process can call out <close> function which can
105 // remove the <ACE_SV_Semaphore> if that process is the last
106 // one using it. Therefor we handle the error condition of
107 // an invalid <ACE_SV_Semaphore> ID specifically below, and
108 // if it does happen, we just go back and create it again.
109 result = ACE_OS::semop (this->internal_id_,
110 &ACE_SV_Semaphore_Complex::op_lock_[0],
113 while (result == -1 && (errno == EINVAL || errno == EIDRM));
115 if (result == -1)
116 return -1;
118 // Get the value of the process counter. If it equals 0, then no
119 // one has initialized the ACE_SV_Semaphore yet.
121 int semval = ACE_SV_Semaphore_Simple::control (GETVAL, 0, 1);
123 if (semval == -1)
124 #ifdef ACE_HAS_SYSV_IPC
125 return this->init ();
126 #else
127 return -1;
128 #endif
129 else if (semval == 0)
131 // We should initialize by doing a SETALL, but that would
132 // clear the adjust value that we set when we locked the
133 // ACE_SV_Semaphore above. Instead we do system calls to
134 // initialize [1], as well as all the nsems SV_Semaphores.
136 if (ACE_SV_Semaphore_Simple::control (SETVAL,
137 ACE_SV_Semaphore_Complex::BIGCOUNT_,
138 1) == -1)
139 return -1;
140 else
141 for (u_short i = 0; i < nsems; i++)
142 if (this->control (SETVAL, initial_value, i) == -1)
143 return -1;
146 // Decrement the process counter and then release the lock.
147 return ACE_OS::semop (this->internal_id_,
148 &ACE_SV_Semaphore_Complex::op_endcreate_[0],
151 else
153 this->internal_id_ = ACE_OS::semget (this->key_, 2 + nsems, 0);
154 if (this->internal_id_ == -1)
155 return -1; // doesn't exist or tables full
157 // Decrement the process counter. We don't need a lock to do this.
158 if (ACE_OS::semop (this->internal_id_,
159 &ACE_SV_Semaphore_Complex::op_open_[0], 1) < 0)
160 #ifdef ACE_HAS_SYSV_IPC
161 return this->init ();
162 #else
163 return -1;
164 #endif
165 return 0;
170 ACE_SV_Semaphore_Complex::open (const char *name,
171 short flags,
172 int initial_value,
173 u_short nsems,
174 mode_t perms)
176 ACE_TRACE ("ACE_SV_Semaphore_Complex::open");
177 return this->open (ACE_SV_Semaphore_Simple::name_2_key (name),
178 flags, initial_value, nsems, perms);
181 // Close a ACE_SV_Semaphore. Unlike the remove above, this function
182 // is for a process to call before it exits, when it is done with the
183 // ACE_SV_Semaphore. We "decrement" the counter of processes using
184 // the ACE_SV_Semaphore, and if this was the last one, we can remove
185 // the ACE_SV_Semaphore.
188 ACE_SV_Semaphore_Complex::close (void)
190 ACE_TRACE ("ACE_SV_Semaphore_Complex::close");
191 int semval;
193 #ifdef ACE_HAS_SYSV_IPC
194 if (this->key_ == (key_t) - 1 || this->internal_id_ == -1)
195 return -1;
196 #endif
198 // The following semop() first gets a lock on the ACE_SV_Semaphore,
199 // then increments [1] - the process number.
201 if (ACE_OS::semop (this->internal_id_,
202 &ACE_SV_Semaphore_Complex::op_close_[0],
203 3) == -1)
204 return -1;
206 // Now that we have a lock, read the value of the process counter to
207 // see if this is the last reference to the ACE_SV_Semaphore. There
208 // is a race condition here - see the comments in create ().
210 if ((semval = ACE_SV_Semaphore_Simple::control (GETVAL, 0, 1)) == -1)
211 return -1;
213 if (semval > ACE_SV_Semaphore_Complex::BIGCOUNT_)
214 return -1;
215 else if (semval == ACE_SV_Semaphore_Complex::BIGCOUNT_)
216 return this->remove ();
217 else
219 int result = ACE_OS::semop (this->internal_id_,
220 &ACE_SV_Semaphore_Complex::op_unlock_[0], 1);
221 #ifdef ACE_HAS_SYSV_IPC
222 this->init ();
223 #endif
224 return result;
228 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (key_t k,
229 short flags,
230 int initial_value,
231 u_short nsems,
232 mode_t perms)
234 ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
235 if (this->open (k, flags, initial_value, nsems, perms) == -1)
236 ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_SV_Semaphore_Complex")));
239 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (const char *name,
240 short flags,
241 int initial_value,
242 u_short nsems,
243 mode_t perms)
245 ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
247 key_t key = ACE_DEFAULT_SEM_KEY;
249 #ifdef ACE_HAS_SYSV_IPC
250 if (name != 0)
251 key = this->name_2_key (name);
252 #else
253 ACE_UNUSED_ARG (name);
254 #endif
256 if (this->open (key, flags, initial_value, nsems, perms) == -1)
257 ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_SV_Semaphore_Complex")));
260 ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex (void)
262 ACE_TRACE ("ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex");
263 if (this->internal_id_ >= 0)
264 this->close ();
267 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (void)
269 ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
270 #ifdef ACE_HAS_SYSV_IPC
271 this->init ();
272 #endif
275 ACE_END_VERSIONED_NAMESPACE_DECL