Tizen 2.0 Release
[framework/web/wrt-commons.git] / modules / core / src / semaphore.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        semaphore.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of semaphore
21  */
22 #include <stddef.h>
23 #include <dpl/semaphore.h>
24 #include <dpl/assert.h>
25 #include <dpl/log/log.h>
26 #include <errno.h>
27 #include <malloc.h>
28 #include <cstring>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 namespace DPL
33 {
34 void Semaphore::Remove(const std::string &fileName)
35 {
36     if (sem_unlink(fileName.c_str()) == -1) {
37         int error = errno;
38         LogPedantic("Failed to unlink semaphore. Errno: " << error);
39         ThrowMsg(Exception::RemoveFailed,
40                 "Failed to unlink semaphore. Errno: " << error);
41     }
42 }
43
44 Semaphore::Semaphore(size_t maxLockCount)
45 {
46     LogPedantic("Allocating unnamed semaphore:");
47     LogPedantic("    Maximum lock count: " << maxLockCount);
48
49     if (-1 == sem_init(&m_semaphore.unnamed.handle,
50                        0,
51                        static_cast<unsigned>(maxLockCount)))
52     {
53         int error = errno;
54
55         LogPedantic("Failed to create semaphore. Errno: " << error);
56
57         ThrowMsg(Exception::CreateFailed,
58             "Failed to create semaphore. Errno: " << error);
59     }
60
61     m_type = Type_Unnamed;
62 }
63
64 Semaphore::Semaphore(const std::string &fileName,
65                      bool allowCreate,
66                      bool exclusiveCreate,
67                      size_t maxLockCount,
68                      int permissions,
69                      bool unlinkOnDestroy)
70 {
71     LogPedantic("Allocating named semaphore:");
72     LogPedantic("    File name: " << fileName);
73     LogPedantic("    Maximum lock count: " << maxLockCount);
74     LogPedantic("    File name: " << fileName);
75     LogPedantic("    Allowed create: " << allowCreate);
76     LogPedantic("    Exclusive create: " << exclusiveCreate);
77     LogPedantic("    Permissions: " << permissions);
78     LogPedantic("    Unlink on destroy: " << unlinkOnDestroy);
79
80     sem_t *semaphore;
81
82     do
83     {
84         if (allowCreate)
85         {
86             if (exclusiveCreate)
87             {
88                 semaphore = sem_open(fileName.c_str(),
89                                      O_CREAT | O_EXCL,
90                                      permissions,
91                                      static_cast<unsigned>(maxLockCount));
92             }
93             else
94             {
95                 semaphore = sem_open(fileName.c_str(),
96                                      O_CREAT,
97                                      permissions,
98                                      static_cast<unsigned>(maxLockCount));
99             }
100         }
101         else
102         {
103             semaphore = sem_open(fileName.c_str(), 0);
104         }
105     }
106     while (semaphore == SEM_FAILED && errno == EINTR);
107
108     if (semaphore == SEM_FAILED)
109     {
110         int error = errno;
111
112         LogPedantic("Failed to create semaphore '" << fileName
113                     << "'. Errno: " << error);
114
115         ThrowMsg(Exception::CreateFailed,
116                  "Failed to create semaphore '" << fileName
117                      << "'. Errno: " << error);
118     }
119
120     m_semaphore.named.handle = semaphore;
121
122     m_semaphore.named.name = strdup(fileName.c_str()); // May be NULL
123
124     if (m_semaphore.named.name == NULL)
125         LogPedantic("Out of memory while duplicating semaphore name");
126
127     m_semaphore.named.unlinkOnDestroy = unlinkOnDestroy;
128
129     m_type = Type_Named;
130 }
131
132 Semaphore::~Semaphore()
133 {
134     InternalDestroy();
135 }
136
137 sem_t *Semaphore::InternalGet() const
138 {
139     switch (m_type)
140     {
141         case Type_Unnamed:
142             return &m_semaphore.unnamed.handle;
143
144         case Type_Named:
145             return m_semaphore.named.handle;
146
147         default:
148             Assert(false && "Invalid type");
149     }
150
151     return NULL;
152 }
153
154 void Semaphore::InternalDestroy()
155 {
156     switch (m_type)
157     {
158         case Type_Unnamed:
159             if (sem_destroy(&m_semaphore.unnamed.handle) == -1)
160             {
161                 int error = errno;
162
163                 LogPedantic("Failed to destroy semaphore. Errno: " << error);
164             }
165             break;
166
167         case Type_Named:
168             if (sem_close(m_semaphore.named.handle) == -1)
169             {
170                 int error = errno;
171
172                 LogPedantic("Failed to close semaphore. Errno: " << error);
173             }
174
175             if (m_semaphore.named.name != NULL)
176             {
177                 // Unlink named semaphore
178                 if (m_semaphore.named.unlinkOnDestroy &&
179                     sem_unlink(m_semaphore.named.name) == -1)
180                 {
181                     int error = errno;
182
183                     LogPedantic("Failed to unlink semaphore. Errno: "
184                                 << error);
185                 }
186
187                 // Free name
188                 free(m_semaphore.named.name);
189             }
190             break;
191
192         default:
193             Assert(false && "Invalid type");
194     }
195 }
196
197 void Semaphore::Lock() const
198 {
199     if (TEMP_FAILURE_RETRY(sem_wait(InternalGet())) != 0)
200     {
201         int error = errno;
202
203         LogPedantic("Failed to lock semaphore. Errno: " << error);
204
205         ThrowMsg(Exception::LockFailed,
206             "Failed to lock semaphore. Errno: " << error);
207     }
208 }
209
210 void Semaphore::Unlock() const
211 {
212     if (sem_post(InternalGet()) != 0)
213     {
214         int error = errno;
215
216         LogPedantic("Failed to unlock semaphore. Errno: " << error);
217
218         ThrowMsg(Exception::UnlockFailed,
219             "Failed to unlock semaphore. Errno: " << error);
220     }
221 }
222
223 Semaphore::ScopedLock::ScopedLock(Semaphore *semaphore)
224     : m_semaphore(semaphore)
225 {
226     Assert(semaphore != NULL);
227     m_semaphore->Lock();
228 }
229
230 Semaphore::ScopedLock::~ScopedLock()
231 {
232     Try
233     {
234         m_semaphore->Unlock();
235     }
236     Catch (Semaphore::Exception::UnlockFailed)
237     {
238         LogPedantic("Failed to leave semaphore scoped lock");
239     }
240 }
241 } // namespace DPL