XRootD
XrdPosixObject.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d P o s i x O b j e c t . h h */
4 /* */
5 /* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cerrno>
32 #include <fcntl.h>
33 #include <sys/resource.h>
34 #include <sys/stat.h>
35 
38 #include "XrdSys/XrdSysHeaders.hh"
39 #include "XrdSys/XrdSysTimer.hh"
40 
41 /******************************************************************************/
42 /* G l o b a l s */
43 /******************************************************************************/
44 
45 namespace XrdPosixGlobals
46 {
47 extern thread_local XrdOucECMsg ecMsg;
48 }
49 
50 /******************************************************************************/
51 /* S t a t i c M e m b e r s */
52 /******************************************************************************/
53 
54 XrdSysMutex XrdPosixObject::fdMutex;
55 XrdPosixObject **XrdPosixObject::myFiles = 0;
56 int XrdPosixObject::highFD = -1;
57 int XrdPosixObject::lastFD = -1;
58 int XrdPosixObject::baseFD = 0;
59 int XrdPosixObject::freeFD = 0;
60 int XrdPosixObject::posxFD = 0;
61 int XrdPosixObject::devNull = -1;
62 
63 /******************************************************************************/
64 /* A s s i g n F D */
65 /******************************************************************************/
66 
67 bool XrdPosixObject::AssignFD(bool isStream)
68 {
69  XrdSysMutexHelper fdHelper(fdMutex);
70  int fd;
71 
72 // Obtain a new filedscriptor from the system. Use the fd to track the object.
73 // Streams are not supported for virtual file descriptors.
74 //
75  if (baseFD)
76  { if (isStream) return 0;
77  for (fd = freeFD; fd < posxFD && myFiles[fd]; fd++) {}
78  if (fd >= posxFD) return 0;
79  freeFD = fd+1;
80  } else {
81  do{if ((fd = dup(devNull)) < 0) return false;
82  if (fd >= lastFD || (isStream && fd > 255))
83  {close(fd); return 0;}
84  if (!myFiles[fd]) break;
85  DMSG("AssignFD", "FD " <<fd <<" closed outside of XrdPosix!");
86  } while(1);
87  }
88 
89 // Enter object in out vector of objects and assign it the FD
90 //
91  myFiles[fd] = this;
92  if (fd > highFD) highFD = fd;
93  fdNum = fd + baseFD;
94 
95 // All done.
96 //
97  return true;
98 }
99 
100 /******************************************************************************/
101 /* D i r */
102 /******************************************************************************/
103 
105 {
106  XrdPosixDir *dP;
107  XrdPosixObject *oP;
108  int waitCount = 0;
109  bool haveLock;
110 
111 // Validate the fildes
112 //
113 do{if (fd >= lastFD || fd < baseFD)
114  {errno = EBADF; return (XrdPosixDir *)0;}
115 
116 // Obtain the file object, if any
117 //
118  fdMutex.Lock();
119  if (!(oP = myFiles[fd - baseFD]) || !(oP->Who(&dP)))
120  {fdMutex.UnLock(); errno = EBADF; return (XrdPosixDir *)0;}
121 
122 // Attempt to lock the object in the appropriate mode. If we fail, then we need
123 // to retry this after dropping the global lock. We pause a bit to let the
124 // current lock holder a chance to unlock the lock. We only do this a limited
125 // amount of time (1 minute) so that we don't get stuck here forever.
126 //
127  if (glk) haveLock = oP->objMutex.CondWriteLock();
128  else haveLock = oP->objMutex.CondReadLock();
129  if (!haveLock)
130  {fdMutex.UnLock();
131  waitCount++;
132  if (waitCount > 120) break;
133  XrdSysTimer::Wait(500); // We wait 500 milliseconds
134  continue;
135  }
136 
137 // If the global lock is to be held, then release the object lock as this
138 // is a call to destroy the object and there is no need for the local lock.
139 //
140  if (glk) oP->UnLock();
141  else fdMutex.UnLock();
142  return dP;
143  } while(1);
144 
145 // If we get here then we timedout waiting for the object lock
146 //
147  errno = ETIMEDOUT;
148  return (XrdPosixDir *)0;
149 }
150 
151 /******************************************************************************/
152 /* F i l e */
153 /******************************************************************************/
154 
156 {
157  XrdPosixFile *fP;
158  XrdPosixObject *oP;
159  int waitCount = 0;
160  bool haveLock;
161 
162 // Validate the fildes
163 //
164 do{if (fd >= lastFD || fd < baseFD)
165  {errno = EBADF; return (XrdPosixFile *)0;}
166 
167 // Obtain the file object, if any
168 //
169  fdMutex.Lock();
170  if (!(oP = myFiles[fd - baseFD]) || !(oP->Who(&fP)))
171  {fdMutex.UnLock(); errno = EBADF; return (XrdPosixFile *)0;}
172 
173 // Attempt to lock the object in the appropriate mode. If we fail, then we need
174 // to retry this after dropping the global lock. We pause a bit to let the
175 // current lock holder a chance to unlock the lock. We only do this a limited
176 // amount of time (1 minute) so that we don't get stuck here forever.
177 //
178  if (glk) haveLock = oP->objMutex.CondWriteLock();
179  else haveLock = oP->objMutex.CondReadLock();
180  if (!haveLock)
181  {fdMutex.UnLock();
182  waitCount++;
183  if (waitCount > 120) break;
184  XrdSysTimer::Wait(500); // We wait 500 milliseconds
185  continue;
186  }
187 
188 // If the global lock is to be held, then release the object lock as this
189 // is a call to destroy the object and there is no need for the local lock.
190 //
191  if (glk) oP->UnLock();
192  else fdMutex.UnLock();
193  return fP;
194  } while(1);
195 
196 // If we get here then we timedout waiting for the object lock
197 //
198  errno = ETIMEDOUT;
199  return (XrdPosixFile *)0;
200 }
201 
202 /******************************************************************************/
203 /* I n i t */
204 /******************************************************************************/
205 
206 int XrdPosixObject::Init(int fdnum)
207 {
208  static const int maxFD = 1048576;
209  struct rlimit rlim;
210  int isize, limfd;
211 
212 // Initialize the /dev/null file descriptors, bail if we cannot
213 //
214  devNull = open("/dev/null", O_RDWR, 0744);
215  if (devNull < 0) return -1;
216 
217 // Obtain the file descriptor limit but be careful of infinity
218 //
219  if (getrlimit(RLIMIT_NOFILE, &rlim)) limfd = maxFD;
220  else {if (rlim.rlim_max == RLIM_INFINITY || (int)rlim.rlim_max > maxFD)
221  {rlim.rlim_cur = maxFD;
222  setrlimit(RLIMIT_NOFILE, &rlim);
223  } else {
224  if (rlim.rlim_cur != rlim.rlim_max)
225  {rlim.rlim_cur = rlim.rlim_max;
226  setrlimit(RLIMIT_NOFILE, &rlim);
227  }
228  }
229  limfd = static_cast<int>(rlim.rlim_cur);
230  }
231 
232 // Compute size of table. if the passed fdnum is negative then the caller does
233 // not want us to shadow fd's (ther caller promises to be honest). Otherwise,
234 // the actual fdnum limit will be based on the current limit.
235 //
236  if (fdnum < 0) {posxFD = fdnum = -fdnum; baseFD = limfd;}
237  else fdnum = limfd;
238  isize = fdnum * sizeof(XrdPosixFile *);
239 
240 // Allocate the table for fd-type pointers
241 //
242  if (!(myFiles = (XrdPosixObject **)malloc(isize))) lastFD = -1;
243  else {memset((void *)myFiles, 0, isize); lastFD = fdnum+baseFD;}
244 
245 // All done
246 //
247  return baseFD;
248 }
249 
250 /******************************************************************************/
251 /* R e l e a s e */
252 /******************************************************************************/
253 
255 {
256 // Get the lock if need be
257 //
258  if (needlk) fdMutex.Lock();
259 
260 // Remove the object from the table
261 //
262  if (baseFD)
263  {int myFD = oP->fdNum - baseFD;
264  if (myFD < freeFD) freeFD = myFD;
265  myFiles[myFD] = 0;
266  } else {
267  myFiles[oP->fdNum] = 0;
268  close(oP->fdNum);
269  }
270 
271 // Zorch the object fd and release the global lock
272 //
273  oP->fdNum = -1;
274  fdMutex.UnLock();
275 }
276 
277 /******************************************************************************/
278 /* R e l e a s e D i r */
279 /******************************************************************************/
280 
282 {
283  XrdPosixDir *dP;
284 
285 // Find the directory object
286 //
287  if (!(dP = Dir(fd, true))) return (XrdPosixDir *)0;
288 
289 // Release it and return the underlying object
290 //
291  Release((XrdPosixObject *)dP, false);
292  return dP;
293 }
294 
295 /******************************************************************************/
296 /* R e l e a s e F i l e */
297 /******************************************************************************/
298 
300 {
301  XrdPosixFile *fP;
302 
303 // Find the file object
304 //
305  if (!(fP = File(fd, true))) return (XrdPosixFile *)0;
306 
307 // Release it and return the underlying object
308 //
309  Release((XrdPosixObject *)fP, false);
310  return fP;
311 }
312 
313 /******************************************************************************/
314 /* S h u t d o w n */
315 /******************************************************************************/
316 
318 {
319  XrdPosixObject *oP;
320  int i;
321 
322 // Destroy all files and static data
323 //
324  fdMutex.Lock();
325  if (myFiles)
326  {for (i = 0; i <= highFD; i++)
327  if ((oP = myFiles[i]))
328  {myFiles[i] = 0;
329  if (oP->fdNum >= 0) close(oP->fdNum);
330  oP->fdNum = -1;
331  delete oP;
332  };
333  free(myFiles); myFiles = 0;
334  }
335  fdMutex.UnLock();
336 }
int open(const char *path, int oflag,...)
#define DMSG(x, y)
#define close(a)
Definition: XrdPosix.hh:43
static void Release(XrdPosixObject *oP, bool needlk=true)
static void Shutdown()
bool AssignFD(bool isStream=false)
static XrdPosixDir * Dir(int fildes, bool glk=false)
static XrdPosixDir * ReleaseDir(int fildes)
XrdSysRWLock objMutex
static int Init(int numfd)
virtual bool Who(XrdPosixDir **dirP)
static XrdPosixFile * ReleaseFile(int fildes)
static XrdPosixFile * File(int fildes, bool glk=false)
static void Wait(int milliseconds)
Definition: XrdSysTimer.cc:227
int devNull
Definition: XrdGlobals.cc:55
thread_local XrdOucECMsg ecMsg