@@ -55,6 +55,8 @@ pub struct ShmemConf {
5555 size : usize ,
5656 ext : os_impl:: ShmemConfExt ,
5757 mode : Option < Mode > ,
58+ use_tmpfs : bool ,
59+ tmpfs_base_dir : Option < PathBuf > ,
5860}
5961impl Drop for ShmemConf {
6062 fn drop ( & mut self ) {
@@ -108,6 +110,35 @@ impl ShmemConf {
108110 self
109111 }
110112
113+ /// Enable tmpfs mode with a specific base directory
114+ ///
115+ /// This will use regular files in the specified directory instead of POSIX shared memory
116+ pub fn use_tmpfs_with_dir < P : AsRef < Path > > ( mut self , base_dir : P ) -> Self {
117+ self . use_tmpfs = true ;
118+ self . tmpfs_base_dir = Some ( PathBuf :: from ( base_dir. as_ref ( ) ) ) ;
119+ self
120+ }
121+
122+ /// Get the tmpfs file path for this configuration
123+ fn get_tmpfs_file_path ( & self ) -> Result < PathBuf , ShmemError > {
124+ if !self . use_tmpfs {
125+ return Err ( ShmemError :: NotInTmpfsMode ) ;
126+ }
127+
128+ let base_dir = self
129+ . tmpfs_base_dir
130+ . as_ref ( )
131+ . ok_or ( ShmemError :: NoTmpfsBaseDir ) ?;
132+
133+ if let Some ( ref os_id) = self . os_id {
134+ // Use os_id as filename
135+ Ok ( base_dir. join ( format ! ( "shmem_{os_id}" ) ) )
136+ } else {
137+ // Generate random filename
138+ Ok ( base_dir. join ( format ! ( "shmem_{:X}" , rand:: random:: <u64 >( ) ) ) )
139+ }
140+ }
141+
111142 /// Create a new mapping using the current configuration
112143 pub fn create ( mut self ) -> Result < Shmem , ShmemError > {
113144 if self . size == 0 {
@@ -121,21 +152,51 @@ impl ShmemConf {
121152 }
122153
123154 // Create the mapping
124- let mapping = match self . os_id {
125- None => {
126- // Generate random ID until one works
155+ let mapping = if self . use_tmpfs {
156+ // tmpfs mode
157+ if self . os_id . is_some ( ) {
158+ // Use specified os_id
159+ let tmpfs_file_path = self . get_tmpfs_file_path ( ) ?;
160+ os_impl:: create_mapping_tmpfs (
161+ tmpfs_file_path
162+ . to_str ( )
163+ . ok_or ( ShmemError :: UnknownOsError ( 0 ) ) ?,
164+ self . size ,
165+ self . mode ,
166+ ) ?
167+ } else {
168+ // Generate random filename until one works
127169 loop {
128- let cur_id = format ! ( "/shmem_{:X}" , rand:: random:: <u64 >( ) ) ;
129- match os_impl:: create_mapping ( & cur_id, self . size , self . mode ) {
170+ let random_path = self . get_tmpfs_file_path ( ) ?;
171+ match os_impl:: create_mapping_tmpfs (
172+ random_path. to_str ( ) . ok_or ( ShmemError :: UnknownOsError ( 0 ) ) ?,
173+ self . size ,
174+ self . mode ,
175+ ) {
130176 Err ( ShmemError :: MappingIdExists ) => continue ,
131177 Ok ( m) => break m,
132- Err ( e) => {
133- return Err ( e) ;
178+ Err ( e) => return Err ( e) ,
179+ }
180+ }
181+ }
182+ } else {
183+ // shm_open mode
184+ match self . os_id {
185+ None => {
186+ // Generate random ID until one works
187+ loop {
188+ let cur_id = format ! ( "/shmem_{:X}" , rand:: random:: <u64 >( ) ) ;
189+ match os_impl:: create_mapping ( & cur_id, self . size , self . mode ) {
190+ Err ( ShmemError :: MappingIdExists ) => continue ,
191+ Ok ( m) => break m,
192+ Err ( e) => return Err ( e) ,
134193 }
135- } ;
194+ }
195+ }
196+ Some ( ref specific_id) => {
197+ os_impl:: create_mapping ( specific_id, self . size , self . mode ) ?
136198 }
137199 }
138- Some ( ref specific_id) => os_impl:: create_mapping ( specific_id, self . size , self . mode ) ?,
139200 } ;
140201 debug ! ( "Created shared memory mapping '{}'" , mapping. unique_id) ;
141202
@@ -153,7 +214,7 @@ impl ShmemConf {
153214
154215 match open_options. open ( flink_path) {
155216 Ok ( mut f) => {
156- // write the shmem uid asap
217+ // write the mapping identifier
157218 if let Err ( e) = f. write ( mapping. unique_id . as_bytes ( ) ) {
158219 let _ = std:: fs:: remove_file ( flink_path) ;
159220 return Err ( ShmemError :: LinkWriteFailed ( e) ) ;
@@ -183,36 +244,50 @@ impl ShmemConf {
183244
184245 /// Opens an existing mapping using the current configuration
185246 pub fn open ( mut self ) -> Result < Shmem , ShmemError > {
186- // Must at least have a flink or an os_id
187- if self . flink_path . is_none ( ) && self . os_id . is_none ( ) {
247+ // Must at least have a flink or an os_id (except in tmpfs mode where we might infer the path)
248+ if self . flink_path . is_none ( ) && self . os_id . is_none ( ) && ! self . use_tmpfs {
188249 debug ! ( "Open called with no file link or unique id..." ) ;
189250 return Err ( ShmemError :: NoLinkOrOsId ) ;
190251 }
191252
192- let mut flink_uid = String :: new ( ) ;
253+ let mut flink_content = String :: new ( ) ;
193254 let mut retry = 0 ;
255+
194256 loop {
195- let unique_id = if let Some ( ref unique_id) = self . os_id {
257+ let target_identifier = if let Some ( ref unique_id) = self . os_id {
196258 retry = 5 ;
197- unique_id. as_str ( )
198- } else {
199- let flink_path = self . flink_path . as_ref ( ) . unwrap ( ) ;
259+ if self . use_tmpfs {
260+ // tmpfs mode: convert os_id to file path
261+ let tmpfs_path = self . get_tmpfs_file_path ( ) ?;
262+ tmpfs_path. to_string_lossy ( ) . to_string ( )
263+ } else {
264+ // shm_open mode: use os_id directly
265+ unique_id. clone ( )
266+ }
267+ } else if let Some ( ref flink_path) = self . flink_path {
268+ // Read from flink file
200269 debug ! (
201270 "Open shared memory from file link {}" ,
202271 flink_path. to_string_lossy( )
203272 ) ;
204- let mut f = match File :: open ( flink_path) {
205- Ok ( f) => f,
206- Err ( e) => return Err ( ShmemError :: LinkOpenFailed ( e) ) ,
207- } ;
208- flink_uid. clear ( ) ;
209- if let Err ( e) = f. read_to_string ( & mut flink_uid) {
210- return Err ( ShmemError :: LinkReadFailed ( e) ) ;
211- }
212- flink_uid. as_str ( )
273+ let mut f = File :: open ( flink_path) . map_err ( ShmemError :: LinkOpenFailed ) ?;
274+ flink_content. clear ( ) ;
275+ f. read_to_string ( & mut flink_content)
276+ . map_err ( ShmemError :: LinkReadFailed ) ?;
277+ flink_content. clone ( )
278+ } else {
279+ return Err ( ShmemError :: NoLinkOrOsId ) ;
280+ } ;
281+
282+ let mapping_result = if self . use_tmpfs {
283+ // tmpfs mode: target_identifier is a file path
284+ os_impl:: open_mapping_tmpfs ( & target_identifier, self . size )
285+ } else {
286+ // shm_open mode: target_identifier is shm ID
287+ os_impl:: open_mapping ( & target_identifier, self . size , & self . ext )
213288 } ;
214289
215- match os_impl :: open_mapping ( unique_id , self . size , & self . ext ) {
290+ match mapping_result {
216291 Ok ( m) => {
217292 self . size = m. map_size ;
218293 self . owner = false ;
@@ -222,8 +297,8 @@ impl ShmemConf {
222297 mapping : m,
223298 } ) ;
224299 }
225- // If we got this failing os_id from the flink, try again in case the shmem owner didnt write the full
226- // unique_id to the file
300+ // If we got this failing from the flink, try again in case the owner didn't write the full
301+ // identifier to the file yet
227302 Err ( ShmemError :: MapOpenFailed ( _) ) if self . os_id . is_none ( ) && retry < 5 => {
228303 retry += 1 ;
229304 std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 50 ) ) ;
0 commit comments