loTrid loCacheUpdate(loService *se, unsigned count, loTagValue taglist[], FILETIME *timestamp) { unsigned ii; loTagValue *ts; #if 0 != LO_FILL_TIMESTAMP FILETIME ft; #endif // UL_DEBUG((LOGID, "loCacheUpdate(%p %u %p)", se, count, taglist)); if (!loSERVICE_OK(se)) return 0;//EBADF; /*ERROR:EARG*/ if (!timestamp && (0 >= count || !taglist)) return 0; #if 0 != LO_FILL_TIMESTAMP #if 1 == LO_FILL_TIMESTAMP se->driver.ldCurrentTime(&se->cactx, &ft); #else if (timestamp) ft = *timestamp; else memset(&ft, 0, sizeof(ft)); #endif #endif if (!(ts = loCacheLock(se))) { UL_INFO((LOGID, "loCacheUpdate() lock failed")); return 0;//-1; /*ERROR:out-of-service*/ } for(ii = 0; ii < count; ii++, taglist++) { loTagId ti; if (0 == (ti = taglist->tvTi)) continue; else if (ti < 1 || ti > se->lastused/*tag_count*/) { /*rv = -1;*//*ERROR:BAD ti*/ UL_INFO((LOGID, "loCacheUpdate(BAD ti:%u)", ii)); continue; } else { HRESULT hr; loTagValue *tv = &ts[ti]; tv->tvState = taglist->tvState; #if 0 != LO_FILL_TIMESTAMP if (!IsFILETIME(tv->tvState.tsTime)) tv->tvState.tsTime = ft; #endif /* hr = (V_ISBYREF(&taglist->tvValue)? VariantCopyInd(&tv->tvValue, &taglist->tvValue): VariantCopy(&tv->tvValue, &taglist->tvValue)); */ hr = VariantCopy(&tv->tvValue, &taglist->tvValue); if (S_OK != hr) { LO_E_BADTYPE_QUAL(hr, tv->tvState.tsError, tv->tvState.tsQuality); /*rv = -1;*//*ERROR:BAD VALUE*/ UL_WARNING((LOGID, "%!l loCacheUpdate(VariantCopy())", hr)); } tv->tvTi = ti; } } return loCacheUnlock(se, timestamp); /* return rv; */ }
lw_thrrettype loUpdatePipe(void *vse) { loService *se = (loService *)vse; if (!loIS_VALID(se)) { UL_ERROR((LOGID, "loUpdatePipe() prematurely terminated")); lw_RETURN; } UL_TRACE((LOGID, "loUpdatePipe() started...")); loThrControl_accept(&se->update_pipe); lw_mutex_lock(&se->update_pipe.lk); for(;; lw_conds_wait(&se->update_pipe.cond, &se->update_pipe.lk)) if (0 != se->update_pipe.tstate) { if (0 > se->update_pipe.tstate) break; /* terminate thread */ lw_mutex_unlock(&se->update_pipe.lk); lw_rw_wrlock(&se->lkPrim); lw_mutex_lock(&se->update_pipe.lk); if (0 > se->update_pipe.tstate) { lw_rw_unlock(&se->lkPrim); break; }/* terminate thread */ { /* do actual update here */ unsigned ii = se->lastused; loTagEntry *te = se->tags; loTagValue *ts = se->secondary; loTrid prim_changed = se->sec_trid; while(ii--) { te++; ts++; if (ts->tvTi) { if (ts->tvTi == loCH_TIMESTAMP) te->prim.tsTime = ts->tvState.tsTime; else { te->primChanged = prim_changed; te->prim = ts->tvState; #if LO_KEEP_OLD_CACHE { HRESULT hr; if (S_OK != (hr = VariantCopy(&te->primValue, &ts->tvValue))) { LO_E_BADTYPE_QUAL(hr, te->prim.tsError, te->prim.tsQuality); UL_WARNING((LOGID, "%!l loUpdatePipe(VariantCopy())", hr)); } } #else VariantClear(&te->primValue); te->primValue = ts->tvValue; VARIANTINIT(&ts->tvValue); #endif } ts->tvTi = 0; } } } se->prim_trid = se->sec_trid; #if 0 != LO_EV_TIMESTAMP if (se->ts_prim != se->ts_sec) { freeX(se->ts_prim); se->ts_prim = se->ts_sec; } memcpy(se->ts_prim, se->ts_prim + se->ts_size, se->ts_size * sizeof(FILETIME)); #endif lw_rw_unlock(&se->lkPrim); se->update_pipe.tstate = 0; lw_condb_broadcast(&se->lkTridWait); } loThrControl_finish(&se->update_pipe); lw_mutex_unlock(&se->update_pipe.lk); UL_NOTICE((LOGID, "loUpdatePipe() finished")); lw_RETURN; }
int loInternalServiceDestroy(loService *se) { int rv0, rv; unilog *log; UL_TRACE((LOGID, "loInternalServiceDestroy(%p)...", se)); if (!loIS_VALID(se)) { UL_ERROR((LOGID, "loInternalServiceDestroy(%p) illegal pointer", se)); return EBADF; } se->iam = 0; log = (unilog*)se->log; se->log = 0; rv = 0; if ((se->initphase & ifLKSEC) && (rv0 = loThrControl_destroy(&se->update_pipe)) && !rv) rv = rv0; if ((se->initphase & ifLKMGMT) && (rv0 = lw_rwlock_destroy(&se->lkMgmt)) && !rv) rv = rv0; if ((se->initphase & ifLKPRIM) && (rv0 = lw_rwlock_destroy(&se->lkPrim)) && !rv) rv = rv0; if ((se->initphase & ifLKDR) && (rv0 = lw_mutex_destroy(&se->lkDr)) && !rv) rv = rv0; if ((se->initphase & ifLKLIST) && (rv0 = lw_mutex_destroy(&se->lkList)) && !rv) rv = rv0; if ((se->initphase & ifTRWAIT) && (rv0 = lw_condb_destroy(&se->lkTridWait)) && !rv) rv = rv0; se->initphase = 0; /* cleanup the CACHE & ATTRIB */ if (se->secondary) loTagValue_clear(se->secondary, se->tag_count); if (se->tags) loTagEntry_clear(se->tags, se->tag_count); se->tag_count = 0; lo_proplist_clear(se); se->ts_size = 0; if (se->ts_prim != se->ts_sec && se->ts_sec) freeX(se->ts_sec); se->ts_sec = 0; if (se->ts_prim) freeX(se->ts_prim); se->ts_prim = 0; freeX(se); if (rv) UL_WARNING((LOGID, "%!e loDelete() finished", rv)); else UL_TRACE((LOGID, "loDelete() finished = %u", rv)); { #if 0 != LO_USE_MALLOCX // extern long mallocX_count; UL_WARNING((LOGID, "loDelete()::mallocX = %ld xobjref = %ld", mallocX_count, lo_X_objcount)); #endif mallocX_trap(); } if (log) unilog_Delete(log); return rv; }
int loServiceCreate(loService **result, const loDriver *drv, unsigned tagcount) { int rv = 0; size_t size; loService *se; if (!result) return EINVAL; *result = 0; if (!drv || 0 >= tagcount || 0 >= ++tagcount) return EINVAL; UL_DEBUG((LOGID, "structs: tE=%u tA=%u tD=%u tV=%u tS=%u tP=%u", sizeof(loTagEntry), sizeof(loTagAttrib), sizeof(loTagDetail), sizeof(loTagValue), sizeof(loTagState), sizeof(loTagPair))); size = sizeof(loService) + (sizeof(loTagEntry) + sizeof(loTagValue) + sizeof(lo_hash)) * tagcount; UL_TRACE((LOGID, "loCreate(%u) requested size = %u", tagcount - 1, size)); se = (loService*)mallocX(size); if (!se) { UL_ERROR((LOGID, "loCreate(%u) requested size = %ud FAILED", tagcount, size)); return ENOMEM; } se->iam = se; se->servlist = 0; se->serv_key = 0; se->shutdown = 0; se->initphase = 0; se->tag_count = 0; se->firstfree = 1; /* first entry is not used */ se->lastused = 0; se->lastnamed = 0; se->proplist = 0; se->proplist_count = 0; se->driver = *drv; se->cactx.ca_se = se; se->cactx.ca_se_arg = se->driver.ldDriverArg; se->cactx.ca_cli = 0; se->cactx.ca_cli_arg = 0; se->ts_prim = se->ts_sec = 0; se->ts_size = 0; se->log = 0; #if 0 <= USE_LOG if (!lolog) { lolog = (unilog*)(se->log = INIT_LOG()); UL_INFO((LOGID, "UNILOG initialization missed...")); UL_TRACE((LOGID, "loCreate(%u) requested size = %u", tagcount - 1, size)); } #endif se->ts_prim = se->ts_sec = (FILETIME*)mallocX(2 * sizeof(FILETIME)); if (!se->ts_prim) { rv = ENOMEM; UL_ERROR((LOGID, "ts_prim init() FAILED")); goto Fail; } memset(se->ts_prim, 0, 2 * sizeof(FILETIME)); se->ts_size = 1; if (rv = lo_proplist_init(se)) { UL_ERROR((LOGID, "lo_proplist_init() FAILED")); goto Fail; } lo_setup_clock(); if (se->driver.ldRefreshRate < 1) { se->driver.ldRefreshRate = lo_default_timegran( se->driver.ldRefreshRate_min < 1 ? &se->driver.ldRefreshRate_min : 0); if (se->driver.ldRefreshRate/*_min*/ < 1) se->driver.ldRefreshRate/*_min*/ = 16; } if (se->driver.ldRefreshRate_min < se->driver.ldRefreshRate) se->driver.ldRefreshRate_min = se->driver.ldRefreshRate; if (se->driver.ldQueueMax < 1) se->driver.ldQueueMax = 4; /* DEFAULT */ if ((se->driver.ldFlags & loDf_EE_SFALSE) == loDf_EE_SFALSE) se->driver.ldFlags &= ~loDf_EE_SFALSE; se->wstrcmp = (se->driver.ldFlags & loDF_IGNCASE)? _wcsicmp: wcscmp; se->wstrncmp = (se->driver.ldFlags & loDF_IGNCASE)? _wcsnicmp: wcsncmp; se->wstrhash = (se->driver.ldFlags & loDF_IGNCASE)? lo_wcsihash: lo_wcshash; #if 0 se->wstrnhash = (se->driver.ldFlags & loDF_IGNCASE)? lo_wcsnihash: lo_wcsnhash; #endif if (!se->driver.ldCurrentTime) se->driver.ldCurrentTime = ld_current_time; if (!se->driver.ldBranchSep || 0 >= mbtowc(&se->branch_sep, &se->driver.ldBranchSep, 1)) se->branch_sep = 0; UL_TRACE((LOGID, "Branch Separator = \\x%02X <%lc>\\x%02X", se->driver.ldBranchSep, se->branch_sep, se->branch_sep)); se->tags = (loTagEntry*)(&se[1]); loTagEntry_init(se->tags, tagcount); se->secondary = (loTagValue*)(&se->tags[tagcount]); loTagValue_init(se->secondary, tagcount); se->tag_count = tagcount; se->name_hash = (lo_hash*)(&se->secondary[tagcount]); memset(se->name_hash, 0, sizeof(lo_hash) * tagcount); /* we assume VT_EMPTY === 0 */ se->sec_trid = se->prim_trid = 0; /* se->prim_changed = 0; */ se->tags[0].attr.taDetail = (loTagDetail*)mallocX(sizeof(loTagDetail)); if (!se->tags[0].attr.taDetail) { UL_ERROR((LOGID, "loCreate(%u) taDetail FAILED", tagcount)); rv = ENOMEM; goto Fail; } loTagDetail_init(se->tags[0].attr.taDetail); se->tags[0].attr.taFlags = loTt_DETAILS | loTF_EMPTY; se->tags[0].attr.taDetail->tdName[0] = 0; se->tags[0].attr.taRangecent = 0.0; if (rv = lw_rwlock_init(&se->lkMgmt, 0)) { UL_ERROR((LOGID, "loCreate()::lkMgmt FAILED")); goto Fail; } se->initphase |= ifLKMGMT; if (rv = lw_rwlock_init(&se->lkPrim, 0)) { UL_ERROR((LOGID, "loCreate()::lkPrim FAILED")); goto Fail; } se->initphase |= ifLKPRIM; if (rv = lw_mutex_init(&se->lkList, 0)) { UL_ERROR((LOGID, "loCreate()::lkList FAILED")); goto Fail; } se->initphase |= ifLKLIST; if (rv = lw_mutex_init(&se->lkDr, 0)) { UL_ERROR((LOGID, "loCreate()::lkDr FAILED")); goto Fail; } se->initphase |= ifLKDR; if (rv = lw_condb_init(&se->lkTridWait, 0)) { UL_ERROR((LOGID, "loCreate()::lkTridWait FAILED")); goto Fail; } se->initphase |= ifTRWAIT; if (rv = loThrControl_init(&se->update_pipe)) { UL_ERROR((LOGID, "loCreate()::loThr_init FAILED")); goto Fail; } se->initphase |= ifLKSEC; if (rv = loThrControl_start(&se->update_pipe, 0, loUpdatePipe, se)) { UL_ERROR((LOGID, "loCreate()::loThr_start FAILED")); goto Fail; } se->cform_dataonly = RegisterClipboardFormat("OPCSTMFORMATDATA"); se->cform_datatime = RegisterClipboardFormat("OPCSTMFORMATDATATIME"); se->cform_writecompl = RegisterClipboardFormat("OPCSTMFORMATWRITECOMPLETE"); *result = se; return 0; Fail: UL_WARNING((LOGID, "%!e loCreate(%u) failed", rv, tagcount)); loServiceDestroy(se); return rv; }
int LightOPCServer::send_callback(LightOPCGroup *grp, unsigned group_key, loUpdList *upl, int advmask) { int tr = 0; IOPCDataCallback *c_databack = 0; IAdviseSink *c_datatime = 0, *c_dataonly = 0, *c_writecomp = 0; unsigned cform_dtime, cform_donly, cform_wrcompl; OPCHANDLE client_handle; // UL_DEBUG((LOGID, "send_notify(){...")); if (!upl->used) { if (!upl->trqid) return 0; if (S_OK == upl->master_err) upl->master_err = S_FALSE; } if (FAILED(upl->master_err)) upl->master_qual = S_FALSE; if (!grp) { lock_read(); if (0 == (grp = by_handle_g(group_key))) { unlock(); UL_INFO((LOGID, "send_callback(%x) FAILED: No such group")); return 0; } } #if LO_USE_BOTHMODEL && 0 else group_key = grp->ServerHandle; #endif client_handle = grp->ClientHandle; /* There is only client_sched() thread allowed to change connection info under read_lock ! */ if ((advmask & loRQ_CONN_DATABACK) && grp->conn_databack) loGET_IFACE(c_databack, grp->conn_databack, IOPCDataCallback, grp->initphase); if (advmask & (loRQ_CONN_DATA_1 | loRQ_CONN_WRITECOMPL)) { if ((advmask & loRQ_CONN_DATATIME) && grp->conn_datatime) { cform_dtime = se->cform_datatime; loGET_IFACE(c_datatime, grp->conn_datatime, IAdviseSink, grp->initphase); /* ?? advise_present &= ~loRQ_CONN_DATATIME */ } if ((advmask & loRQ_CONN_DATAONLY) && grp->conn_dataonly) { cform_donly = se->cform_dataonly; loGET_IFACE(c_dataonly, grp->conn_dataonly, IAdviseSink, grp->initphase); /* ?? advise_present &= ~loRQ_CONN_DATAONLY */ } if ((advmask & loRQ_CONN_WRITECOMPL) && grp->conn_writecompl) { cform_wrcompl = se->cform_writecompl; loGET_IFACE(c_writecomp, grp->conn_writecompl, IAdviseSink, grp->initphase); /* ?? advise_present &= ~loRQ_CONN_WRITECOMPL */ } } unlock(); // UL_DEBUG((LOGID, "send_notify() #3")); if (c_databack) { HRESULT hr = E_INVALIDARG; switch(advmask & loRQ_OPER_MASK) { case loRQ_OP_REFRESH: hr = c_databack->OnDataChange(upl->trqid, client_handle, upl->master_err, upl->master_qual, upl->used, upl->opchandle, upl->variant, upl->quality, upl->timestamp, upl->errors); break; case loRQ_OP_READ: hr = c_databack->OnReadComplete(upl->transaction_id, client_handle, upl->master_err, upl->master_qual, upl->used, upl->opchandle, upl->variant, upl->quality, upl->timestamp, upl->errors); break; case loRQ_OP_WRITE: hr = c_databack->OnWriteComplete(upl->transaction_id, client_handle, upl->master_err, upl->used, upl->opchandle, upl->errors); break; case loRQ_OP_CANCEL: hr = c_databack->OnCancelComplete(upl->transaction_id, client_handle); break; } c_databack->Release(); if (S_OK == hr) { tr++; UL_DEBUG((LOGID, "OnDataChange2(0x%X) Ok", advmask)); } else { UL_WARNING((LOGID, "%!l OnDataChange2(0x%X) FAILED", hr, advmask)); } // UL_WARNING((LOGID, "OnDataChange() 2 Ok")); } if (advmask & loRQ_CONN_DATA_1) { HGLOBAL gmem = 0; unsigned datasize = 0; if (c_datatime) { // UL_DEBUG((LOGID, "OnDataChange1() with time")); if (0 <= lo_OnDataChange1(upl, client_handle, cform_dtime, 1, c_datatime, &gmem, &datasize)) tr++; c_datatime->Release(); } if (c_dataonly) { // UL_DEBUG((LOGID, "OnDataChange1() without time")); if (0 <= lo_OnDataChange1(upl, client_handle, cform_donly, 0, c_dataonly, &gmem, &datasize)) tr++; c_dataonly->Release(); } if (gmem && (// && (!GlobalSize(gmem) ||*/ GlobalFree(gmem))) //(GlobalFlags(gmem) & (GMEM_INVALID_HANDLE | GMEM_DISCARDED)) || GlobalFree(gmem) ) ) { UL_WARNING((LOGID, "%!L GlobalFree(%X) FAILED flags=0x%X", gmem, GlobalFlags(gmem))); } } else if (c_writecomp) { // UL_DEBUG((LOGID, "OnWriteComplete1()")); if (0 <= lo_OnWriteComplete1(upl, client_handle, cform_wrcompl, c_writecomp, 0)) tr++; c_writecomp->Release(); } // UL_DEBUG((LOGID, "send_datachange() finished}")); return tr; }
int lo_OnDataChange1(loUpdList *upl, OPCHANDLE hClient, unsigned cform, int with_time, IAdviseSink *ias, HGLOBAL *gmem, unsigned *hint_dsize) { HGLOBAL fakegmem = 0; unsigned hdrsize, totalsize, ihdr_size, datasize; unsigned ii, itcount = upl->used; loUpdList lup = *upl; ihdr_size = with_time? sizeof(OPCITEMHEADER1): sizeof(OPCITEMHEADER2); hdrsize = sizeof(OPCGROUPHEADER) + itcount * ihdr_size; datasize = 0; if (hint_dsize && *hint_dsize) datasize = *hint_dsize; else { for(ii = itcount; ii--;) { datasize += loVariantSize(&lup.variant[ii]); } if (hint_dsize) *hint_dsize = datasize; } totalsize = hdrsize + datasize; if (!gmem) gmem = &fakegmem; if (!gmem_realloc(gmem, totalsize)) { itcount = 0; hdrsize = sizeof(OPCGROUPHEADER); if (!gmem_realloc(gmem, hdrsize)) { UL_ERROR((LOGID, "%!L Trasaction %X ABORTED due gmem_alloc(%u)", lup.trqid, totalsize)); return -1; } UL_WARNING((LOGID, "%!L Trasaction %X Failed due gmem_alloc(%u)", lup.trqid, totalsize)); totalsize = hdrsize; lup.master_err = E_OUTOFMEMORY; } { char *glob, *glob0, *ihdr; OPCGROUPHEADER *gh; FILETIME faketime, *timest = &faketime; unsigned timest_inc = 0; glob = glob0 = (char*)GlobalLock(*gmem); gh = (OPCGROUPHEADER*)glob; ihdr = (char*)&gh[1]; glob += hdrsize; if (with_time) timest_inc = sizeof(OPCITEMHEADER1), timest = &((OPCITEMHEADER1*)ihdr)->ftTimeStampItem; gh->dwSize = totalsize; gh->dwItemCount = itcount; gh->hClientGroup = hClient; gh->dwTransactionID = lup.trqid; for(ii = 0; ii < itcount; ii++) { ((OPCITEMHEADER1*)ihdr)->wReserved = 0; ((OPCITEMHEADER1*)ihdr)->dwValueOffset = glob - glob0; ((OPCITEMHEADER1*)ihdr)->hClient = lup.opchandle[ii]; ((OPCITEMHEADER1*)ihdr)->wQuality = lup.quality[ii]; loVariantPack((void**)&glob, &lup.variant[ii]); *timest = lup.timestamp[ii]; timest = (FILETIME*)(((char*)timest) + timest_inc); ihdr += ihdr_size; } gh->hrStatus = lup.master_err != S_OK? lup.master_err: lup.master_qual; if ((unsigned)(glob - glob0) != totalsize) { UL_ERROR((LOGID, "Transaction:%X datasize mismatch %u %u", lup.trqid, glob - glob0, totalsize)); } GlobalUnlock(*gmem); } { STGMEDIUM stgm; FORMATETC form; form.cfFormat = cform; form.dwAspect = DVASPECT_CONTENT; form.ptd = NULL; form.tymed = TYMED_HGLOBAL; form.lindex = -1; stgm.tymed = TYMED_HGLOBAL; stgm.STGM_hGlobal = *gmem; stgm.pUnkForRelease = DUMMY_UNKNOWN; UL_DEBUG((LOGID, "OnDataChange1:%s-time(%u)...%p{ %X", with_time? "with": "without", itcount, ias, *gmem)); ias->OnDataChange(&form, &stgm); UL_DEBUG((LOGID, "OnDataChange()...}")); } gmem_free(&fakegmem); return FAILED(lup.master_err)? -1: 0; }
int lo_OnWriteComplete1(loUpdList *upl, OPCHANDLE hClient, unsigned cform, IAdviseSink *ias, HGLOBAL *gmem) { HGLOBAL fakegmem = 0; unsigned datasize; unsigned ii, itcount = upl->used; loUpdList lup = *upl; datasize = sizeof(OPCGROUPHEADERWRITE) + itcount * sizeof(OPCITEMHEADERWRITE); if (!gmem) gmem = &fakegmem; if (!gmem_realloc(gmem, datasize)) { itcount = 0; datasize = sizeof(OPCGROUPHEADERWRITE); if (!gmem_realloc(gmem, datasize)) { UL_ERROR((LOGID, "%!L Trasaction %X ABORTED due gmem_alloc(%u)", lup.trqid, datasize)); return -1; } UL_WARNING((LOGID, "%!L Trasaction %X Failed due gmem_alloc(%u)", lup.trqid, datasize)); lup.master_err = E_OUTOFMEMORY; } { OPCGROUPHEADERWRITE *gh; OPCITEMHEADERWRITE *ihdr; gh = (OPCGROUPHEADERWRITE*)GlobalLock(*gmem); ihdr = (OPCITEMHEADERWRITE*)&gh[1]; gh->dwItemCount = itcount; gh->hClientGroup = hClient; gh->dwTransactionID = lup.trqid; gh->hrStatus = lup.master_err; for(ii = 0; ii < itcount; ii++, ihdr++) { ihdr->hClient = lup.opchandle[ii]; ihdr->dwError = lup.errors[ii]; // UL_DEBUG((LOGID, "OnWriteComplete(%u : %X/%X)", itcount, ihdr->dwError, gh->hrStatus)); } if ((unsigned)((char*)ihdr - (char*)gh) != datasize) { UL_ERROR((LOGID, "Transaction:%X datasize mismatch %u %u", lup.trqid, (char*)ihdr - (char*)gh, datasize)); } UL_DEBUG((LOGID, "OnWriteComplete(%u : %X/%X)", itcount, gh->hrStatus, lup.master_err)); GlobalUnlock(*gmem); } { STGMEDIUM stgm; FORMATETC form; form.cfFormat = cform; form.dwAspect = DVASPECT_CONTENT; form.ptd = NULL; form.tymed = TYMED_HGLOBAL; form.lindex = -1; stgm.tymed = TYMED_HGLOBAL; stgm.STGM_hGlobal = *gmem; stgm.pUnkForRelease = DUMMY_UNKNOWN; ias->OnDataChange(&form, &stgm); UL_DEBUG((LOGID, "OnWriteComplete()...}")); } gmem_free(&fakegmem); return FAILED(lup.master_err)? -1: 0; }