The Tape Server holds the most recent fully constructed data buffers in shared memory where they are available for access by data analysis programs (e.g. MTsort). The data buffers include the standard 24 byte block header.
The shared memory is accessed using a name (SunOS shm_open - default value /SHM_110205 or Win32 CreateFileMapping - default value SHM_110205) or key (Linux shmget -default value 110205).
In non default cases simply replace 10205 with the ID used when you start the Tape Server.
The shared memory area can only be access in Read mode.
// Structure of the Shared Data Area Header #define NBLOCKS 64 /* current number of buffers used - must be 2**n */ #define MAX_BUFFERS 128 /* unchangeable maximum because of header structure */ typedef struct s_buffer_header { int buffer_offset; // offset to first buffer int buffer_number; // number of buffers int buffer_length; // length of buffers int buffer_next; // next buffer to be written int buffer_max; // MAX_BUFFERS int buffer_spare1; int buffer_spare2; int buffer_spare3; long long buffer_currentage; // long long buffer_age[MAX_BUFFERS]; int buffer_status[MAX_BUFFERS]; } BUFFER_HEADER;
A sample program demonstrating access to the shared buffer area.
This is available as the program peek in the Tape Server distribution.
#ifdef WIN32 #include <windows.h> #endif #ifdef LINUX #include <sys/types.h> #include <sys/shm.h> #endif #ifdef SOLARIS #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #endif #include <stdio.h> #include <stdlib.h> /* format of the data buffer area header */ #define NBLOCKS 64 /* current number of buffers used - must be 2**n */ #define MAX_BUFFERS 128 /* unchangeable maximum because of header structure */ typedef struct s_buffer_header { int buffer_offset; /* offset to first buffer */ int buffer_number; /* number of buffers */ int buffer_length; /* length of buffers */ int buffer_next; /* next buffer to be written */ int buffer_max; /* MAX_BUFFERS */ int buffer_spare1; int buffer_spare2; int buffer_spare3; #ifdef WIN32 long buffer_currentage; long padding1; long buffer_age[MAX_BUFFERS]; long padding2[MAX_BUFFERS]; #else long long buffer_currentage; long long buffer_age[MAX_BUFFERS]; #endif } BUFFER_HEADER; #ifdef WIN32 void ReportError (char * s) { LPVOID lpMsgBuf; DWORD ErrNo; ErrNo = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrNo, 0, (LPTSTR) &lpMsgBuf, 0, NULL ); printf("%s: error %d - %s\n", s, ErrNo, lpMsgBuf); LocalFree (lpMsgBuf); } #endif int main (int argc, char * argv[]) { int offset, number, length, next, max; int i, j; #ifdef WIN32 unsigned long cage, age; #else unsigned long long cage, age; #endif #ifndef LINUX char object_name[16]; #endif #ifdef LINUX int shmid; key_t shmkey = 110205; #endif #ifdef SOLARIS int shmid; int shmkey = 110205; #endif #ifdef WIN32 HANDLE shmid; int shmkey = 110205; #endif short * shm_bufferarea; BUFFER_HEADER * baseaddress; short * bufferaddress; #ifdef SOLARIS /* create a file mapped object (MASTER) or obtain ID of existing object */ sprintf(object_name,"/SHM_%d", shmkey); shmid = shm_open(object_name, O_RDONLY, (mode_t) 0); if (shmid == -1) { perror("shm_open"); exit(1); } #endif #ifdef LINUX shmid = shmget(shmkey, 0, SHM_R); if (shmid == -1) {perror("shmget"); exit(1);} #endif #ifdef WIN32 /* create a file mapped object */ sprintf(object_name,"SHM_%d", shmkey); shmid = CreateFileMapping( (HANDLE) INVALID_HANDLE_VALUE, NULL, PAGE_READONLY, (DWORD) 0, (DWORD) 1, object_name); if (!shmid) { /* give up! */ ReportError("CreatFileMapping"); ExitProcess(1); } #endif #ifdef SOLARIS /* attach the memory segment */ shm_bufferarea = mmap((caddr_t) NULL, (size_t) 0x400000, PROT_READ, MAP_SHARED, shmid, (off_t) 0); if (shm_bufferarea == (void *) MAP_FAILED) { perror("mmap"); exit(1); } close(shmid); #endif #ifdef LINUX shm_bufferarea = shmat(shmid, (void *) 0, SHM_RDONLY); if (shm_bufferarea == (void *) -1) {perror("shmat"); exit(1);} #endif #ifdef WIN32 /* map a view of the file mapped object */ shm_bufferarea = MapViewOfFile(shmid, FILE_MAP_READ, 0, 0, 0); if (shm_bufferarea == NULL) { ReportError("MapViewOfFile"); ExitProcess(1); } #endif printf("Shared buffer area located at 0x%x\n", shm_bufferarea); baseaddress = (BUFFER_HEADER *) shm_bufferarea; offset = baseaddress->buffer_offset; number = baseaddress->buffer_number; length = baseaddress->buffer_length; next = baseaddress->buffer_next; max = baseaddress->buffer_max; cage = baseaddress->buffer_currentage; printf ("current control information\n"); #ifndef WIN32 printf ("offset=%d number=%d length=%d next=%d max=%d age=%lld\n", offset, number, length, next, max, cage); #else printf ("offset=%d number=%d length=%d next=%d max=%d age=%d\n", offset, number, length, next, max, cage); #endif for (i = 0; i < number; i++) { age = baseaddress->buffer_age[i]; #ifndef WIN32 printf(" %lld", age); #else printf(" %d", age); #endif } printf("\n"); i = (next - 1) & (number -1); if (baseaddress->buffer_age[i] != 0) { /* print out start of lastest data block */ bufferaddress = (short *) ((char *)shm_bufferarea + offset + (length * i)); #ifndef WIN32 printf ("buffer %d, age %lld, address 0x%x\n", i, baseaddress->buffer_age[i], bufferaddress); #else printf ("buffer %d, age %d, address 0x%x\n", i, baseaddress->buffer_age[i], bufferaddress); #endif for (i = 0; i < 64; i++) { for (j = 0; j < 16; j++) { printf(" 0x%04x", (*bufferaddress & 0x0000ffff)); bufferaddress++; } printf ("\n"); } printf ("\n"); } #ifdef WIN32 ExitProcess(0); #else exit(0); #endif }