/*
 * $Id: imshared.hxx,v 4.2 2004/05/23 23:13:53 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 * Include file for imshared.C
 *
 * Contains definitions for mput, a subclass of `put' which does the
 * same thing, but uses a segment of shared memory instead of a data
 * stream for image data exchange
 *
 * Hugues Talbot	26 Mar 2000
 *      
 *-----------------------------------------------------------------------*/

#ifndef IMSHARED_H
#define IMSHARED_H

// valid for all type of shared memory
#define SHM_SIZE 400000     // big enough for one 512*768 char buffer

#ifdef HAVE_SYSV_IPC
// we are using semaphores and shared memory, which are SVR4-specific features
#include <stdio.h>
#include <string.h>
#include "imunistd.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <signal.h>
#include <setjmp.h>

// this is WEIRD! but required on Unices
#ifdef Linux
#  if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
#warning Incorrect <sys/sem.h>, workaround used.
/* union semun is defined by including <sys/sem.h> */
#  else
/* according to X/OPEN we have to define it ourselves (!) */
union semun {
    int val;                    /* value for SETVAL */
    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
    unsigned short int *array;  /* array for GETALL, SETALL */
    struct seminfo *__buf;      /* buffer for IPC_INFO */
};
#  endif // Gnu stuff
#endif // Linux

#ifdef __CYGWIN__ // cygwin has an implementation of SYSV shared memory...
union semun {
    int val;                    /* value for SETVAL */
    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;     /* array for GETALL, SETALL */
};
#endif


/* same X/OPEN stuff. there must be a good reason for it... */
#if defined(OSF1) || defined(Solaris)
union semun {
  int val;
  struct semid_ds *buf;
  unsigned short *array;
};
#endif // OSF1

typedef enum {
  SEM_ACS = 0, 
  SEM_RD = 1, 
  SEM_WR = 2
} semnames;

#define FPATH1   "/tmp/willcrash"  // must point to a file that can be opened



// same as put, using shared memory instead of data stream
class putm:public put {
    key_t           sem_key, shm_key;
    int             semid, shmid;
    bool            shm_setup_ok, sem_setup_ok;
    char           *data; // pointer to shared memory segment
    // the pathame must be the same across all instances of putm.
    static char     ref_pathname[L_tmpnam+1];
    // private methods.
    int setup_shm(void);
    int get_data(char *dest);

public:
    putm();
    ~putm();
    int perform(vector<string> &l, string &result);
    int sem_reset(void);
    // static methods
    static char *unique_filename(void) {return ref_pathname;}
    // this should be called ONLY once.
    static void setPathToEmpty(void) {ref_pathname[0] = '\0';}
};

#else
// shared memory not available
// this is basically a useless class.
class putm:public put {
    int perform(vector<string> &l, string &result);
};
#endif // HAVE_SYSV_IPC

#ifdef HAVE_POSIX_IPC

#include <semaphore.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#define STR_ACCESS   "_ACCESS"
#define STR_READ     "_READ"
#define STR_WRITE    "_WRITE"
#define STR_SHM      "_SHM"

#define IPC_FILE_MODE 0600 // rw for creator only, must be Octal!

class putp:public put {
    enum {SEM_ACCESS, SEM_READ, SEM_WRITE}; // we'll use 3 semaphores

    char         *data; // pointer to shared memory area
    bool          shm_setup_ok, sem_setup_ok;
    sem_t        *putsem[3]; // array of 3 semaphores
    int           tempfd, shmfd; // file descriptor to temporary file
    char          errbuff[DFLTSTRLEN], perrbuff[DFLTSTRLEN]; // error buffer in case something goes wrong
    char         *px_templ_name;
    // the pathame must be the same across all instances of putp.
    static const char *posix_tmp_path;
    // private methods
    sem_t *init_sem(const char *postfix, int which_sem, int start_val);
    void   remove_sem(const char *postfix);
    void   remove_shm(void);
    char  *px_ipc_name(const char *name); // from unpv2
    void   errformat(const char *msg_prefix, int myerrno);
    int    setup_shm(void);
    int    get_data(char *dest);
public:
    putp();
    ~putp();
    int perform(vector<string> &l, string &result);
    static char       ref_pathname[DFLTSTRLEN];
};

#else // HAVE_POSIX_IPC

class putp:public put {
public:
    int perform(vector<string> &l, string &result);
};

#endif // HAVE_POSIX_IPC

#endif // IMSHARED_H
