enum ach_status ach_open( ach_channel_t *chan, const char *channel_name, ach_attr_t *attr ) { ach_header_t * shm; size_t len; int fd = -1; if( attr ) memcpy( &chan->attr, attr, sizeof(chan->attr) ); else memset( &chan->attr, 0, sizeof(chan->attr) ); if( attr && attr->map_anon ) { shm = attr->shm; len = sizeof(ach_header_t) + sizeof(ach_index_t)*shm->index_cnt + shm->data_size; }else { if( ! channel_name_ok( channel_name ) ) return ACH_INVALID_NAME; /* open shm */ if( ! channel_name_ok( channel_name ) ) return ACH_INVALID_NAME; if( (fd = fd_for_channel_name( channel_name, 0 )) < 0 ) { return check_errno(); } if( (shm = (ach_header_t*) mmap (NULL, sizeof(ach_header_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0ul) ) == MAP_FAILED ) return ACH_FAILED_SYSCALL; if( ACH_SHM_MAGIC_NUM != shm->magic ) return ACH_BAD_SHM_FILE; /* calculate mmaping size */ len = sizeof(ach_header_t) + sizeof(ach_index_t)*shm->index_cnt + shm->data_size; /* remap */ if( -1 == munmap( shm, sizeof(ach_header_t) ) ) return check_errno(); if( (shm = (ach_header_t*) mmap( NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0ul) ) == MAP_FAILED ) return check_errno(); } /* Check guard bytes */ { enum ach_status r = check_guards(shm); if( ACH_OK != r ) return r; } /* initialize struct */ chan->fd = fd; chan->len = len; chan->shm = shm; chan->seq_num = 0; chan->next_index = 1; chan->cancel = 0; return ACH_OK; }
static enum ach_status shmfile_for_channel_name( const char *name, char *buf, size_t n ) { if( n < ACH_CHAN_NAME_MAX + 16 ) return ACH_BUG; if( !channel_name_ok(name) ) return ACH_INVALID_NAME; strcpy( buf, ACH_CHAN_NAME_PREFIX ); strncat( buf, name, ACH_CHAN_NAME_MAX ); return ACH_OK; }
enum ach_status ach_create( const char *channel_name, size_t frame_cnt, size_t frame_size, ach_create_attr_t *attr) { ach_header_t *shm; int fd; size_t len; /* fixme: truncate */ /* open shm */ { len = sizeof( ach_header_t) + frame_cnt*sizeof( ach_index_t ) + frame_cnt*frame_size + 3*sizeof(uint64_t); if( attr && attr->map_anon ) { /* anonymous (heap) */ shm = (ach_header_t *) malloc( len ); fd = -1; }else { int oflag = O_EXCL | O_CREAT; /* shm */ if( ! channel_name_ok( channel_name ) ) return ACH_INVALID_NAME; if( attr ) { if( attr->truncate ) oflag &= ~O_EXCL; } if( (fd = fd_for_channel_name( channel_name, oflag )) < 0 ) { return check_errno();; } { /* make file proper size */ /* FreeBSD needs ftruncate before mmap, Linux can do either order */ int r; int i = 0; do { r = ftruncate( fd, (off_t) len ); }while(-1 == r && EINTR == errno && i++ < ACH_INTR_RETRY); if( -1 == r ) { DEBUG_PERROR( "ftruncate"); return ACH_FAILED_SYSCALL; } } /* mmap */ if( (shm = (ach_header_t *)mmap( NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0) ) == MAP_FAILED ) { DEBUG_PERROR("mmap"); DEBUGF("mmap failed %s, len: %"PRIuPTR", fd: %d\n", strerror(errno), len, fd); return ACH_FAILED_SYSCALL; } } memset( shm, 0, len ); shm->len = len; } { /* initialize synchronization */ { /* initialize condition variables */ int r; pthread_condattr_t cond_attr; if( (r = pthread_condattr_init(&cond_attr)) ) { DEBUG_PERROR("pthread_condattr_init"); return ACH_FAILED_SYSCALL; } /* Process Shared */ if( ! (attr && attr->map_anon) ) { /* Set shared if not anonymous mapping Default will be private. */ if( (r = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) ) { DEBUG_PERROR("pthread_condattr_setpshared"); return ACH_FAILED_SYSCALL; } } /* Clock */ if( attr && attr->set_clock ) { if( (r = pthread_condattr_setclock(&cond_attr, attr->clock)) ) { DEBUG_PERROR("pthread_condattr_setclock"); return ACH_FAILED_SYSCALL; } } else { if( (r = pthread_condattr_setclock(&cond_attr, ACH_DEFAULT_CLOCK)) ) { DEBUG_PERROR("pthread_condattr_setclock"); return ACH_FAILED_SYSCALL; } } if( (r = pthread_cond_init(&shm->sync.cond, &cond_attr)) ) { DEBUG_PERROR("pthread_cond_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_condattr_destroy(&cond_attr)) ) { DEBUG_PERROR("pthread_condattr_destroy"); return ACH_FAILED_SYSCALL; } } { /* initialize mutex */ int r; pthread_mutexattr_t mutex_attr; if( (r = pthread_mutexattr_init(&mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED)) ) { DEBUG_PERROR("pthread_mutexattr_setpshared"); return ACH_FAILED_SYSCALL; } /* Error Checking Mutex */ #ifdef PTHREAD_MUTEX_ERRORCHECK_NP if( (r = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK_NP)) ) { DEBUG_PERROR("pthread_mutexattr_settype"); return ACH_FAILED_SYSCALL; } #endif /* Priority Inheritance Mutex */ #ifdef PTHREAD_PRIO_INHERIT if( (r = pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT)) ) { DEBUG_PERROR("pthread_mutexattr_setprotocol"); return ACH_FAILED_SYSCALL; } #endif if( (r = pthread_mutex_init(&shm->sync.mutex, &mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_init"); return ACH_FAILED_SYSCALL; } if( (r = pthread_mutexattr_destroy(&mutex_attr)) ) { DEBUG_PERROR("pthread_mutexattr_destroy"); return ACH_FAILED_SYSCALL; } } } /* initialize name */ strncpy( shm->name, channel_name, ACH_CHAN_NAME_MAX ); /* initialize counts */ shm->index_cnt = frame_cnt; shm->index_head = 0; shm->index_free = frame_cnt; shm->data_head = 0; shm->data_free = frame_cnt * frame_size; shm->data_size = frame_cnt * frame_size; assert( sizeof( ach_header_t ) + shm->index_free * sizeof( ach_index_t ) + shm->data_free + 3*sizeof(uint64_t) == len ); *ACH_SHM_GUARD_HEADER(shm) = ACH_SHM_GUARD_HEADER_NUM; *ACH_SHM_GUARD_INDEX(shm) = ACH_SHM_GUARD_INDEX_NUM; *ACH_SHM_GUARD_DATA(shm) = ACH_SHM_GUARD_DATA_NUM; shm->magic = ACH_SHM_MAGIC_NUM; if( attr && attr->map_anon ) { attr->shm = shm; } else { int r; /* remove mapping */ r = munmap(shm, len); if( 0 != r ){ DEBUG_PERROR("munmap"); return ACH_FAILED_SYSCALL; } /* close file */ int i = 0; do { IFDEBUG( i ? DEBUGF("Retrying close()\n"):0 ); r = close(fd); }while( -1 == r && EINTR == errno && i++ < ACH_INTR_RETRY ); if( -1 == r ){ DEBUG_PERROR("close"); return ACH_FAILED_SYSCALL; } } return ACH_OK; }