1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 ** uxshm.c -- Unix Implementations NSPR Named Shared Memory
52 extern PRLogModuleInfo *_pr_shm_lm;
55 #define NSPR_IPC_SHM_KEY 'b'
57 ** Implementation for System V
59 #if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY
62 #include <sys/types.h>
65 #define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
66 #define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
67 #define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
68 #define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
69 #define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
71 extern PRSharedMemory * _MD_OpenSharedMemory(
78 PRStatus rc = PR_SUCCESS;
81 char ipcname[PR_IPC_NAME_SIZE];
83 rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
84 if ( PR_FAILURE == rc )
86 _PR_MD_MAP_DEFAULT_ERROR( errno );
87 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
88 ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
92 shm = PR_NEWZAP( PRSharedMemory );
95 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
96 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
100 shm->ipcname = (char*)PR_MALLOC( strlen( ipcname ) + 1 );
101 if ( NULL == shm->ipcname )
103 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
104 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
109 /* copy args to struct */
110 strcpy( shm->ipcname, ipcname );
114 shm->ident = _PR_SHM_IDENT;
116 /* create the file first */
117 if ( flags & PR_SHM_CREATE ) {
118 int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode );
120 _PR_MD_MAP_OPEN_ERROR( errno );
121 PR_FREEIF( shm->ipcname );
125 if ( close(osfd) == -1 ) {
126 _PR_MD_MAP_CLOSE_ERROR( errno );
127 PR_FREEIF( shm->ipcname );
133 /* hash the shm.name to an ID */
134 key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY );
138 _PR_MD_MAP_DEFAULT_ERROR( errno );
139 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
140 ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname));
141 PR_FREEIF( shm->ipcname );
146 /* get the shared memory */
147 if ( flags & PR_SHM_CREATE ) {
148 shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL));
149 if ( shm->id >= 0 ) {
152 if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) {
153 PR_SetError( PR_FILE_EXISTS_ERROR, errno );
154 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
155 ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno));
156 PR_FREEIF(shm->ipcname);
162 shm->id = shmget( key, shm->size, shm->mode );
163 if ( -1 == shm->id ) {
164 _PR_MD_MAP_DEFAULT_ERROR( errno );
165 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
166 ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno));
167 PR_FREEIF(shm->ipcname);
173 } /* end _MD_OpenSharedMemory() */
175 extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
178 PRUint32 aFlags = shm->mode;
180 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
182 aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0;
184 addr = shmat( shm->id, NULL, aFlags );
185 if ( (void*)-1 == addr )
187 _PR_MD_MAP_DEFAULT_ERROR( errno );
188 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
189 ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d",
190 shm->ipcname, PR_GetOSError() ));
197 extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
199 PRStatus rc = PR_SUCCESS;
202 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
208 _PR_MD_MAP_DEFAULT_ERROR( errno );
209 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
210 ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname ));
216 extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
218 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
220 PR_FREEIF(shm->ipcname);
226 extern PRStatus _MD_DeleteSharedMemory( const char *name )
228 PRStatus rc = PR_SUCCESS;
232 char ipcname[PR_IPC_NAME_SIZE];
234 rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
235 if ( PR_FAILURE == rc )
237 PR_SetError( PR_UNKNOWN_ERROR , errno );
238 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
239 ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
243 /* create the file first */
245 int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 );
247 _PR_MD_MAP_OPEN_ERROR( errno );
248 return( PR_FAILURE );
250 if ( close(osfd) == -1 ) {
251 _PR_MD_MAP_CLOSE_ERROR( errno );
252 return( PR_FAILURE );
256 /* hash the shm.name to an ID */
257 key = ftok( ipcname, NSPR_IPC_SHM_KEY );
261 _PR_MD_MAP_DEFAULT_ERROR( errno );
262 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
263 ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname));
267 /* In Symbian OS the system imposed minimum is 1 byte, instead of ZERO */
268 id = shmget( key, 1, 0 );
270 id = shmget( key, 0, 0 );
273 _PR_MD_MAP_DEFAULT_ERROR( errno );
274 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
275 ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno));
279 urc = shmctl( id, IPC_RMID, NULL );
282 _PR_MD_MAP_DEFAULT_ERROR( errno );
283 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
284 ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname ));
288 urc = unlink( ipcname );
290 _PR_MD_MAP_UNLINK_ERROR( errno );
291 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
292 ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname ));
297 } /* end _MD_DeleteSharedMemory() */
300 ** Implementation for Posix
302 #elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
303 #include <sys/mman.h>
305 #define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
306 #define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
307 #define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
308 #define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
309 #define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
311 struct _MDSharedMemory {
315 extern PRSharedMemory * _MD_OpenSharedMemory(
322 PRStatus rc = PR_SUCCESS;
325 char ipcname[PR_IPC_NAME_SIZE];
327 rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
328 if ( PR_FAILURE == rc )
330 PR_SetError( PR_UNKNOWN_ERROR , errno );
331 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
332 ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
336 shm = PR_NEWZAP( PRSharedMemory );
339 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
340 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
344 shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
345 if ( NULL == shm->ipcname )
347 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
348 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
352 /* copy args to struct */
353 strcpy( shm->ipcname, ipcname );
357 shm->ident = _PR_SHM_IDENT;
360 ** Create the shared memory
362 if ( flags & PR_SHM_CREATE ) {
363 int oflag = (O_CREAT | O_RDWR);
365 if ( flags & PR_SHM_EXCL )
367 shm->id = shm_open( shm->ipcname, oflag, shm->mode );
369 shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode );
372 if ( -1 == shm->id ) {
373 _PR_MD_MAP_DEFAULT_ERROR( errno );
374 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
375 ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d",
376 shm->ipcname, PR_GetOSError()));
377 PR_DELETE( shm->ipcname );
382 end = ftruncate( shm->id, shm->size );
384 _PR_MD_MAP_DEFAULT_ERROR( errno );
385 PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
386 ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d",
388 PR_DELETE( shm->ipcname );
394 } /* end _MD_OpenSharedMemory() */
396 extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
399 PRIntn prot = (PROT_READ | PROT_WRITE);
401 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
403 if ( PR_SHM_READONLY == flags)
406 addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 );
407 if ((void*)-1 == addr )
409 _PR_MD_MAP_DEFAULT_ERROR( errno );
410 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
411 ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d",
412 shm->ipcname, PR_GetOSError()));
415 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
416 ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr));
422 extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
424 PRStatus rc = PR_SUCCESS;
427 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
429 urc = munmap( addr, shm->size );
433 _PR_MD_MAP_DEFAULT_ERROR( errno );
434 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
435 ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d",
436 shm->ipcname, PR_GetOSError()));
441 extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
445 PR_ASSERT( shm->ident == _PR_SHM_IDENT );
447 urc = close( shm->id );
449 _PR_MD_MAP_CLOSE_ERROR( errno );
450 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
451 ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError()));
454 PR_DELETE( shm->ipcname );
459 extern PRStatus _MD_DeleteSharedMemory( const char *name )
461 PRStatus rc = PR_SUCCESS;
463 char ipcname[PR_IPC_NAME_SIZE];
465 rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
466 if ( PR_FAILURE == rc )
468 PR_SetError( PR_UNKNOWN_ERROR , errno );
469 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
470 ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
474 urc = shm_unlink( ipcname );
477 _PR_MD_MAP_DEFAULT_ERROR( errno );
478 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
479 ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d",
480 ipcname, PR_GetOSError()));
482 PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
483 ("_MD_DeleteSharedMemory(): %s, success", ipcname));
487 } /* end _MD_DeleteSharedMemory() */
493 ** Unix implementation for anonymous memory (file) mapping
495 extern PRLogModuleInfo *_pr_shma_lm;
499 extern PRFileMap* _md_OpenAnonFileMap(
502 PRFileMapProtect prot
505 PRFileMap *fm = NULL;
511 pid_t pid = getpid(); /* for generating filename */
512 PRThread *tid = PR_GetCurrentThread(); /* for generating filename */
513 int incr; /* for generating filename */
514 const int maxTries = 20; /* maximum # attempts at a unique filename */
515 PRInt64 size64; /* 64-bit version of 'size' */
518 ** generate a filename from input and runtime environment
519 ** open the file, unlink the file.
520 ** make maxTries number of attempts at uniqueness in the filename
522 for ( incr = 0; incr < maxTries ; incr++ ) {
524 #define NSPR_AFM_FILENAME "%s\\NSPR-AFM-%d-%p.%d"
526 #define NSPR_AFM_FILENAME "%s/.NSPR-AFM-%d-%p.%d"
528 genName = PR_smprintf( NSPR_AFM_FILENAME,
529 dirName, (int) pid, tid, incr );
530 if ( NULL == genName ) {
531 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
532 ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename"));
536 /* create the file */
537 osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode );
539 if ( EEXIST == errno ) {
540 PR_smprintf_free( genName );
541 continue; /* name exists, try again */
543 _PR_MD_MAP_OPEN_ERROR( errno );
544 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
545 ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d",
546 genName, PR_GetOSError()));
547 PR_smprintf_free( genName );
551 break; /* name generation and open successful, break; */
554 if ( incr == maxTries ) {
555 PR_ASSERT( -1 == osfd );
556 PR_ASSERT( EEXIST == errno );
557 _PR_MD_MAP_OPEN_ERROR( errno );
561 urc = unlink( genName );
562 #if defined(SYMBIAN) && defined(__WINS__)
563 /* If it is being used by the system or another process, Symbian OS
564 * Emulator(WINS) considers this an error. */
565 if ( -1 == urc && EACCES != errno ) {
569 _PR_MD_MAP_UNLINK_ERROR( errno );
570 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
571 ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno));
572 PR_smprintf_free( genName );
576 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
577 ("_md_OpenAnonFileMap(): unlink(): %s", genName ));
579 PR_smprintf_free( genName );
581 fd = PR_ImportFile( osfd );
583 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
584 ("_md_OpenAnonFileMap(): PR_ImportFile(): failed"));
587 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
588 ("_md_OpenAnonFileMap(): fd: %p", fd ));
590 urc = ftruncate( fd->secret->md.osfd, size );
592 _PR_MD_MAP_DEFAULT_ERROR( errno );
593 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
594 ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno));
598 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
599 ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size ));
601 LL_UI2L(size64, size); /* PRSize (size_t) is unsigned */
602 fm = PR_CreateFileMap( fd, size64, prot );
604 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
605 ("PR_OpenAnonFileMap(): failed"));
609 fm->md.isAnonFM = PR_TRUE; /* set fd close */
611 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
612 ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm ));
616 } /* end md_OpenAnonFileMap() */
619 ** _md_ExportFileMapAsString()
623 extern PRStatus _md_ExportFileMapAsString(
630 PRIntn prot = (PRIntn)fm->prot;
632 written = PR_snprintf( buf, bufSize, "%ld:%d",
633 fm->fd->secret->md.osfd, prot );
635 return((written == -1)? PR_FAILURE : PR_SUCCESS);
636 } /* end _md_ExportFileMapAsString() */
639 extern PRFileMap * _md_ImportFileMapFromString(
645 PRIntn prot; /* really: a PRFileMapProtect */
647 PRFileMap *fm = NULL; /* default return value */
650 PR_sscanf( fmstring, "%ld:%d", &osfd, &prot );
652 /* import the os file descriptor */
653 fd = PR_ImportFile( osfd );
655 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
656 ("_md_ImportFileMapFromString(): PR_ImportFile() failed"));
660 rc = PR_GetOpenFileInfo64( fd, &info );
661 if ( PR_FAILURE == rc ) {
662 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
663 ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo64() failed"));
667 fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot );
669 PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
670 ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed"));
675 } /* end _md_ImportFileMapFromString() */