Beispiel #1
0
static void test_lock(void)
{
    int i = 0;
    int n = 100;
    //int counter = 0;

    Lock* lock = lock_create();

    for(i = 0; i < n; i++)
    {
        assert(lock_read(lock) == RET_OK);
        //assert(lock_get_rcounter(lock, &counter) == RET_OK);
        //assert(counter == 1);
        assert(data == 0);
        assert(lock_unread(lock) == RET_OK);
        //assert(lock_get_rcounter(lock, &counter) == RET_OK);
        //assert(counter == 0);
        assert(lock_write(lock) == RET_OK);
        data = 1;
        assert(lock_unwrite(lock) == RET_OK);

        assert(lock_read(lock) == RET_OK);
        assert(data == 1);
        assert(lock_unread(lock) == RET_OK);

        assert(lock_write(lock) == RET_OK);
        data = 0;
        assert(lock_unwrite(lock) == RET_OK);
    }

    lock_destroy(lock);

    return;
}
Beispiel #2
0
STDMETHODIMP LightOPCGroup::RemoveItems(DWORD dwCount,
                                        OPCHANDLE *phServer,
                                        HRESULT **ppErrors)
{
 HRESULT hr = S_OK;
 HRESULT *err = 0;

 LO_CHECK_STATEz1("RemoveItems", ppErrors);

 if (!dwCount || !phServer) { hr = E_INVALIDARG; goto Return; }

 err = (HRESULT*)loComAlloc(dwCount * sizeof(HRESULT));
 if (!err) { hr = E_OUTOFMEMORY; goto Return; }

 lock_write();
   {
    DWORD ii;
    LightOPCItem *item;

    for(ii = 0; ii < dwCount;)
      {
       unsigned tt;
       loTagId ti[32];

       for(tt = 0; tt < SIZEOF_ARRAY(ti) && ii < dwCount; ii++)
         if (item = by_index((unsigned)phServer[ii]))
           {
            if (item->bActive)
              {
               active_count--;
               ti[tt++] = item->tid;
              }
            del((unsigned)phServer[ii]);
            err[ii] = S_OK;
           }
         else
           {
            err[ii] = OPC_E_INVALIDHANDLE;
            hr = S_FALSE;
           }
       if (tt && Active) loChangeActivity(&owner->ctxt.cactx, 0, tt, ti);
      }

   }
 unlock();

Return:
 if (FAILED(hr))
   {
    UL_INFO((LOG_GRH("RemoveItems(%lu) = %s"), dwCount, loStrError(hr)));
   }
 else
   {
    if (ppErrors) *ppErrors = err, err = 0;
    UL_NOTICE((LOG_GRH("RemoveItems(%lu) = %s"), dwCount, loStrError(hr)));
   }
 if (err) loComFree(err);
 LO_FINISH();
 return hr;
}
MatchErrorCode
MatchTable::delete_entry(entry_handle_t handle)
{
  WriteLock lock = lock_write();

  return match_unit->delete_entry(handle);
}
Beispiel #4
0
HRESULT LightOPCServer::internalRemoveGroup(unsigned groupHandleID, int bForce)
{
#if 1
 HRESULT hr = loOPC_E_INVALIDHANDLE;
#else
 HRESULT hr = loOPC_E_NOTFOUND;
#endif
 unsigned ii;

 UL_DEBUG((LOG_SR("internalRemoveGroup(%u %s)"), groupHandleID, bForce? "FORCE": ""));

    WR_lock(&lk_remove);
    lock_write();
        if (ii = by_handle(groupHandleID))
          {
           hr = del(ii, bForce && !(/*se->driver.*/ldFlags & loDf_NOFORCE))
                   ? OPC_S_INUSE: S_OK;
           ostatus.dwGroupCount--;
          }
    unlock();
    lw_rw_unlock(&lk_remove);


 UL_DEBUG((LOGID, "%!l internalRemoveGroup(%u %s) =",
                   hr, groupHandleID, bForce? "FORCE": ""));
 return hr;
}
MatchErrorCode
MatchTableAbstract::set_entry_ttl(
  entry_handle_t handle, unsigned int ttl_ms
)
{
  if(!with_ageing) return MatchErrorCode::AGEING_DISABLED;
  WriteLock lock = lock_write();
  return match_unit_->set_entry_ttl(handle, ttl_ms);
}
MatchErrorCode
MatchTableIndirect::set_default_member(mbr_hdl_t mbr)
{
  WriteLock lock = lock_write();

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;
  default_index = IndirectIndex::make_mbr_index(mbr);

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirectWS::set_default_group(grp_hdl_t grp)
{
  WriteLock lock = lock_write();

  if(!is_valid_grp(grp)) return MatchErrorCode::INVALID_GRP_HANDLE;
  default_index = IndirectIndex::make_grp_index(grp);

  return MatchErrorCode::SUCCESS;
}
Beispiel #8
0
static void test_invalid_params(void)
{
    printf("==========Warning is normal begin==========\n");
    assert(lock_read(NULL) == RET_INVALID_PARAMS);
    assert(lock_unread(NULL) == RET_INVALID_PARAMS);
    assert(lock_write(NULL) == RET_INVALID_PARAMS);
    assert(lock_unwrite(NULL) == RET_INVALID_PARAMS);
    printf("==========Warning is normal end============\n");

    return;
}
MatchErrorCode
MatchTableIndirect::delete_entry(entry_handle_t handle)
{
  WriteLock lock = lock_write();

  const IndirectIndex *index;
  MatchErrorCode rc = match_unit->get_value(handle, &index);
  if(rc != MatchErrorCode::SUCCESS) return rc;
  index_ref_count.decrease(*index);
  
  return match_unit->delete_entry(handle);
}
MatchErrorCode
MatchTableIndirectWS::create_group(grp_hdl_t *grp)
{
  WriteLock lock = lock_write();

  if(grp_handles.get_handle(grp)) return MatchErrorCode::ERROR;

  groups_insert(*grp);

  num_groups++;

  return MatchErrorCode::SUCCESS;  
}
MatchErrorCode
MatchTableAbstract::write_counters(entry_handle_t handle,
				   counter_value_t bytes,
				   counter_value_t packets)
{
  ReadLock lock = lock_write();
  if(!with_counters) return MatchErrorCode::COUNTERS_DISABLED;
  if(!is_valid_handle(handle)) return MatchErrorCode::INVALID_HANDLE;
  MatchUnit::EntryMeta &meta = match_unit_->get_entry_meta(handle);
  // should I hide counter implementation more?
  meta.counter.write_counter(bytes, packets);
  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirect::add_entry(
  const std::vector<MatchKeyParam> &match_key, mbr_hdl_t mbr,
  entry_handle_t *handle, int priority
)
{
  WriteLock lock = lock_write();

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;
  IndirectIndex index = IndirectIndex::make_mbr_index(mbr);
  index_ref_count.increase(index);
  return match_unit->add_entry(match_key, std::move(index), handle, priority);
}
MatchErrorCode
MatchTable::modify_entry(
  entry_handle_t handle, const ActionFn *action_fn, ActionData action_data
)
{
  WriteLock lock = lock_write();

  ActionFnEntry action_fn_entry(action_fn, std::move(action_data));
  const ControlFlowNode *next_node = get_next_node(action_fn->get_id());
  return match_unit->modify_entry(
    handle, ActionEntry(std::move(action_fn_entry), next_node)
  );
}
Beispiel #14
0
STDMETHODIMP LightOPCGroup::SetClientHandles(DWORD dwCount,
                                             OPCHANDLE *phServer,
                                             OPCHANDLE *phClient,
		                             HRESULT **ppErrors)
{
 HRESULT hr = S_OK;
 HRESULT *err = 0;

 LO_CHECK_STATEz1("SetClientHandles", ppErrors);

 if (!dwCount || !phServer || !phClient)
   { hr = E_INVALIDARG; goto Return; }

 err = (HRESULT*)loComAlloc(dwCount * sizeof(HRESULT));
 if (!err) { hr = E_OUTOFMEMORY; goto Return; }

 lock_write();
   {
    DWORD ii;
    LightOPCItem *item;

    for(ii = 0; ii < dwCount; ii++)
      if (item = by_index((unsigned)phServer[ii]))
	{
         item->hClient = phClient[ii];
         err[ii] = S_OK;
        }
      else
        {
         err[ii] = OPC_E_INVALIDHANDLE;
         hr = S_FALSE;
        }
   }
 unlock();

Return:

 if (FAILED(hr))
   {
    UL_INFO((LOG_GRH("SetClientHandles(%lu) = %s"), dwCount, loStrError(hr)));
   }
 else
   {
    if (ppErrors) *ppErrors = err, err = 0;
    UL_NOTICE((LOG_GRH("SetClientHandles(%lu) = %s"), dwCount, loStrError(hr)));
   }
 if (err) loComFree(err);

 LO_FINISH();
 return hr;
}
MatchErrorCode
MatchTable::set_default_action(
  const ActionFn *action_fn, ActionData action_data
)
{
  ActionFnEntry action_fn_entry(action_fn, std::move(action_data));
  const ControlFlowNode *next_node = get_next_node(action_fn->get_id());

  WriteLock lock = lock_write();

  default_entry = ActionEntry(std::move(action_fn_entry), next_node);

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirectWS::add_entry_ws(
  const std::vector<MatchKeyParam> &match_key,
  grp_hdl_t grp, entry_handle_t *handle, int priority
)
{
  WriteLock lock = lock_write();

  if(!is_valid_grp(grp)) return MatchErrorCode::INVALID_GRP_HANDLE;

  if(get_grp_size(grp) == 0) return MatchErrorCode::EMPTY_GRP;

  IndirectIndex index = IndirectIndex::make_grp_index(grp);
  index_ref_count.increase(index);
  return match_unit->add_entry(match_key, std::move(index), handle, priority);
}
MatchErrorCode
MatchTableIndirectWS::remove_member_from_group(mbr_hdl_t mbr, grp_hdl_t grp)
{
  WriteLock lock = lock_write();

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;
  if(!is_valid_grp(grp)) return MatchErrorCode::INVALID_GRP_HANDLE;

  GroupInfo &group_info = group_entries[grp];
  MatchErrorCode rc = group_info.delete_member(mbr);
  if(rc != MatchErrorCode::SUCCESS) return rc;

  index_ref_count.decrease(IndirectIndex::make_mbr_index(mbr));

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirect::modify_member(
  mbr_hdl_t mbr, const ActionFn *action_fn, ActionData action_data
)
{
  ActionFnEntry action_fn_entry(action_fn, std::move(action_data));
  const ControlFlowNode *next_node = get_next_node(action_fn->get_id());

  WriteLock lock = lock_write();

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;

  action_entries[mbr] = ActionEntry(std::move(action_fn_entry), next_node);

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirect::delete_member(mbr_hdl_t mbr)
{
  WriteLock lock = lock_write();

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;

  if(index_ref_count.get(IndirectIndex::make_mbr_index(mbr)) > 0)
    return MatchErrorCode::MBR_STILL_USED;

  assert(!mbr_handles.release_handle(mbr));

  num_members--;

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTable::add_entry(
  const std::vector<MatchKeyParam> &match_key,
  const ActionFn *action_fn, ActionData action_data, // move it
  entry_handle_t *handle, int priority
)
{
  ActionFnEntry action_fn_entry(action_fn, std::move(action_data));
  const ControlFlowNode *next_node = get_next_node(action_fn->get_id());

  WriteLock lock = lock_write();

  return match_unit->add_entry(
    match_key,
    ActionEntry(std::move(action_fn_entry), next_node),
    handle, priority
  );
}
Beispiel #21
0
STDMETHODIMP LightOPCGroup::SetState(DWORD *pRequestedUpdateRate, DWORD *pRevisedUpdateRate,
		                  BOOL *pActive, LONG *pTimeBias, FLOAT *pPercentDeadband,
		                  DWORD *pLCID, OPCHANDLE *phClientGroup)
{
 HRESULT hr = S_OK;

 LO_CHECK_STATEz0("SetState");
 UL_TRACE((LOG_GRH("LightOPCGroup::SetState()")));

 if (pLCID && owner->se->driver.ldCheckLocale &&
              owner->se->driver.ldCheckLocale(&owner->ctxt.cactx, *pLCID))
   pLCID = 0; /* ignore on errors */
 lock_write();
    if (pRequestedUpdateRate)
      {
//	  if (!pRevisedUpdateRate) hr = E_INVALIDARG;
       DWORD revised_rate = loReviseUpdateRate(owner->se, *pRequestedUpdateRate);
       if (UpdateRate > revised_rate && (!pActive || *pActive)
         /* && Active && 0 != (advise_present & advise_enabled)*/)
         UpdateRate = revised_rate, actuate_async(0);
       else UpdateRate = revised_rate;
       if (UpdateRate != *pRequestedUpdateRate) hr = OPC_S_UNSUPPORTEDRATE;
      }
    if (pRevisedUpdateRate) *pRevisedUpdateRate = UpdateRate;
    if (pActive) set_active(*pActive);
    if (pTimeBias) TimeBias = *pTimeBias;
    if (pPercentDeadband)
      if (lo_IsNANf(*pPercentDeadband) ||
          *pPercentDeadband < 0. ||
          *pPercentDeadband > 100.) hr = E_INVALIDARG;
      else Deadband = *pPercentDeadband;
    if (pLCID) grLCID = *pLCID;
    if (phClientGroup) ClientHandle = *phClientGroup;
 unlock();

 if (!FAILED(hr)) UL_NOTICE((LOG_GR("SetGroupState(%u) =(%umS (%umS) %g%%)Ok"),
                  ServerHandle, (unsigned)UpdateRate,
                  (unsigned)(pRequestedUpdateRate? *pRequestedUpdateRate: 0),
                  Deadband));
 else UL_INFO((LOG_GR("SetGroupState(%u) =%s"), ServerHandle, loStrError(hr)));

 LO_FINISH();
 return hr;
}
MatchErrorCode
MatchTableIndirect::modify_entry(
  entry_handle_t handle, mbr_hdl_t mbr
)
{
  WriteLock lock = lock_write();

  const IndirectIndex *index;
  MatchErrorCode rc = match_unit->get_value(handle, &index);
  if(rc != MatchErrorCode::SUCCESS) return rc;
  index_ref_count.decrease(*index);

  if(!is_valid_mbr(mbr)) return MatchErrorCode::INVALID_MBR_HANDLE;

  IndirectIndex new_index = IndirectIndex::make_mbr_index(mbr);
  index_ref_count.increase(new_index);

  return match_unit->modify_entry(handle, std::move(new_index));
}
MatchErrorCode
MatchTableIndirect::add_member(
  const ActionFn *action_fn, ActionData action_data,
  mbr_hdl_t *mbr
)
{
  ActionFnEntry action_fn_entry(action_fn, std::move(action_data));
  const ControlFlowNode *next_node = get_next_node(action_fn->get_id());

  WriteLock lock = lock_write();

  if(mbr_handles.get_handle(mbr)) return MatchErrorCode::ERROR;

  entries_insert(*mbr, ActionEntry(std::move(action_fn_entry), next_node));

  num_members++;

  return MatchErrorCode::SUCCESS;
}
MatchErrorCode
MatchTableIndirectWS::modify_entry_ws(
  entry_handle_t handle, grp_hdl_t grp
)
{
  WriteLock lock = lock_write();

  const IndirectIndex *index;
  MatchErrorCode rc = match_unit->get_value(handle, &index);
  if(rc != MatchErrorCode::SUCCESS) return rc;
  index_ref_count.decrease(*index);

  if(!is_valid_grp(grp)) return MatchErrorCode::INVALID_GRP_HANDLE;

  if(get_grp_size(grp) == 0) return MatchErrorCode::EMPTY_GRP;

  IndirectIndex new_index = IndirectIndex::make_grp_index(grp);
  index_ref_count.increase(new_index);

  return match_unit->modify_entry(handle, std::move(new_index));
}
MatchErrorCode
MatchTableIndirectWS::delete_group(grp_hdl_t grp)
{
  WriteLock lock = lock_write();

  if(!is_valid_grp(grp)) return MatchErrorCode::INVALID_GRP_HANDLE;

  if(index_ref_count.get(IndirectIndex::make_grp_index(grp)) > 0)
    return MatchErrorCode::GRP_STILL_USED;

  /* we allow deletion of non-empty groups, but we must remember to decrease the
     ref count for the members. Note that we do not allow deletion of a member
     which is in a group */
  GroupInfo &group_info = group_entries[grp];
  for(auto mbr : group_info)
    index_ref_count.decrease(IndirectIndex::make_mbr_index(mbr));

  assert(!grp_handles.release_handle(grp));

  num_groups--;

  return MatchErrorCode::SUCCESS;
}
Beispiel #26
0
STDMETHODIMP LightOPCGroup::SetName(LPCWSTR szName)
{
 HRESULT hr = S_OK;

 LO_CHECK_STATEz0("SetName");

 UL_TRACE((LOG_GRH("LightOPCGroup::SetName()")));
 if (!szName) hr = E_INVALIDARG;
 else
   {
    LightOPCGroup *grp;
    lock_write();
       grp = owner->by_name(szName);
       if (!grp) hr = set_name(szName);
       else if (grp != this) hr = OPC_E_DUPLICATENAME;
    unlock();
   }
 if (S_OK != hr) UL_INFO((LOG_GRH("SetGroupName(%ls) =%s"),
                              loWnul(szName), loStrError(hr)));
 else UL_NOTICE((LOG_GRH("SetGroupName(%ls)"), szName));

 LO_FINISH();
 return hr;
}
Beispiel #27
0
STDMETHODIMP LightOPCGroup::SetDatatypes(DWORD dwCount,
                                         OPCHANDLE *phServer,
                                         VARTYPE *pRequestedDatatypes,
		                         HRESULT **ppErrors)
{
 HRESULT hr = S_OK;
 HRESULT *err = 0;
 loTagEntry *te;
 loCallerx cctx;

 LO_CHECK_STATEz1("SetDatatypes", ppErrors);

 if (!dwCount || !phServer || !pRequestedDatatypes)
   { hr = E_INVALIDARG; goto Return; }

 err = (HRESULT*)loComAlloc(dwCount * sizeof(HRESULT));
 if (!err) { hr = E_OUTOFMEMORY; goto Return; }

 te = owner->se->tags;
 cctx = owner->ctxt;

 lock_write();
   {
    DWORD ii;
    LightOPCItem *item;
    cctx.cta.vc_lcid = grLCID;

    for(ii = 0; ii < dwCount; ii++)
      if (item = by_index((unsigned)phServer[ii]))
        {
         VARTYPE vt;
         loTagAttrib *ta;
        /* if (VT_EMPTY == (vt = pRequestedDatatypes[ii]))
           item->vtRequestedDataType = vt, err[ii] = S_OK;
         else */
         if (S_OK == (err[ii] = lo_checktype(&cctx,
                                  ta = &te[item->tid].attr,
				                  vt = pRequestedDatatypes[ii])))
           {
            item->vtRequestedDataType = vt;
            item->convtype = lo_check_conversion(ta, vt);
           }
         else hr = S_FALSE;
        }
      else
        {
         err[ii] = OPC_E_INVALIDHANDLE;
         hr = S_FALSE;
        }
   }
 unlock();

Return:

 if (FAILED(hr))
   {
    UL_INFO((LOG_GRH("SetDatatypes(%lu) = %s"), dwCount, loStrError(hr)));
   }
 else
   {
    if (ppErrors) *ppErrors = err, err = 0;
    UL_NOTICE((LOG_GRH("SetDatatypes(%lu) = %s"), dwCount, loStrError(hr)));
   }
 if (err) loComFree(err);
 LO_FINISH();
 return hr;
}
void
MatchTableAbstract::reset_state() {
  WriteLock lock = lock_write();
  reset_state_();
}
Beispiel #29
0
STDMETHODIMP LightOPCGroup::SetActiveState(DWORD dwCount,
                                           OPCHANDLE *phServer,
                                           BOOL bActive,
                                           HRESULT **ppErrors)
{
 HRESULT hr = S_OK;
 HRESULT *err = 0;
 int aqual = OPC_QUALITY_OUT_OF_SERVICE;
 unsigned aact = 0;

 LO_CHECK_STATEz1("SetActiveState", ppErrors);

 if (!dwCount || !phServer /*|| !ppErrors*/)
   { hr = E_INVALIDARG; goto Return; }

 err = (HRESULT*)loComAlloc(dwCount * sizeof(HRESULT));
 if (!err) { hr = E_OUTOFMEMORY; goto Return; }
 if (bActive = 0 != bActive) aqual = -1;

 lock_write();
   {
    DWORD ii;
    LightOPCItem *item;

    for(ii = 0; ii < dwCount;)
      {
       unsigned tt;
       loTagId ti[32];

       for(tt = 0; tt < SIZEOF_ARRAY(ti) && ii < dwCount; ii++)
         if (item = by_index((unsigned)phServer[ii]))
           {
            if (item->bActive != bActive /*&&
               (OPC_READABLE & tags[item->tid].attr.flag)*/)
              {
               aact++;
               item->bActive = bActive;
               ti[tt++] = item->tid;
               item->Quality = aqual;
               item->TouchChanged();
              }
            err[ii] = S_OK;
           }
         else
           {
            err[ii] = OPC_E_INVALIDHANDLE;
            hr = S_FALSE;
           }

       if (tt && Active) loChangeActivity(&owner->ctxt.cactx, bActive, tt, ti);
      }
    if (bActive)
      active_count += aact, last_trid = 0;
    else active_count -= aact;
   }
 unlock();

Return:

 if (FAILED(hr))
   {
    UL_INFO((LOG_GRH("SetActiveState(%lu, %u) = %s"),
                       dwCount, bActive, loStrError(hr)));
   }
 else
   {
    if (ppErrors) *ppErrors = err, err = 0;
    UL_NOTICE((LOG_GRH("SetActiveState(%lu, %u) = %s"),
                      dwCount, bActive, loStrError(hr)));
   }
 if (err) loComFree(err);

 LO_FINISH();
 return hr;
}
Beispiel #30
0
STDMETHODIMP LightOPCGroup::AddItems(DWORD dwCount,
                                     OPCITEMDEF *pItemArray,
                                     OPCITEMRESULT **ppAddResults,
                                     HRESULT **ppErrors)
{
 HRESULT hr;
 HRESULT *err = 0;
 OPCITEMRESULT *ir = 0;
 loTagId *tid = 0;
 void **acpath;
 LightOPCItem **oi = 0;
 DWORD ii;
 loTagEntry *tags;
 unsigned act_count;
 loAA_DECLARE(sizeof(LightOPCItem*) + sizeof(loTagId) + sizeof(void*));

 LO_CHECK_STATEz2("AddItems", ppAddResults, ppErrors);
 if (!ppAddResults) { hr = E_INVALIDARG; goto Return; }

 ii = dwCount * (sizeof(*oi) + sizeof(*tid) + sizeof(*acpath));
 if (0 == ii) { hr = E_INVALIDARG; goto Return; }
 if (!(oi = (LightOPCItem**)loAA_ALLOC(ii))) { hr = E_OUTOFMEMORY; goto Return; }
 memset(oi, 0, ii);
 tid = (loTagId*)&oi[dwCount];
 acpath = (void**)&tid[dwCount];

 hr = internalValidateItems(dwCount, pItemArray, tid, acpath, &ir, &err);
 if (FAILED(hr)) goto Return;

 tags = owner->se->tags;

 for(ii = 0; ii < dwCount; ii++)
   if (S_OK == err[ii])
     {
      LightOPCItem *newby;
      hr = E_OUTOFMEMORY;

      if (oi[ii] = newby = new LightOPCItem)
        {
         OPCITEMDEF *idef = &pItemArray[ii];
         loTagAttrib *ta = &tags[tid[ii]].attr;
         newby->tid = tid[ii];
         newby->AcPath = acpath[ii];
         newby->hClient = idef->hClient;

         newby->vtRequestedDataType = idef->vtRequestedDataType;
         newby->convtype = lo_check_conversion(ta, newby->vtRequestedDataType);

         hr = S_OK;
         if ((NULL == newby->AcPath ||
             S_OK == (hr = newby->set_accpath(idef->szAccessPath))) &&
             (!ta->taName || !(ta->taFlags & loTF_CANONAME) &&
#if 0
              wcscmp
#else
         owner->se->wstrcmp
#endif
                    (ta->taName, idef->szItemID)))
           hr = newby->set_itemid(idef->szItemID);
         newby->Quality = -1;
         if (0 == (newby->bActive = 0 != idef->bActive))
           tid[ii] = 0, newby->Quality = OPC_QUALITY_OUT_OF_SERVICE;
//         else if (!(OPC_READABLE & tags[tid[ii]].attr.flag))
  //         newby->bActive = 0;
        }
      err[ii] = hr;
      if (hr != S_OK)
        UL_NOTICE((LOG_GR("AddItem(%ls)(%ls)%x/%x = %s"),
	                loWnul(pItemArray[ii].szItemID),
	   		        loWnul(pItemArray[ii].szAccessPath),
                           pItemArray[ii].vtRequestedDataType,
                           ir[ii].vtCanonicalDataType,
			        loStrError(err[ii])));
     }

 act_count = 0;
 lock_write();
    for(ii = 0; ii < dwCount; ii++)
      if (S_OK == err[ii])
        {
         unsigned idx;
         if (idx = add(oi[ii]))
           {
            act_count += oi[ii]->bActive /* != 0*/;
            oi[ii] = 0;
            ir[ii].hServer = (OPCHANDLE)idx;
           }
	     else
           {
            err[ii] = E_OUTOFMEMORY;
            tid[ii] = 0;
            hr = S_FALSE;
            UL_NOTICE((LOG_GR("AddItem:add(%ls)(%ls)%x/%x = %s"),
	                loWnul(pItemArray[ii].szItemID),
	   		        loWnul(pItemArray[ii].szAccessPath),
                           pItemArray[ii].vtRequestedDataType,
                           ir[ii].vtCanonicalDataType,
			        loStrError(err[ii])));
           }
        }
      else
        {
         tid[ii] = 0;
         hr = S_FALSE;
        } /* end of for(;;) */
    if (act_count)
      {
       active_count += act_count;
       if (Active)
         {
          loChangeActivity(&owner->ctxt.cactx, 1, (unsigned)dwCount, tid);
          last_trid = 0; /* force callback */
         }
      }
 unlock();

Return:

 if (oi)
   {
    for(ii = 0; ii < dwCount; ii++)
      if (oi[ii]) delete oi[ii];
    loAA_FREE(oi);
   }

 if (FAILED(hr))
   {
    UL_INFO((LOG_GRH("AddItems(%lu) = %s"), dwCount, loStrError(hr)));
   }
 else
   {
    *ppAddResults = ir, ir = 0;
    if (ppErrors) *ppErrors = err, err = 0;
    UL_NOTICE((LOG_GRH("AddItems(%lu) = %s"), dwCount, loStrError(hr)));
   }
 if (ir)  loComFree(ir);
 if (err) loComFree(err);

 LO_FINISH();
 return hr;
}