mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-18 00:49:09 +09:00
1055 lines
35 KiB
C
1055 lines
35 KiB
C
/*
|
|
* Copyright (c) 2010,2011 Joshua V Dillon
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or
|
|
* without modification, are permitted provided that the
|
|
* following conditions are met:
|
|
* * Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
* * Neither the name of the author nor the names of its
|
|
* contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY JOSHUA V DILLON ''AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOSHUA
|
|
* V DILLON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <string.h>
|
|
#include <sys/shm.h>
|
|
#include <ctype.h>
|
|
#include "sharedmatrix.h"
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Matlab gateway function */
|
|
/* */
|
|
/* (see sharedmatrix.m for description) */
|
|
/* ------------------------------------------------------------------------- */
|
|
void mexFunction( int nlhs, mxArray *plhs[],
|
|
int nrhs, const mxArray *prhs[] )
|
|
{
|
|
/* mex inputs */
|
|
const mxArray *mxDirective; /* directive {clone, attach, detach, free} */
|
|
const mxArray *mxShmKey; /* name of the shared memory segment */
|
|
const mxArray *mxInput; /* input array (for clone) */
|
|
/* mex outputs */
|
|
mxArray *mxOutput=NULL;
|
|
|
|
/* for storing directive (string) input */
|
|
char directive[MAXDIRECTIVELEN+1];
|
|
|
|
/* for working with shared memory ... */
|
|
key_t shmkey=0;
|
|
size_t shmsiz=0; /* apparently you can attach w/o specifying this */
|
|
size_t shmsiz_tmp=0; /* for shallowrestore recursion */
|
|
int shmid;
|
|
char *shm=NULL;
|
|
|
|
/* for storing the mxArrays ... */
|
|
header_t hdr;
|
|
data_t dat;
|
|
|
|
/* check min number of arguments */
|
|
if ( nrhs<2 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix",
|
|
"Minimum input arguments missing; must supply directive and key.");
|
|
|
|
/* assign inputs */
|
|
mxDirective = prhs[0];
|
|
mxShmKey = prhs[1];
|
|
|
|
/* get directive (ARGUMENT 0) */
|
|
if ( mxGetString(mxDirective,directive,MAXDIRECTIVELEN)!=0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix",
|
|
"First input argument must be {'clone','attach','detach','free'}.");
|
|
|
|
/* get key (ARGUMENT 1) */
|
|
if ( mxIsNumeric(mxShmKey) && mxGetNumberOfElements(mxShmKey)==1 )
|
|
shmkey = (key_t)mxGetScalar(mxShmKey);
|
|
else
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix",
|
|
"Second input argument must be a valid key (numeric scalar).");
|
|
|
|
/* check outputs */
|
|
if ( nlhs > 1 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix",
|
|
"Function returns only one value.");
|
|
|
|
/* clone, attach, detach, free */
|
|
switch ( tolower(directive[0]) ) {
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Clone */
|
|
/* --------------------------------------------------------------------- */
|
|
case 'c':
|
|
|
|
if ( nrhs<3 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Required third argument missing (variable).");
|
|
|
|
if ( mxGetNumberOfElements(prhs[2])<2 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Required third argument (variable) must have at least two elements.");
|
|
|
|
/* Assign (ARGUMENT 2) */
|
|
mxInput = prhs[2];
|
|
|
|
bool allocate_only = false;
|
|
if (nrhs>3) {
|
|
int * tmp = (int*)mxGetData(prhs[3]);
|
|
allocate_only = tmp[0];
|
|
}
|
|
|
|
/* scan input data */
|
|
shmsiz = deepscan(&hdr,&dat,mxInput);
|
|
mydebug("clone: deepscan done (%u)",(unsigned)shmsiz);
|
|
|
|
/* create the segment */
|
|
if ( (shmid=shmget(shmkey,shmsiz,IPC_CREAT|IPC_EXCL|0644 )) < 0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Unable to create shared memory segment.");
|
|
|
|
/* attach the segment to this dataspace */
|
|
shm = (char*)shmat(shmid,NULL,0);
|
|
if ( shm==(char*)-1 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Unable to attach shared memory to data space.");
|
|
|
|
mydebug("clone: shared memory at: 0x%llx",shm);
|
|
|
|
/* copy data to the shared memory */
|
|
deepcopy(&hdr,&dat,shm, allocate_only);
|
|
mydebug("clone: deep copy successful");
|
|
|
|
/* free temporary allocation */
|
|
deepfree(&dat);
|
|
shmdt(shm);
|
|
|
|
/* return its size */
|
|
mxOutput = mxCreateDoubleScalar((double)shmsiz);
|
|
|
|
break;
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Attach */
|
|
/* --------------------------------------------------------------------- */
|
|
case 'a':
|
|
|
|
/* get SM id */
|
|
if ( (shmid=shmget(shmkey,shmsiz,IPC_CREAT|0644)) < 0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach",
|
|
"Unable to get shared memory id.");
|
|
|
|
/* attach the segment to this dataspace */
|
|
shm = (char*)shmat(shmid,NULL,0);
|
|
if ( shm==(char*)-1 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach",
|
|
"Unable to attach shared memory to data space.");
|
|
|
|
mydebug("attach: shared memory at: 0x%llx",shm);
|
|
|
|
/* restore the segments (ignore return value) */
|
|
shmsiz_tmp=shallowrestore(shm,&mxOutput);
|
|
|
|
mydebug("attach: done");
|
|
|
|
break;
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Detach */
|
|
/* --------------------------------------------------------------------- */
|
|
case 'd':
|
|
|
|
if ( nrhs<3 || mxIsEmpty(prhs[2]) )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach",
|
|
"Required third argument (variable) missing or empty.");
|
|
|
|
/* Assign */
|
|
mxInput = prhs[2];
|
|
|
|
shm = deepdetach((mxArray*)mxInput); /* Abuse const */
|
|
mxOutput = mxCreateDoubleMatrix(0,0,mxREAL);
|
|
|
|
mydebug("detach: shared memory at: 0x%llx",shm);
|
|
|
|
if ( shmdt(shm) != 0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach",
|
|
"Unable to detach shared memory.");
|
|
|
|
break;
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Free */
|
|
/* --------------------------------------------------------------------- */
|
|
case 'f':
|
|
|
|
/* get SM id */
|
|
if ( (shmid=shmget(shmkey,shmsiz,0644)) < 0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:free",
|
|
"Unable to get shared memory id.");
|
|
|
|
/* free SM */
|
|
if ( (shmctl(shmid,IPC_RMID,(struct shmid_ds *)NULL)) != 0 )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:free",
|
|
"Unable to destroy shared memory.");
|
|
|
|
mxOutput = mxCreateDoubleMatrix(0,0,mxREAL);
|
|
|
|
break;
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
/* Error */
|
|
/* --------------------------------------------------------------------- */
|
|
default:
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix",
|
|
"Unrecognized directive.");
|
|
}
|
|
|
|
/* assign the output */
|
|
plhs[0] = mxOutput;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* deepdetach */
|
|
/* */
|
|
/* Remove shared memory references to input matrix (in-situ), recursively */
|
|
/* if needed. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* Input matrix to remove references. */
|
|
/* Returns: */
|
|
/* Pointer to start of shared memory segment. */
|
|
/* ------------------------------------------------------------------------- */
|
|
char* deepdetach(mxArray *mxInput) {
|
|
|
|
/* uses side-effects! */
|
|
mwSize dims[] = {0,0};
|
|
mwSize nzmax = 0;
|
|
size_t elemsiz;
|
|
size_t i,j,n,m;
|
|
size_t offset=0;
|
|
char *shm=(char*)NULL,*tmp=(char*)NULL;
|
|
|
|
|
|
/* restore matlab memory */
|
|
if ( mxInput==(mxArray*)NULL || mxIsEmpty(mxInput) ) {
|
|
/* do nothing */
|
|
|
|
} else if ( mxIsStruct(mxInput) ) {
|
|
/* struct case */
|
|
|
|
/* detach each field for each element */
|
|
m = mxGetNumberOfElements(mxInput);
|
|
n = mxGetNumberOfFields(mxInput);
|
|
for ( i=0; i<m; i++ ) { /* element */
|
|
for ( j=0; j<n; j++ ) { /* field */
|
|
/* detach this one */
|
|
tmp=deepdetach((mxArray*)(mxGetFieldByNumber(mxInput,i,j)));
|
|
if ( shm==NULL ) {
|
|
if ( tmp!=NULL ) shm=tmp;
|
|
offset += FieldNamesSize(mxInput); /* always a multiple of alignment size */
|
|
offset += sizeof(header_t);
|
|
offset += pad_to_align( mxGetNumberOfDimensions(mxInput) * sizeof(mwSize) );
|
|
/*offset += strBytes;*/
|
|
}
|
|
}
|
|
}
|
|
shm -= offset;
|
|
|
|
} else if ( mxIsCell(mxInput) ) {
|
|
/* cell case */
|
|
|
|
/* detach each element */
|
|
m = mxGetNumberOfElements(mxInput);
|
|
for ( i=0; i<m; i++ ) {
|
|
/* detach this one */
|
|
tmp=deepdetach((mxArray*)(mxGetCell(mxInput,i)));
|
|
if ( shm==NULL ) {
|
|
if ( tmp!=NULL ) shm=tmp;
|
|
offset += sizeof(header_t);
|
|
offset += pad_to_align( mxGetNumberOfDimensions(mxInput) * sizeof(mwSize) );
|
|
}
|
|
}
|
|
shm -= offset;
|
|
|
|
} else if ( mxIsNumeric(mxInput) || mxIsLogical(mxInput) || mxIsChar(mxInput)) {
|
|
/* matrix case */
|
|
|
|
n = sizeof(header_t);
|
|
n += pad_to_align( mxGetNumberOfDimensions(mxInput) * sizeof(mwSize) );
|
|
shm = (char*)(mxGetData(mxInput) - n);
|
|
|
|
/* in safe mode these entries were allocated so remove them properly */
|
|
if ( mxIsComplex(mxInput) ) {
|
|
mxFree(mxGetData(mxInput));
|
|
mxFree(mxGetImagData(mxInput));
|
|
}
|
|
|
|
/* handle sparse objects */
|
|
// if ( mxIsSparse(mxInput) ) {
|
|
// /* can't give sparse arrays zero size (nzmax must be 1) */
|
|
// dims[0] = dims[1] = nzmax = 1;
|
|
// if ( mxSetDimensions(mxInput,dims,2) )
|
|
// mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach",
|
|
// "Unable to resize the array.");
|
|
//
|
|
// /* in safe mode these entries were allocated so remove them
|
|
// * properly */
|
|
// #ifdef SAFEMODE
|
|
// mxFree(mxGetIr(mxInput));
|
|
// mxFree(mxGetJc(mxInput));
|
|
// #endif
|
|
//
|
|
// /* allocate 1 element */
|
|
// elemsiz = mxGetElementSize(mxInput);
|
|
// mxSetData(mxInput,mxCalloc(nzmax,elemsiz));
|
|
// if ( mxIsComplex(mxInput) )
|
|
// mxSetImagData(mxInput,mxCalloc(nzmax,elemsiz));
|
|
// else
|
|
// mxSetImagData(mxInput,(void*)NULL);
|
|
//
|
|
// /* allocate 1 element */
|
|
// mxSetNzmax(mxInput,nzmax);
|
|
// mxSetIr(mxInput,(mwSize*)mxCalloc(nzmax,sizeof(mwIndex)));
|
|
// mxSetJc(mxInput,(mwSize*)mxCalloc(dims[1]+1,sizeof(mwIndex)));
|
|
//
|
|
// } else {
|
|
/* Can have zero size, so nullify data storage containers */
|
|
if (mxSetDimensions(mxInput,dims,2))
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach",
|
|
"Unable to resize the array.");
|
|
|
|
/* Doesn't allocate or deallocate any space for the pr or pi arrays */
|
|
mxSetData(mxInput, (void*)NULL);
|
|
mxSetImagData(mxInput, (void*)NULL);
|
|
// }
|
|
|
|
} else {
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach",
|
|
"Unsupported type.");
|
|
|
|
}
|
|
|
|
return shm;
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* shallowrestore */
|
|
/* */
|
|
/* Shallow copy matrix from shared memory into Matlab form. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* shared memory segment. */
|
|
/* pointer to an mxArray pointer. */
|
|
/* Returns: */
|
|
/* size of shared memory segment. */
|
|
/* ------------------------------------------------------------------------- */
|
|
size_t shallowrestore(char *shm, mxArray** p_mxInput) {
|
|
|
|
/* for working with shared memory ... */
|
|
size_t i,shmsiz;
|
|
mxArray *mxChild; /* temporary pointer */
|
|
|
|
/* for working with payload ... */
|
|
header_t *hdr;
|
|
mwSize *pSize; /* pointer to the array dimensions */
|
|
void *pr=NULL,*pi=NULL; /* real and imaginary data pointers */
|
|
mwIndex *ir=NULL,*jc=NULL; /* sparse matrix data indices */
|
|
|
|
/* for structures */
|
|
int ret;
|
|
size_t nFields; /* number of fields */
|
|
size_t field_num; /* current field */
|
|
size_t strBytes; /* Number of bytes in the string recording the field names */
|
|
char **pFieldStr; /* Array to pass to Matlab with the field names pFields[0] is a poitner to the first field name, pFields[1] is the pointer to the second*/
|
|
|
|
/* retrieve the data */
|
|
hdr = (header_t*)shm;
|
|
shm += sizeof(header_t);
|
|
|
|
/* the size pointer */
|
|
pSize = (mwSize*)shm;
|
|
|
|
/* skip over the stored sizes */
|
|
shm += pad_to_align(sizeof(mwSize)*hdr->nDims);
|
|
|
|
if ( hdr->isStruct ) {
|
|
/* struct case */
|
|
|
|
mydebug("shallowrestore: found structure %d x %d",pSize[0],pSize[1]);
|
|
|
|
/* Pull out the field names, they follow the size*/
|
|
ret = NumFieldsFromString(shm, &nFields, &strBytes);
|
|
|
|
/* check the recovery */
|
|
if ((ret) || (nFields != hdr->nFields))
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach",
|
|
"Structure fields have not been recovered properly.");
|
|
|
|
/* And convert to something matlab understands */
|
|
pFieldStr = (char**)mxCalloc(nFields, sizeof(char*));
|
|
PointCharArrayAtString(pFieldStr, shm, nFields);
|
|
|
|
/* skip over the stored field string */
|
|
shm += strBytes;
|
|
|
|
/*create the matrix */
|
|
*p_mxInput = mxCreateStructArray(hdr->nDims, pSize, hdr->nFields, (const char**)pFieldStr);
|
|
mxFree(pFieldStr); /* no longer need it */
|
|
|
|
for ( i=0; i<hdr->nzmax; i++ ) { /* each element */
|
|
for ( field_num=0; field_num<hdr->nFields; field_num++ ) { /* each field */
|
|
mydebug("shallowrestore: working on %d field %d at 0x%llx",i,field_num, *p_mxInput);
|
|
|
|
/* And fill it */
|
|
shmsiz = shallowrestore(shm,&mxChild); /* restore the mxArray */
|
|
mxSetFieldByNumber(*p_mxInput, i, field_num, mxChild); /* and pop it in */
|
|
shm += shmsiz;
|
|
|
|
mydebug("shallowrestore: completed %d field %d",i, field_num);
|
|
}
|
|
}
|
|
|
|
} else if ( hdr->isCell ) {
|
|
/* cell case */
|
|
|
|
mydebug("shallowrestore: found cell %d x %d",pSize[0], pSize[1]);
|
|
|
|
/* Create the array */
|
|
*p_mxInput = mxCreateCellArray(hdr->nDims, pSize);
|
|
for ( i=0; i<hdr->nzmax; i++ ) {
|
|
mydebug("shallowrestore: working on %d at 0x%llx",i,mxChild);
|
|
|
|
/* And fill it */
|
|
shmsiz = shallowrestore(shm,&mxChild);
|
|
mxSetCell(*p_mxInput, i, mxChild);
|
|
shm += shmsiz;
|
|
|
|
mydebug("shallowrestore: completed %d at 0x%llx",i,mxChild);
|
|
}
|
|
|
|
|
|
} else {
|
|
/* matrix case */
|
|
|
|
/* this is the address of the first data */
|
|
pr = (void*)shm;
|
|
shm += pad_to_align((hdr->nzmax)*(hdr->elemsiz)); /* takes us to the end of the real data */
|
|
|
|
/* if complex get a pointer to the complex data */
|
|
if ( hdr->isComplex ) {
|
|
pi = (void*)shm;
|
|
shm += pad_to_align((hdr->nzmax)*(hdr->elemsiz)); /* takes us to the end of the complex data */
|
|
}
|
|
|
|
/* if sparse get a list of the elements */
|
|
// if ( hdr->isSparse ) {
|
|
// mydebug("shallowrestore: found non-cell, sparse 0x%llx",*p_mxInput);
|
|
//
|
|
// ir = (mwIndex*)shm;
|
|
// shm += pad_to_align((hdr->nzmax)*sizeof(mwIndex));
|
|
//
|
|
// jc = (mwIndex*)shm;
|
|
// shm += pad_to_align((pSize[1]+1)*sizeof(mwIndex));
|
|
//
|
|
// /* need to create sparse logical differently */
|
|
// if ( hdr->classid==mxLOGICAL_CLASS )
|
|
// *p_mxInput = mxCreateSparseLogicalMatrix(0,0,0);
|
|
// else
|
|
// *p_mxInput = mxCreateSparse(0,0,0,(hdr->isComplex)?mxCOMPLEX:mxREAL);
|
|
//
|
|
// /* free the memory it was created with */
|
|
// mxFree(mxGetIr(*p_mxInput));
|
|
// mxFree(mxGetJc(*p_mxInput));
|
|
//
|
|
// /* set the size */
|
|
// if (mxSetDimensions(*p_mxInput, pSize, hdr->nDims))
|
|
// mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach",
|
|
// "Unable to resize the sparse array.");
|
|
//
|
|
// /* set the pointers relating to sparse (set the real and imaginary data later)*/
|
|
// #ifndef SAFEMODE
|
|
//
|
|
// /* Hack Method */
|
|
// ((mxArrayHack*)*p_mxInput)->data.number_array.reserved5 = ir;
|
|
// ((mxArrayHack*)*p_mxInput)->data.number_array.reserved6[0] = (size_t)jc;
|
|
// ((mxArrayHack*)*p_mxInput)->data.number_array.reserved6[1] = (size_t)(hdr->nzmax);
|
|
//
|
|
// /* dont do this as it makes a write turn into a copy to local memory */
|
|
// /*((mxArrayHack*)*p_mxInput)->reserved3 = 1;*/ /*give it a reference count*/
|
|
//
|
|
// #else
|
|
//
|
|
// /* Safe - but takes it out of global memory */
|
|
// mxSetIr(*p_mxInput, (mwIndex*) safeCopy(ir,(hdr->nzmax)*sizeof(mwIndex)));
|
|
// mxSetJc(*p_mxInput, (mwIndex*) safeCopy(jc,(pSize[1]+1)*sizeof(mwIndex)));
|
|
//
|
|
// #endif
|
|
// mxSetNzmax(*p_mxInput,hdr->nzmax);
|
|
//
|
|
// } else {
|
|
|
|
/* rebuild constitute the array */
|
|
mydebug("shallowrestore: found non-cell, non-sparse");
|
|
|
|
/* create an empty array */
|
|
*p_mxInput = mxCreateNumericMatrix(0,0,hdr->classid,(hdr->isComplex)?mxCOMPLEX:mxREAL);
|
|
|
|
mydebug("%d %d (of total: %d)",pSize[0],pSize[1],hdr->nDims);
|
|
|
|
/* set the size */
|
|
if (mxSetDimensions(*p_mxInput, pSize, hdr->nDims))
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach",
|
|
"Unable to resize the array.");
|
|
// }
|
|
|
|
|
|
/* Free the memory it was created with (shouldn't be necessary) */
|
|
mxFree(mxGetPr(*p_mxInput));
|
|
mxFree(mxGetPi(*p_mxInput));
|
|
|
|
/* set the real and imaginary data */
|
|
if ( ! hdr->isComplex )
|
|
{
|
|
/* Hack Method */
|
|
|
|
mydebug("pr:0x%llx",pr);
|
|
|
|
/* BUGFIX: this line causes matlab ABORT when shared object is a scalar! */
|
|
/* the theory is that scalars are copied not copy on reference hence
|
|
* the return of the function causes a failure. */
|
|
((mxArrayHack*)(*p_mxInput))->data.number_array.pdata = pr;
|
|
|
|
if ( hdr->isComplex )
|
|
((mxArrayHack*)(*p_mxInput))->data.number_array.pimag_data = pi;
|
|
}
|
|
else
|
|
{
|
|
/* Safe - but takes it out of global memory */
|
|
|
|
|
|
mxSetData(*p_mxInput, safeCopy(pr, hdr->nzmax*hdr->elemsiz));
|
|
if ( hdr->isComplex )
|
|
mxSetImagData(*p_mxInput, safeCopy(pi, hdr->nzmax*hdr->elemsiz));
|
|
}
|
|
|
|
}
|
|
return hdr->shmsiz;
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* deepscan */
|
|
/* */
|
|
/* Recursively descend through Matlab matrix to assess how much space its */
|
|
/* serialization will require. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* header to populate. */
|
|
/* data container to populate. */
|
|
/* mxArray to analyze. */
|
|
/* Returns: */
|
|
/* size that shared memory segment will need to be. */
|
|
/* ------------------------------------------------------------------------- */
|
|
size_t deepscan(header_t *hdr, data_t *dat, const mxArray* mxInput) {
|
|
/* counter */
|
|
size_t i;
|
|
|
|
/* for structures */
|
|
size_t field_num, count, plussiz;
|
|
size_t strBytes;
|
|
|
|
/* initialize data info; _possibly_ update these later */
|
|
dat->pSize = ( mwSize* )NULL;
|
|
dat->pr = ( void*)NULL;
|
|
dat->pi = ( void*)NULL;
|
|
dat->ir = ( void*)NULL;
|
|
dat->jc = ( mwIndex*)NULL;
|
|
dat->child_dat = ( data_t*)NULL;
|
|
dat->child_hdr = (header_t*)NULL;
|
|
|
|
if ( mxInput==(const mxArray*)NULL || mxIsEmpty(mxInput) ) {
|
|
/* initialize header info */
|
|
hdr->isCell = 0;
|
|
hdr->isSparse = 0;
|
|
hdr->isComplex = 0;
|
|
hdr->isStruct = 0;
|
|
hdr->classid = mxUNKNOWN_CLASS;
|
|
hdr->nDims = 0;
|
|
hdr->elemsiz = 0;
|
|
hdr->nzmax = 0;
|
|
hdr->nFields = 0;
|
|
hdr->shmsiz = sizeof(header_t);
|
|
return hdr->shmsiz;
|
|
}
|
|
|
|
/* initialize header info */
|
|
hdr->isCell = mxIsCell(mxInput);
|
|
hdr->isSparse = mxIsSparse(mxInput);
|
|
hdr->isComplex = mxIsComplex(mxInput);
|
|
hdr->isStruct = mxIsStruct(mxInput);
|
|
hdr->classid = mxGetClassID(mxInput);
|
|
hdr->nDims = mxGetNumberOfDimensions(mxInput);
|
|
hdr->elemsiz = mxGetElementSize(mxInput);
|
|
hdr->nzmax = mxGetNumberOfElements(mxInput); /* update this later (if sparse) */
|
|
hdr->nFields = 0; /* update this later */
|
|
hdr->shmsiz = sizeof(header_t); /* update this later */
|
|
|
|
/* copy the size */
|
|
dat->pSize = (mwSize*)mxGetDimensions(mxInput); /* some abuse of const for now, fix on deep copy*/
|
|
|
|
/* Add space for the dimensions */
|
|
hdr->shmsiz += pad_to_align(hdr->nDims * sizeof(mwSize));
|
|
|
|
if ( hdr->isStruct ) {
|
|
/* struct case */
|
|
|
|
mydebug("deepscan: found structure");
|
|
|
|
/* How many fields to work with? */
|
|
hdr->nFields = mxGetNumberOfFields(mxInput);
|
|
|
|
/* Find the size required to store the field names */
|
|
strBytes = FieldNamesSize(mxInput); /* always a multiple of alignment size */
|
|
hdr->shmsiz += strBytes; /* Add space for the field string */
|
|
|
|
/* use mxCalloc so mem is freed on error via garbage collection */
|
|
dat->child_hdr = (header_t*)mxCalloc(hdr->nzmax * hdr->nFields * (sizeof(header_t) +
|
|
sizeof(data_t)) + strBytes, 1); /* extra space for the field string */
|
|
dat->child_dat = (data_t*)&dat->child_hdr[hdr->nFields * hdr->nzmax];
|
|
dat->ir = (void*)&dat->child_dat[hdr->nFields * hdr->nzmax];
|
|
|
|
/* make a record of the field names */
|
|
CopyFieldNames(mxInput, (char*)(dat->ir));
|
|
|
|
/* go through each recursively */
|
|
count = 0;
|
|
for ( i=0; i<hdr->nzmax; i++ ) { /* each element */
|
|
for (field_num = 0; field_num < hdr->nFields; field_num++) { /* each field */
|
|
/* call recursivley */
|
|
plussiz = deepscan(&(dat->child_hdr[count]),
|
|
&(dat->child_dat[count]), mxGetFieldByNumber(mxInput,i,field_num) );
|
|
hdr->shmsiz += plussiz;
|
|
count++; /* progress */
|
|
mydebug("deepscan: finished element %d field %d (%12u %12u)",i,field_num,plussiz,hdr->shmsiz);
|
|
}
|
|
}
|
|
|
|
} else if ( hdr->isCell ) {
|
|
/* cell case */
|
|
|
|
mydebug("deepscan: found cell");
|
|
|
|
/* use mxCalloc so mem is freed on error via garbage collection */
|
|
dat->child_hdr = (header_t*)mxCalloc(hdr->nzmax,sizeof(header_t) + sizeof(data_t));
|
|
dat->child_dat = (data_t*)&dat->child_hdr[hdr->nzmax];
|
|
|
|
/* go through each recursively */
|
|
for ( i=0;i<hdr->nzmax;i++ ) {
|
|
plussiz = deepscan( &(dat->child_hdr[i]),
|
|
&(dat->child_dat[i]), mxGetCell(mxInput,i));
|
|
hdr->shmsiz += plussiz;
|
|
mydebug("deepscan: finished %d (%12u %12u)",i,plussiz,hdr->shmsiz);
|
|
}
|
|
|
|
/* if its a cell it has to have at least one mom-empty element */
|
|
if ( hdr->shmsiz==(1+hdr->nzmax)*sizeof(header_t) )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Required third argument (variable) must contain at "
|
|
"least one non-empty item (at all levels).");
|
|
|
|
} else if ( mxIsNumeric(mxInput) || mxIsLogical(mxInput) || mxIsChar(mxInput)) { /* a matrix containing data */
|
|
/* matrix case */
|
|
|
|
if ( hdr->isSparse ) {
|
|
/* len(pr)=nzmax, len(ir)=nzmax, len(jc)=colc+1 */
|
|
hdr->nzmax = mxGetNzmax(mxInput);/* make sure to do this because its sparse */
|
|
dat->ir = mxGetIr(mxInput);
|
|
dat->jc = mxGetJc(mxInput);
|
|
/* ensure both pointers are aligned individually */
|
|
hdr->shmsiz += pad_to_align(sizeof(mwIndex)*(hdr->nzmax)); /* ir */
|
|
hdr->shmsiz += pad_to_align(sizeof(mwIndex)*(dat->pSize[1]+1)); /* jc */
|
|
}
|
|
|
|
dat->pr = mxGetData(mxInput);
|
|
dat->pi = mxGetImagData(mxInput);
|
|
/* ensure both pointers are aligned individually */
|
|
hdr->shmsiz += pad_to_align(hdr->elemsiz*hdr->nzmax); /* pr */
|
|
if (hdr->isComplex)
|
|
hdr->shmsiz += pad_to_align(hdr->elemsiz*hdr->nzmax); /* pi */
|
|
|
|
} else {
|
|
/* error case */
|
|
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Unknown class found: %s.", mxGetClassName(mxInput));
|
|
}
|
|
|
|
|
|
return hdr->shmsiz;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* deepcopy */
|
|
/* */
|
|
/* Descend through header and data structure and copy relevent data to */
|
|
/* shared memory. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* header to serialize. */
|
|
/* data container of pointers to data to serialize. */
|
|
/* pointer to shared memory segment. */
|
|
/* Returns: */
|
|
/* void */
|
|
/* ------------------------------------------------------------------------- */
|
|
void deepcopy(header_t *hdr, data_t *dat, char *shm, bool allocate_only) {
|
|
|
|
/* declarations */
|
|
size_t i,offset;
|
|
mwSize *pSize; /* points to the size data */
|
|
size_t nDims=hdr->nDims;
|
|
|
|
/* for structures */
|
|
size_t nFields;
|
|
int ret;
|
|
|
|
/* copy the header (NOALIGN) */
|
|
offset = sizeof(header_t);
|
|
memcpy(shm,hdr,offset);
|
|
shm+=offset;
|
|
|
|
/* keep for later */
|
|
pSize = (mwSize*)shm;
|
|
|
|
/* copy the dimensions (ALIGN) */
|
|
offset = nDims * sizeof(mwSize);
|
|
memcpy(shm,dat->pSize,offset);
|
|
shm += pad_to_align(offset);
|
|
|
|
if (hdr->isStruct) {
|
|
/* struct case */
|
|
|
|
mydebug("deepcopy: found structure");
|
|
|
|
/* place the field names next in shared memory */
|
|
/* note: NumFieldsFromString() automatically pads the offset */
|
|
ret = NumFieldsFromString((char*)(dat->ir), &nFields, &offset);
|
|
|
|
/* check the recovery */
|
|
if ( ret || nFields!=hdr->nFields )
|
|
mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone",
|
|
"Structure fields have not been recovered properly.");
|
|
|
|
/* copy the field string (ALIGN) */
|
|
memcpy(shm,dat->ir,offset);
|
|
shm += offset; /* aligned already! in NumFieldsFromString */
|
|
|
|
/* copy children recursively (NOALIGN) */
|
|
for ( i=0; i<hdr->nzmax*hdr->nFields; i++ ) {
|
|
deepcopy( &(dat->child_hdr[i]),&(dat->child_dat[i]), shm, allocate_only );
|
|
shm += (dat->child_hdr[i]).shmsiz;
|
|
}
|
|
|
|
} else if ( hdr->isCell ) {
|
|
/* cell case */
|
|
|
|
mydebug("deepcopy: found cell");
|
|
|
|
/* copy children recursively (NOALIGN) */
|
|
for( i=0; i<hdr->nzmax; i++ ) {
|
|
deepcopy(&(dat->child_hdr[i]),&(dat->child_dat[i]),shm, allocate_only );
|
|
shm+=(dat->child_hdr[i]).shmsiz;
|
|
}
|
|
|
|
} else {
|
|
/* matrix case */
|
|
|
|
/* copy real data (ALIGN) */
|
|
offset = (hdr->nzmax)*(hdr->elemsiz);
|
|
if (!allocate_only)
|
|
memcpy(shm,dat->pr,offset);
|
|
shm += pad_to_align(offset);
|
|
|
|
/* copy complex data (ALIGN) */
|
|
if ( hdr->isComplex ) {
|
|
offset = (hdr->nzmax)*(hdr->elemsiz);
|
|
if (!allocate_only)
|
|
memcpy(shm,dat->pi,offset);
|
|
shm += pad_to_align(offset);
|
|
}
|
|
|
|
/* indices of sparse (ALIGN) */
|
|
if ( hdr->isSparse ) {
|
|
offset = hdr->nzmax*sizeof(mwIndex);
|
|
memcpy(shm,dat->ir,offset);
|
|
shm += pad_to_align(offset);
|
|
|
|
offset = (pSize[1]+1)*sizeof(mwIndex);
|
|
memcpy(shm,dat->jc,offset);
|
|
shm += pad_to_align(offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* deepfree */
|
|
/* */
|
|
/* Descend through header and data structure and free the memory. */
|
|
/* */
|
|
/* Arguments: */
|
|
/* data container */
|
|
/* Returns: */
|
|
/* void */
|
|
/* ------------------------------------------------------------------------- */
|
|
void deepfree(data_t *dat) {
|
|
|
|
/* recurse to the bottom */
|
|
if ( dat->child_dat!=(data_t*)NULL )
|
|
deepfree(dat->child_dat);
|
|
|
|
/* free on the way back up */
|
|
mxFree(dat->child_hdr);
|
|
|
|
dat->child_hdr = (header_t*)NULL;
|
|
dat->child_dat = (data_t*)NULL;
|
|
dat->ir = (void*)NULL; /* could have been used for fieldNames */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* */
|
|
/* Andrew Smith Code for structs. */
|
|
/* */
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* Function to find the number of bytes required to store all of the */
|
|
/* field names of a structure */
|
|
int FieldNamesSize(const mxArray * mxStruct)
|
|
{
|
|
const char* pFieldName;
|
|
int nFields;
|
|
int i,j; /* counters */
|
|
int Bytes = 0;
|
|
|
|
/* How many fields? */
|
|
nFields = mxGetNumberOfFields(mxStruct);
|
|
|
|
/* Go through them */
|
|
for (i = 0; i < nFields; i++)
|
|
{
|
|
/* This field */
|
|
pFieldName = mxGetFieldNameByNumber(mxStruct,i);
|
|
j = 0;
|
|
while (pFieldName[j])
|
|
{ j++; }
|
|
j++; /* for the null termination */
|
|
|
|
if (i == (nFields - 1))
|
|
j++; /* add this at the end for an end of string sequence since we use 0 elsewhere (term_char). */
|
|
|
|
|
|
/* Pad it out to 8 bytes */
|
|
j = pad_to_align(j);
|
|
|
|
/* keep the running tally */
|
|
Bytes += j;
|
|
|
|
}
|
|
|
|
/* Add an extra alignment size to store the length of the string (in Bytes) */
|
|
Bytes += align_size;
|
|
|
|
return Bytes;
|
|
|
|
}
|
|
|
|
/* Function to copy all of the field names to a character array */
|
|
/* Use FieldNamesSize() to allocate the required size of the array */
|
|
/* returns the number of bytes used in pList */
|
|
int CopyFieldNames(const mxArray * mxStruct, char* pList)
|
|
{
|
|
const char* pFieldName; /* name of the field to add to the list */
|
|
int nFields; /* the number of fields */
|
|
int i,j; /* counters */
|
|
int Bytes = 0; /* number of bytes copied */
|
|
|
|
/* How many fields? */
|
|
nFields = mxGetNumberOfFields(mxStruct);
|
|
|
|
/* Go through them */
|
|
for (i = 0; i < nFields; i++)
|
|
{
|
|
/* This field */
|
|
pFieldName = mxGetFieldNameByNumber(mxStruct,i);
|
|
j = 0;
|
|
while (pFieldName[j])
|
|
{ pList[Bytes++]=pFieldName[j++]; }
|
|
pList[Bytes++] = 0; /* add the null termination */
|
|
|
|
/* if this is last entry indicate the end of the string */
|
|
if (i == (nFields - 1))
|
|
{
|
|
pList[Bytes++] = term_char;
|
|
pList[Bytes++] = 0; /* another null termination just to be safe */
|
|
}
|
|
|
|
/* Pad it out to 8 bytes */
|
|
while (Bytes % align_size)
|
|
{ pList[Bytes++] = 0; }
|
|
}
|
|
|
|
/* Add an extra alignment size to store the length of the string (in Bytes) */
|
|
*(unsigned int*)&pList[Bytes] = (unsigned int)(Bytes + align_size);
|
|
Bytes += align_size;
|
|
|
|
return Bytes;
|
|
|
|
}
|
|
|
|
/*Function to take point a each element of the char** array at a list of names contained in string */
|
|
/*ppCharArray must be allocated to length num_names */
|
|
/*names are seperated by null termination characters */
|
|
/*each name must start on an aligned address (see CopyFieldNames()) */
|
|
/*e.g. pCharArray[0] = &name_1, pCharArray[1] = &name_2 ... */
|
|
/*returns 0 if successful */
|
|
int PointCharArrayAtString(char ** pCharArray, char* pString, int nFields)
|
|
{
|
|
int i = 0; /* the index in pString we are up to */
|
|
int field_num = 0; /* the field we are up to */
|
|
|
|
/* and recover them */
|
|
while (field_num < nFields)
|
|
{
|
|
/* scan past null termination chars */
|
|
while (!pString[i])
|
|
i++;
|
|
|
|
/* Check the address is aligned (assume every forth bytes is aligned) */
|
|
if (i % align_size)
|
|
return -1;
|
|
|
|
/* grab the address */
|
|
pCharArray[field_num] = &pString[i];
|
|
field_num++;
|
|
|
|
/* continue until a null termination char */
|
|
while (pString[i])
|
|
i++;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* This function finds the number of fields contained within in a string */
|
|
/* the string is terminated by term_char, a character that can't be in a field name */
|
|
/* returns the number of field names found */
|
|
/* returns -1 if unaligned field names are found */
|
|
int NumFieldsFromString(const char* pString, size_t *pFields, size_t* pBytes)
|
|
{
|
|
unsigned int stored_length; /* the recorded length of the string */
|
|
bool term_found = false; /* has the termination character been found? */
|
|
int i = 0; /* counter */
|
|
|
|
pFields[0] = 0; /* the number of fields in the string */
|
|
pBytes[0] = 0;
|
|
|
|
|
|
/* and recover them */
|
|
while (!term_found)
|
|
{
|
|
/* scan past null termination chars */
|
|
while (!pString[i])
|
|
{ i++; }
|
|
|
|
/* is this the special termination character? */
|
|
term_found = pString[i] == term_char;
|
|
|
|
if (!term_found)
|
|
{
|
|
/* Check the address is aligned (assume every forth bytes is aligned) */
|
|
if (i % align_size)
|
|
{ return -1; }
|
|
|
|
/* a new field */
|
|
pFields[0]++;
|
|
|
|
/* continue until a null termination char */
|
|
while (pString[i] && (pString[i] != term_char))
|
|
{ i++; }
|
|
|
|
/* check there wasn't the terminal character immediately after the field */
|
|
if (pString[i] == term_char)
|
|
{ return -2; }
|
|
|
|
}
|
|
}
|
|
pBytes[0] = i;
|
|
|
|
/* return the aligned size */
|
|
pBytes[0] = pad_to_align(pBytes[0]);
|
|
|
|
/* Check what's recovered matches the stored length */
|
|
stored_length = *(unsigned int*)&pString[pBytes[0]] ; /* the recorded length of the string */
|
|
pBytes[0] += align_size; /* add the extra space for the record */
|
|
|
|
/* Check on it */
|
|
if (stored_length != pBytes[0])
|
|
return -3;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Function to find the bytes in the string starting from the end of the string (i.e. the last element is pString[-1])*/
|
|
/* returns < 0 on error */
|
|
int BytesFromStringEnd(const char* pString, size_t* pBytes)
|
|
{
|
|
|
|
int offset = align_size; /* start from the end of the string */
|
|
pBytes[0] = 0; /* default */
|
|
|
|
/* Grab it directly from the string */
|
|
pBytes[0] = (size_t)(*(unsigned int*)&pString[-offset]);
|
|
|
|
/* scan for the termination character */
|
|
while ((offset < 2*align_size) && (pString[-offset] != term_char))
|
|
{ offset++;}
|
|
|
|
if (offset == align_size)
|
|
{ return -1; }/* failure to find the control character */
|
|
else
|
|
{ return 0; }/* happy */
|
|
|
|
}
|
|
|