summaryrefslogtreecommitdiff
path: root/boost/interprocess/sync/xsi/xsi_named_mutex.hpp
blob: 7d8cf50a83676aeb48ca6cbc26e6353b42f672bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP

#ifndef BOOST_CONFIG_HPP
#  include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#  pragma once
#endif

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>

#if defined(BOOST_INTERPROCESS_WINDOWS)
#error "This header can't be used in Windows operating systems"
#endif

#include <boost/move/utility_core.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/sync/xsi/basic_xsi_semaphore.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>

#include <cstddef>
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <string>


//!\file
//!Describes a class representing a xsi-based named_mutex.

namespace boost {
namespace interprocess {

//!A class that wraps a XSI (System V)-based named semaphore
//!that undoes the operation if the process crashes.
class xsi_named_mutex
{
   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   //Non-copyable and non-assignable
   xsi_named_mutex(xsi_named_mutex &);
   xsi_named_mutex &operator=(xsi_named_mutex &);
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

   public:
   BOOST_MOVABLE_BUT_NOT_COPYABLE(xsi_named_mutex)

   //!Default constructor.
   //!Represents an empty xsi_named_mutex.
   xsi_named_mutex();

   //!Tries to create a new XSI-based named mutex with a key obtained from a call to ftok (with path
   //!"path" and id "id"), and permissions "perm".
   //!If the named mutex previously exists, it tries to open it.
   //!Otherwise throws an error.
   xsi_named_mutex(open_or_create_t, const char *path, boost::uint8_t id, int perm = 0666)
   {  this->priv_open_or_create(ipcdetail::DoOpenOrCreate, path, id, perm);  }

   //!Moves the ownership of "moved"'s named mutex to *this.
   //!After the call, "moved" does not represent any named mutex
   //!Does not throw
   xsi_named_mutex(BOOST_RV_REF(xsi_named_mutex) moved)
   {  this->swap(moved);   }

   //!Moves the ownership of "moved"'s named mutex to *this.
   //!After the call, "moved" does not represent any named mutex.
   //!Does not throw
   xsi_named_mutex &operator=(BOOST_RV_REF(xsi_named_mutex) moved)
   {
      xsi_named_mutex tmp(boost::move(moved));
      this->swap(tmp);
      return *this;
   }

   //!Swaps two xsi_named_mutex. Does not throw
   void swap(xsi_named_mutex &other);

   //!Destroys *this. The named mutex is still valid after
   //!destruction. use remove() to destroy the named mutex.
   ~xsi_named_mutex();

   //!Returns the path used to construct the
   //!named mutex.
   const char *get_path() const;

   //!Returns access
   //!permissions
   int get_permissions() const;

   //!Returns the mapping handle.
   //!Never throws
   mapping_handle_t get_mapping_handle() const;

   //!Erases a XSI-based named mutex from the system.
   //!Returns false on error. Never throws
   bool remove();

   void lock();

   void unlock();

   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   private:

   //!Closes a previously opened file mapping. Never throws.
   void priv_close();

   //!Closes a previously opened file mapping. Never throws.
   bool priv_open_or_create( ipcdetail::create_enum_t type
                           , const char *path
                           , boost::uint8_t id
                           , int perm);
   int            m_semid;
   key_t          m_key;
   boost::uint8_t m_id;
   int            m_perm;
   std::string    m_path;
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};

#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)

inline xsi_named_mutex::xsi_named_mutex()
   :  m_semid(-1), m_key(-1), m_id(0), m_perm(0), m_path()
{}

inline xsi_named_mutex::~xsi_named_mutex()
{  this->priv_close(); }

inline const char *xsi_named_mutex::get_path() const
{  return m_path.c_str(); }

inline void xsi_named_mutex::swap(xsi_named_mutex &other)
{
   (simple_swap)(m_key,   other.m_key);
   (simple_swap)(m_id,    other.m_id);
   (simple_swap)(m_semid, other.m_semid);
   (simple_swap)(m_perm,  other.m_perm);
   m_path.swap(other.m_path);
}

inline mapping_handle_t xsi_named_mutex::get_mapping_handle() const
{  mapping_handle_t mhnd = { m_semid, true};   return mhnd;   }

inline int xsi_named_mutex::get_permissions() const
{  return m_perm; }

inline bool xsi_named_mutex::priv_open_or_create
   (ipcdetail::create_enum_t type, const char *path, boost::uint8_t id, int perm)
{
   key_t key;
   if(path){
      key  = ::ftok(path, id);
      if(((key_t)-1) == key){
         error_info err = system_error_code();
         throw interprocess_exception(err);
      }
   }
   else{
      key = IPC_PRIVATE;
   }

   perm &= 0x01FF;

   int semid;
   if(!xsi::simple_sem_open_or_create(key, 1, semid, perm)){
      error_info err = system_error_code();
      throw interprocess_exception(err);
   }

   m_perm = perm;
   m_semid = semid;
   m_path = path ? path : "";
   m_id   = id;
   m_key  = key;

   return true;
}

inline void xsi_named_mutex::priv_close()
{
}

inline void xsi_named_mutex::lock()
{
   if(!xsi::simple_sem_op(m_semid, -1)){
      error_info err = system_error_code();
      throw interprocess_exception(err);
   }
}

inline void xsi_named_mutex::unlock()
{
   bool success = xsi::simple_sem_op(m_semid, 1);
   (void)success;
   BOOST_ASSERT(success);
}

inline bool xsi_named_mutex::remove()
{
   if(m_semid != -1){
      int ret = ::semctl(m_semid, IPC_RMID, 0);
      if(-1 == ret)
         return false;
      //Now put it in default-constructed state
      m_semid  = -1;
      m_key    = -1;
      m_id     = 0;
      m_perm   = 0;
      m_path.clear();
   }
   return false;
}

#endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

}  //namespace interprocess {
}  //namespace boost {

#include <boost/interprocess/detail/config_end.hpp>

#endif   //BOOST_INTERPROCESS_XSI_XSI_NAMED_MUTEX_HPP