"Chris Thomasson" <cristom@comcast.netwrote in message
news:h_GdnYjvyb3P2efbnZ2dnUVZ_tGvnZ2d@comcast.com. ..
[...]
I just remembered that a library called Nobel uses same basic technique:
You can create an abstract interface in C by declaring a vtable structure
and the interface structure self. First we setup a type for the VTable's
first parameter (e.g., 'this' in c++):
_______________
typedef void* IObject_This_t;
typedef IObject_This_t const VTable_This_t;
_______________
Now, lets say that our new interface will be for a thread/process
mutual-exclusion synchronization object. So, we need to declare the
following structs:
_______________
typedef struct IMutex_s IMutex_t;
typedef struct IMutex_VTable_s IMutex_VTable_t;
_______________
And then we define the struct for our mutex interface:
_______________
struct IMutex_s {
IObject_This_t This;
IMutex_VTable_t const *VTable;
};
/*Take note of the names of the members of IMutex_t: (This, VTable). Its
import that you keep the names you choose consistent because they are going
to be depended upon. More on that later.
*/
_______________
An abstract mutex interface needs at least the following abstract functions
(Destroy, Lock, Unlock), so we define the following vtable struct:
_______________
struct IMutex_VTable_s {
int (*fp_IObject_Destroy) (VTable_This_t);
int (*fp_Lock) (VTable_This_t);
int (*fp_Unlock) (VTable_This_t);
/*Take note of the names of the members of IMutex_VTable_t:
(fp_IObject_Destroy, fp_Lock, fp_Unlock). Its import that you keep the names
you choose consistent because they are going to be depended upon. More on
that later.
*/
};
_______________
Now, we need to define the abstract interface that makes use of all the
above. We start be defining a helper function and an abstract function that
can init/destroy any object:
_______________
#define IObject_Initialize(__IThis, __ThisPtr, __VTablePtr) \
(__IThis)->This = (__ThisPtr); \
(__IThis)->VTable = (__VTablePtr)
#define IObject_Destroy(__IThis) \
(__IThis)->VTable->fp_IObject_Destroy((__IThis)->This)
_______________
Now we define the abstract functions of IMutex_t:
_______________
#define IMutex_Lock(__IThis) \
(__IThis)->VTable->fp_Lock((__IThis)->This)
#define IMutex_Unlock(__IThis) \
(__IThis)->VTable->fp_Unlock((__IThis)->This)
_______________
Stick all the above in a header file called (imutex.h) or whatever and
that's it for the abstract interface part. Now you create an object that
makes use of the interface:
your_mutex.h
_______________
/* include guard */
#include "imutex.h"
extern int Your_Mutex_Create(IMutex_t* const);
your_mutex.c
_______________
#include "your_mutex.h"
#include <stdlib.h/* malloc/free */
/* declare/define your mutexs impl struct */
typedef struct Your_Mutex_s Your_Mutex_t;
typedef Your_Mutex_t* const Your_Mutex_This_t;
struct Your_Mutex_s {
/* [impl specific mutex data] */
};
/* declare your mutexs interface functions */
static int Your_Mutex_IObject_Destroy(VTable_This_t);
static int Your_Mutex_Lock(VTable_This_t);
static int Your_Mutex_Unlock(VTable_This_t);
/* define your mutex interface vtable */
static IMutex_VTable_t const Your_Mutex_VTable = {
Your_Mutex_IObject_Destroy,
Your_Mutex_Lock,
Your_Mutex_Unlock
};
/* define mutex create function */
int Your_Mutex_Create(IMutex_t* const IThis) {
Your_Mutex_This_t This = malloc(sizeof(*This));
if (This) {
/* [init impl This specific mutex data] */
/* init the IThis interface */
IObject_Initialize(IThis, This, &Your_Mutex_VTable);
return 0;
}
return -1;
}
/* define mutex object destroy */
int Your_Mutex_IObject_Destroy(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [teardown impl This specific mutex data] */
free(This);
return -1;
}
/* define mutex interface */
int Your_Mutex_Lock(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [lock impl This specific mutex] */
return -1;
}
int Your_Mutex_Unlock(VTable_This_t ThisState) {
Your_Mutex_This_t This = ThisState;
/* [unlock impl This specific mutex] */
return -1;
}
_______________
That's it for the interface and impl... Now you can use it like:
_______________
#include "your_mutex.h"
int Locked_Callback(
IMutex_t* const IThis,
int (*fp_Callback) (void*, IMutex* const),
void *CallbackState) {
int rStatus = IMutex_Lock(IThis);
if (! rStatus) {
rStatus = fp_Callback(CallbackState, IThis);
if (! rStatus) {
rStatus = IMutex_Unlock(IThis);
}
}
return rStatus;
}
static IMutex_t The_Lock;
int Critical_Section(void *ThisState, IMutex_t* const Lock) {
/* [your in a critical-section locked by 'Lock'] */
return 0;
}
void Some_Threads(/* [...] */) {
/* [...] */
Locked_Callback(&The_Lock, Critical_Section, /* [ptr to state */);
}
int main(void) {
int rStatus = Your_Mutex_Create(&The_Lock);
if (! rStatus) {
/* [create Some_Threads] */
}
return rStatus ;
}
_______________
Well, barring any typos, that's about it. ;^)