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));
266
id = shmget( key, 0, 0 );
268
_PR_MD_MAP_DEFAULT_ERROR( errno );
269
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
270
("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno));
274
urc = shmctl( id, IPC_RMID, NULL );
277
_PR_MD_MAP_DEFAULT_ERROR( errno );
278
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
279
("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname ));
283
urc = unlink( ipcname );
285
_PR_MD_MAP_UNLINK_ERROR( errno );
286
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
287
("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname ));
292
} /* end _MD_DeleteSharedMemory() */
295
** Implementation for Posix
297
#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY
298
#include <sys/mman.h>
300
#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory
301
#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory
302
#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory
303
#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory
304
#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory
306
struct _MDSharedMemory {
310
extern PRSharedMemory * _MD_OpenSharedMemory(
317
PRStatus rc = PR_SUCCESS;
320
char ipcname[PR_IPC_NAME_SIZE];
322
rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
323
if ( PR_FAILURE == rc )
325
PR_SetError( PR_UNKNOWN_ERROR , errno );
326
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
327
("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
331
shm = PR_NEWZAP( PRSharedMemory );
334
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
335
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory"));
339
shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 );
340
if ( NULL == shm->ipcname )
342
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 );
343
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory"));
347
/* copy args to struct */
348
strcpy( shm->ipcname, ipcname );
352
shm->ident = _PR_SHM_IDENT;
355
** Create the shared memory
357
if ( flags & PR_SHM_CREATE ) {
358
int oflag = (O_CREAT | O_RDWR);
360
if ( flags & PR_SHM_EXCL )
362
shm->id = shm_open( shm->ipcname, oflag, shm->mode );
364
shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode );
367
if ( -1 == shm->id ) {
368
_PR_MD_MAP_DEFAULT_ERROR( errno );
369
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
370
("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d",
371
shm->ipcname, PR_GetOSError()));
372
PR_DELETE( shm->ipcname );
377
end = ftruncate( shm->id, shm->size );
379
_PR_MD_MAP_DEFAULT_ERROR( errno );
380
PR_LOG(_pr_shm_lm, PR_LOG_DEBUG,
381
("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d",
383
PR_DELETE( shm->ipcname );
389
} /* end _MD_OpenSharedMemory() */
391
extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags )
394
PRIntn prot = (PROT_READ | PROT_WRITE);
396
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
398
if ( PR_SHM_READONLY == flags)
401
addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 );
402
if ((void*)-1 == addr )
404
_PR_MD_MAP_DEFAULT_ERROR( errno );
405
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
406
("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d",
407
shm->ipcname, PR_GetOSError()));
410
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
411
("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr));
417
extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr )
419
PRStatus rc = PR_SUCCESS;
422
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
424
urc = munmap( addr, shm->size );
428
_PR_MD_MAP_DEFAULT_ERROR( errno );
429
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
430
("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d",
431
shm->ipcname, PR_GetOSError()));
436
extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm )
440
PR_ASSERT( shm->ident == _PR_SHM_IDENT );
442
urc = close( shm->id );
444
_PR_MD_MAP_CLOSE_ERROR( errno );
445
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
446
("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError()));
449
PR_DELETE( shm->ipcname );
454
extern PRStatus _MD_DeleteSharedMemory( const char *name )
456
PRStatus rc = PR_SUCCESS;
458
char ipcname[PR_IPC_NAME_SIZE];
460
rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm );
461
if ( PR_FAILURE == rc )
463
PR_SetError( PR_UNKNOWN_ERROR , errno );
464
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
465
("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name ));
469
urc = shm_unlink( ipcname );
472
_PR_MD_MAP_DEFAULT_ERROR( errno );
473
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
474
("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d",
475
ipcname, PR_GetOSError()));
477
PR_LOG( _pr_shm_lm, PR_LOG_DEBUG,
478
("_MD_DeleteSharedMemory(): %s, success", ipcname));
482
} /* end _MD_DeleteSharedMemory() */
488
** Unix implementation for anonymous memory (file) mapping
490
extern PRLogModuleInfo *_pr_shma_lm;
494
extern PRFileMap* _md_OpenAnonFileMap(
497
PRFileMapProtect prot
500
PRFileMap *fm = NULL;
506
pid_t pid = getpid(); /* for generating filename */
507
PRThread *tid = PR_GetCurrentThread(); /* for generating filename */
508
int incr; /* for generating filename */
509
const int maxTries = 20; /* maximum # attempts at a unique filename */
510
PRInt64 size64; /* 64-bit version of 'size' */
513
** generate a filename from input and runtime environment
514
** open the file, unlink the file.
515
** make maxTries number of attempts at uniqueness in the filename
517
for ( incr = 0; incr < maxTries ; incr++ ) {
518
genName = PR_smprintf( "%s/.NSPR-AFM-%d-%p.%d",
519
dirName, (int) pid, tid, incr );
520
if ( NULL == genName ) {
521
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
522
("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename"));
526
/* create the file */
527
osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode );
529
if ( EEXIST == errno ) {
530
PR_smprintf_free( genName );
531
continue; /* name exists, try again */
533
_PR_MD_MAP_OPEN_ERROR( errno );
534
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
535
("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d",
536
genName, PR_GetOSError()));
537
PR_smprintf_free( genName );
541
break; /* name generation and open successful, break; */
544
if ( incr == maxTries ) {
545
PR_ASSERT( -1 == osfd );
546
PR_ASSERT( EEXIST == errno );
547
_PR_MD_MAP_OPEN_ERROR( errno );
551
urc = unlink( genName );
553
_PR_MD_MAP_UNLINK_ERROR( errno );
554
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
555
("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno));
556
PR_smprintf_free( genName );
560
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
561
("_md_OpenAnonFileMap(): unlink(): %s", genName ));
563
PR_smprintf_free( genName );
565
fd = PR_ImportFile( osfd );
567
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
568
("_md_OpenAnonFileMap(): PR_ImportFile(): failed"));
571
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
572
("_md_OpenAnonFileMap(): fd: %p", fd ));
574
urc = ftruncate( fd->secret->md.osfd, size );
576
_PR_MD_MAP_DEFAULT_ERROR( errno );
577
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
578
("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno));
582
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
583
("_md_OpenAnonFileMap(): ftruncate(): size: %d", size ));
585
LL_UI2L(size64, size); /* PRSize (size_t) is unsigned */
586
fm = PR_CreateFileMap( fd, size64, prot );
588
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
589
("PR_OpenAnonFileMap(): failed"));
593
fm->md.isAnonFM = PR_TRUE; /* set fd close */
595
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
596
("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm ));
600
} /* end md_OpenAnonFileMap() */
603
** _md_ExportFileMapAsString()
607
extern PRStatus _md_ExportFileMapAsString(
614
PRIntn prot = (PRIntn)fm->prot;
616
written = PR_snprintf( buf, bufSize, "%ld:%d",
617
fm->fd->secret->md.osfd, prot );
619
return((written == -1)? PR_FAILURE : PR_SUCCESS);
620
} /* end _md_ExportFileMapAsString() */
623
extern PRFileMap * _md_ImportFileMapFromString(
629
PRIntn prot; /* really: a PRFileMapProtect */
631
PRFileMap *fm = NULL; /* default return value */
634
PR_sscanf( fmstring, "%ld:%d", &osfd, &prot );
636
/* import the os file descriptor */
637
fd = PR_ImportFile( osfd );
639
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
640
("_md_ImportFileMapFromString(): PR_ImportFile() failed"));
644
rc = PR_GetOpenFileInfo64( fd, &info );
645
if ( PR_FAILURE == rc ) {
646
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
647
("_md_ImportFileMapFromString(): PR_GetOpenFileInfo64() failed"));
651
fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot );
653
PR_LOG( _pr_shma_lm, PR_LOG_DEBUG,
654
("_md_ImportFileMapFromString(): PR_CreateFileMap() failed"));
659
} /* end _md_ImportFileMapFromString() */