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
)
17 ACE_SV_Semaphore_Complex::dump () 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
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.
65 ACE_SV_Semaphore_Complex::open (key_t k
,
71 ACE_TRACE ("ACE_SV_Semaphore_Complex::open");
72 #ifdef ACE_HAS_SYSV_IPC
79 // Must include a count for the 2 additional semaphores we use
81 this->sem_number_
= nsems
+ 2;
83 if (create
== ACE_SV_Semaphore_Complex::ACE_CREATE
)
89 this->internal_id_
= ACE_OS::semget
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
));
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);
124 #ifdef ACE_HAS_SYSV_IPC
125 return this->init ();
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_
,
141 for (u_short i
= 0; i
< nsems
; i
++)
142 if (this->control (SETVAL
, initial_value
, i
) == -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],
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 ();
170 ACE_SV_Semaphore_Complex::open (const char *name
,
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 ()
190 ACE_TRACE ("ACE_SV_Semaphore_Complex::close");
193 #ifdef ACE_HAS_SYSV_IPC
194 if (this->key_
== (key_t
) - 1 || this->internal_id_
== -1)
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],
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)
213 if (semval
> ACE_SV_Semaphore_Complex::BIGCOUNT_
)
215 else if (semval
== ACE_SV_Semaphore_Complex::BIGCOUNT_
)
216 return this->remove ();
219 int result
= ACE_OS::semop (this->internal_id_
,
220 &ACE_SV_Semaphore_Complex::op_unlock_
[0], 1);
221 #ifdef ACE_HAS_SYSV_IPC
228 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex (key_t k
,
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
,
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
251 key
= this->name_2_key (name
);
253 ACE_UNUSED_ARG (name
);
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 ()
262 ACE_TRACE ("ACE_SV_Semaphore_Complex::~ACE_SV_Semaphore_Complex");
263 if (this->internal_id_
>= 0)
267 ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex ()
269 ACE_TRACE ("ACE_SV_Semaphore_Complex::ACE_SV_Semaphore_Complex");
270 #ifdef ACE_HAS_SYSV_IPC
275 ACE_END_VERSIONED_NAMESPACE_DECL