?? privopc.h
字號:
/**************************************************************************
* *
* Light OPC Server development library *
* *
* Copyright (c) 2000 Timofei Bondarenko, Kostya Volovich *
**************************************************************************/
#ifndef PRIVOPC_H
#define PRIVOPC_H
/**************************************************************************
TODO:
It would be better to sort groups by UpdateRate.
advise_enabled can be eliminated***
GetEnable() SetEnable() can modify advise_present because
they are not work if connection was not advised.
but how we'll find connections for explicit Refresh/Read/Write ?
make locking for Activate/Deactivate less extensive
it's better to compute deadband using Requested datatypes
include TagAlias as reduced RealTag
CacheRead from PrimaryCache vs Per-Item-Cache? less locks/more updates.
**************************************************************************
IMPORTANT:
Order of the locks. When more than 1 lock should be locked
they must be locked in this order!
Otherwise deadlocks can occure.
loService::lkList
loClient::async.lk
loClient::lk_remove
loClient::lk_all
loService::lkDr
loClient::lk_browse
loService::lkMgmt
loService::update_pipe.lk
loService::lkPrim
**************************************************************************
Internal declarations:
**************************************************************************/
#include <opcda.h> /* The OPC custom interface defintions */
#include <opccomn.h>
#ifndef OPTIONS_H
#include "options.h"
#endif
#ifndef LIGHTOPC_H
#include "lightopc.h"
#endif
#ifndef LOSERV_H
#include "loserv.h"
#endif
#ifndef REQQUEUE_H
#include "reqqueue.h"
#endif
#ifndef UTIL_H
#include "util.h"
#endif
#ifndef GROWLIST_H
#include "growlist.h"
#endif
#ifndef OBJTRACK_H
#include "objtrack.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************/
#ifdef __cplusplus
}
//#endif see at the EOF
#include "connpnt.h"
class LightOPCServer;
class LightOPCGroup;
class LightOPCItem;
/*#define LightOPCServer loClient
It's right: server will be created on each client connection.
Thus, from driver point of view LightOPCServer is assotiated with a client */
#define CLINAME_FMT "%.16s "
#define LOG_SR(fmt) LOGID, CLINAME_FMT fmt, client_name
#define LOG_GR(fmt) LOGID, CLINAME_FMT fmt, owner->client_name
#define LOG_GRO(fmt) LOGID, CLINAME_FMT fmt, (iam_attached()? owner->client_name: "?")
#define LOG_GRH(fmt) LOGID, CLINAME_FMT "%u:" fmt, owner->client_name, ServerHandle
#define LOG_GRHO(fmt) LOGID, CLINAME_FMT "%u:" fmt, (iam_attached()? owner->client_name: "?"), ServerHandle
#define LOG_SR1(fmt,first) LOGID, CLINAME_FMT fmt, first, client_name
#define LOG_GR1(fmt,first) LOGID, CLINAME_FMT fmt, first, owner->client_name
#if LO_USE_OBJXREF
struct loObjXref
{
inline loObjXref() { InterlockedIncrement(&lo_X_objcount); }
inline ~loObjXref() { InterlockedDecrement(&lo_X_objcount); }
};
#define LO_OBJ_XREF loObjXref xxx_ref
#else
#define LO_OBJ_XREF
#endif
#define loUNIQUE_LEN (32)
#define LO_CHECK_STATE_(string) if (lock_state(string)) return LO_E_SHUTDOWN; else {
#define LO_CHECK_STATEz0(string) LO_CHECK_STATE_(string)
#define LO_CHECK_STATEz1(string,a1) if (a1) *(a1) = 0; LO_CHECK_STATEz0(string)
#define LO_CHECK_STATEz2(string,a1,a2) if (a2) *(a2) = 0; LO_CHECK_STATEz1(string,a1)
#define LO_CHECK_STATEz3(string,a1,a2,a3) if (a3) *(a3) = 0; LO_CHECK_STATEz2(string,a1,a2)
#define LO_CHECK_STATEz4(string,a1,a2,a3,a4) if (a4) *(a4) = 0; LO_CHECK_STATEz3(string,a1,a2,a3)
#define LO_FINISH() unlock_state(); }
typedef struct
{
IOPCShutdown *request;
loWchar *reason;
} loShutdownConn;
void loShutdownConn_init(loShutdownConn *);
void loShutdownConn_clear(loShutdownConn *);
void loShutdownConn_call(loShutdownConn *);
#define loShutdownConn_init(p) (memset((p), 0, sizeof(loShutdownConn)))
class LightOPCServer : public IOPCServer,
public IOPCCommon,
public IOPCBrowseServerAddressSpace,
public IOPCItemProperties,
public loConnPnt1 /*public IConnectionPointContainer,*/
{
LO_OBJ_XREF;
public:
unsigned long initphase;
glGrowingList grl;
loService *se;
LightOPCServer *serv_next;
loCallerx ctxt;
unsigned serv_key;
int ldFlags;
short access_mode;
HRESULT (*qi_chain)(void *rha, loService *, loClient *,
const IID *, LPVOID *);
loThrControl async; /* On signaling the tasync.state should be = 1
2 forces client_scheduler() to call selfdestroy() */
inline void touch_scheduler(void)
{
if (0 == async.tstate)
{
lw_mutex_lock(&async.lk);
if (0 == async.tstate) async.tstate = 1;
lw_conds_signal(&async.cond);
lw_mutex_unlock(&async.lk);
}
}
/* This additional flag is requered for proper hanling of late events
which has occured in the middle of client_scheduler() loop.
Such signals will cause zero-time sleep and will be handled on the
next iteration. */
#if LO_USE_BOTHMODEL
char ole_initialized;
#endif
int shuttingdown; /* locked by async.lk */
loObjTracker otrk; /* & otrk.ot_stopped - flags for lock_state() */
loQueueAsync q_req;
loQueueBcast q_ret;
loShutdownConn shutdown_conn; /* locked by async.lk */
HRESULT sync_advise(int operation, void **arg, loRqid grp_key);
HRESULT async_advise(int conn, const IID *iface,
LightOPCGroup *grp, unsigned grp_key,
IUnknown *pUnk);
inline HRESULT async_unadvise(int conn, const IID *iface,
LightOPCGroup *grp, unsigned grp_key)
{ return async_advise(conn, iface, grp, grp_key, 0); }
/* [un]lock_state() must NOT be virtual ! */
int lock_state(const char *msg, const IID *riid_nostrict = 0);
/* returns 0 if Ok or -1 if out of service */
inline ULONG unlock_state(void)
{ UL_DEBUG((LOG_SR("unlock_state() -> finished: va=%d st=%d sd=%d rc=%d"),
loIS_VALID(this), otrk.ot_stopped, shuttingdown, RefCount));
return Release();}
void set_state(int oper, int state, const loWchar *reason);
void client_scheduler(void);
lw_rwlock lk_remove;
lw_rwlock lk_all;
#if LO_USE_BOTHMODEL
int (*lml_rd_lock)(lw_rwlock *lk, DWORD timeout);
int (*lml_wr_lock)(lw_rwlock *lk, DWORD timeout);
inline void lock_read(void) { lml_rd_lock(&lk_all, INFINITE); }
inline void lock_write(void) { lml_wr_lock(&lk_all, INFINITE); }
inline int RD_lock(lw_rwlock *rw) { return lml_rd_lock(rw, INFINITE); }
inline int WR_lock(lw_rwlock *rw) { return lml_wr_lock(rw, INFINITE); }
#else
inline int RD_lock(lw_rwlock *rw) { return lw_rw_rdlock(rw); }
inline int WR_lock(lw_rwlock *rw) { return lw_rw_wrlock(rw); }
inline void lock_read(void)
{
// UL_DEBUG((LOGID, "RdLock..."));
lw_rw_rdlock(&lk_all);
// UL_DEBUG((LOGID, "...RdLock"));
}
inline void lock_write(void)
{
// UL_DEBUG((LOGID, "WrLock..."));
lw_rw_wrlock(&lk_all);
// UL_DEBUG((LOGID, "...WrLock"));
}
#endif
inline void unlock(void)
{
// UL_DEBUG((LOGID, "UnLock..."));
lw_rw_unlock(&lk_all);
//UL_DEBUG((LOGID, "...UnLock"));
}
loStringBuf browsepos;
lw_mutex lk_browse;
inline void lock_browse(void) { lw_mutex_lock(&lk_browse); }
inline void unlock_browse(void) { lw_mutex_unlock(&lk_browse); }
HRESULT set_browsepos(const loWchar *pos, int len = -1);
int cat_browsepos(const loWchar *cpos);
void (*release_handle)(void *, loService *, loClient *);
void *release_handle_arg;
OPCSERVERSTATUS ostatus;
loMilliSec bandwidth_time;
unsigned long unique_GroupName;
OPCHANDLE unique_GroupHandle;
HRESULT mk_unique(loWchar buf[loUNIQUE_LEN], const void *ptr);
LightOPCServer();
virtual ~LightOPCServer();
int initialize(loService *serv, int ld_flags, const loVendorInfo *vi);
void selfdestroy(void);
int attach(void); /* set the owner */
int detach(void); /* should set ready = 0 and do some cleanup */
void clear_all(void);
LightOPCGroup *by_name(const loWchar *name);
unsigned by_handle(OPCHANDLE sgh);
LightOPCGroup *by_handle_g(unsigned sgh);
void del_all(int force = 0);
/* returns -1 on errors or ==0/!=0 depend on item's Release() */
int del(unsigned index, int force = 0);
unsigned add(LightOPCGroup *grp);
/* IUnknown implementation */
LONG RefCount;
STDMETHOD_ (ULONG, AddRef)(void);
STDMETHOD_ (ULONG, Release)(void);
STDMETHOD (QueryInterface) (REFIID riid, void **ppv);
/* IOPCCommon implementation */
char client_name[64]; /* no pointers - no locks */
STDMETHOD (SetLocaleID) (LCID dwLcid);
STDMETHOD (GetLocaleID) (LCID *dwLcid);
STDMETHOD (QueryAvailableLocaleIDs) (DWORD* pdwCount, LCID** pdwLcid);
STDMETHOD (GetErrorString)(LONG dwError, LPWSTR *ppString);
STDMETHOD (SetClientName) (LPCWSTR szClientName);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -