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
|
/*
Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __pbd_file_manager_h__
#define __pbd_file_manager_h__
#include <sys/types.h>
#include <string>
#include <map>
#include <list>
#include <glibmm/threads.h>
#include "pbd/signals.h"
namespace PBD {
class FileManager;
/** Parent class for FileDescriptors.
*
* When a subclass is instantiated, the file it describes is added to a
* list. The FileDescriptor can be `allocated', meaning that its
* file will be opened on the filesystem, and can then be `released'.
* FileDescriptors are reference counted as they are allocated and
* released. When a descriptor's refcount is 0, the file on the
* filesystem is eligible to be closed if necessary to free up file
* handles for other files.
*
* The upshot of all this is that Ardour can manage the number of
* open files to stay within limits imposed by the operating system.
*/
class FileDescriptor
{
public:
FileDescriptor (std::string const &, bool);
virtual ~FileDescriptor () {}
const std::string& path() const { return _path; }
void release ();
virtual void set_path (const std::string&);
/** Emitted when the file is closed */
PBD::Signal0<void> Closed;
protected:
friend class FileManager;
/* These methods and variables must be called / accessed
with a lock held on the FileManager's mutex
*/
/** @return false on success, true on failure */
virtual bool open () = 0;
virtual void close () = 0;
virtual bool is_open () const = 0;
int _refcount; ///< number of active users of this file
double _last_used; ///< monotonic time that this file was last allocated
std::string _path; ///< file path
bool _writeable; ///< true if it should be opened writeable, otherwise false
FileManager* manager ();
private:
static FileManager* _manager;
};
/** FileDescriptor for a file to be opened using POSIX open */
class FdFileDescriptor : public FileDescriptor
{
public:
FdFileDescriptor (std::string const & file_name, bool writeable, mode_t mode);
~FdFileDescriptor ();
int allocate ();
private:
friend class FileManager;
bool open ();
void close ();
bool is_open () const;
int _fd; ///< file descriptor, or -1 if the file is closed
mode_t _mode; ///< mode to use when creating files
};
/** FileDescriptor for a file opened using stdio */
class StdioFileDescriptor : public FileDescriptor
{
public:
StdioFileDescriptor (std::string const & file_name, std::string const & mode);
~StdioFileDescriptor ();
FILE* allocate ();
private:
friend class FileManager;
bool open ();
void close ();
bool is_open () const;
FILE* _file;
std::string _mode;
};
/** Class to limit the number of files held open */
class FileManager
{
public:
FileManager ();
void add (FileDescriptor *);
void remove (FileDescriptor *);
void release (FileDescriptor *);
bool allocate (FileDescriptor *);
private:
void close (FileDescriptor *);
std::list<FileDescriptor*> _files; ///< files we know about
Glib::Threads::Mutex _mutex; ///< mutex for _files, _open and FileDescriptor contents
int _open; ///< number of open files
int _max_open; ///< maximum number of open files
};
}
#endif
|