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
}