XRootD
Loading...
Searching...
No Matches
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
39#include "XrdSys/XrdSysTimer.hh"
40
41/******************************************************************************/
42/* G l o b a l s */
43/******************************************************************************/
44
45namespace XrdPosixGlobals
46{
47extern thread_local XrdOucECMsg ecMsg;
48}
49
50/******************************************************************************/
51/* S t a t i c M e m b e r s */
52/******************************************************************************/
53
54XrdSysMutex XrdPosixObject::fdMutex;
55XrdPosixObject **XrdPosixObject::myFiles = 0;
56int XrdPosixObject::highFD = -1;
57int XrdPosixObject::lastFD = -1;
58int XrdPosixObject::baseFD = 0;
59int XrdPosixObject::freeFD = 0;
60int XrdPosixObject::posxFD = 0;
61int XrdPosixObject::devNull = -1;
62
63/******************************************************************************/
64/* A s s i g n F D */
65/******************************************************************************/
66
67bool 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//
113do{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//
164do{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
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}
#define DMSG(x, y)
#define close(a)
Definition XrdPosix.hh:48
#define open
Definition XrdPosix.hh:76
XrdOucString Dir
XrdOucString File
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)
thread_local XrdOucECMsg ecMsg