nwnss: complete NEB userspace boundary

This commit is contained in:
ChatGPT
2026-06-18 08:16:08 +00:00
committed by Mario Fetka
parent ea135aa1fa
commit 48109fe4bd
4 changed files with 245 additions and 7 deletions

View File

@@ -106,7 +106,7 @@ still stay original and remain listed, because later imports may rely on them.
| PARTIAL | `include/nwnss/include/nssOSAPIs.h` | ORIG+FIX | nwnss.neb, nwnss.schedule | MARS include hook checked; full original diff still open. |
| AUDITED | `include/nwnss/include/pssmpk.h` | PORT | nwnss.pssmpk | MPKNSS owner semantics checked/fixed in 0692. |
| AUDITED | `include/nwnss/include/schedule.h` | ORIG+FIX | nwnss.schedule | Userspace scheduler section scoped to MARS_NWE_NWNSS_USERSPACE; checked in 0691. |
| AUDITED | `include/nwnss/internal/nwnssZosCompat.h` | PORT | nwnss.neb, nwnss.schedule | Mars ZOS/NEB compat override header; checked in 0687-0689. |
| AUDITED | `include/nwnss/internal/nwnssZosCompat.h` | PORT | nwnss.neb, nwnss.schedule | Mars ZOS/NEB compat override header; rechecked in 0739/0740. It deliberately redirects imported ZOS scheduling/event/import/file macros to userspace boundary functions while keeping NSS business logic out of the compatibility header. |
| AUDITED | `include/nwnss/internal/spinlock.h` | PORT | nwnss.spinlock | Userspace spinlock port tested; checked in 0693. |
| PARTIAL | `src/nwnss/comn/common/mgmt.c` | ORIG wrapper | link smoke | Wrapper compiles mgmt.c.h; full original diff open. |
| PARTIAL | `src/nwnss/comn/common/ndp_comn.c` | ORIG wrapper | link smoke | Novell wrapper name/pattern; full audit open. |
@@ -121,7 +121,7 @@ still stay original and remain listed, because later imports may rely on them.
| AUDITED | `src/nwnss/library/misc/rbpTree.c` | PORT | nwnss.rbpTree | No original provider found beyond rbpTree.h/libNSS.imp/callers; CLRS-style algorithmic port checked against header contract in 0703 and strengthened in 0705 with explicit red/black, parent-link, binary-search-order, black-height, and Coin3D-style insertion/deletion stress coverage. Coin3D rbptree.cpp was checked only as an external BSD-licensed CLRS comparison and was not imported. |
| AUDITED | `src/nwnss/library/os/currentTime.c` | PORT | nwnss.utc | No userspace original provider exists after checking `public_core/library/utc` and `public_core/sharedsrc`; `public_core/nsslnxlib/nssLnxDummy.c` has a kernel jiffies-oriented `GetCurrentTime`, while `public_core/library/utc/gethres.386` documents the high-resolution timer unit as 100 microseconds. The userspace port keeps `GetCurrentTime()` on a monotonic centisecond/HZ=100 scale and now exposes `GetHighResolutionTimer()` on the documented 1/10000-second scale for checker/compression callers; covered by nwnss.utc. |
| AUDITED | `src/nwnss/library/os/delay.c` | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | Scheduler functions kept as userspace functions, not macros; original `ZOS_YieldThread`/sleep/schedule lock-boundary behavior rechecked against `nssOSAPIs.h`, and userspace yield now drops/reacquires MPKNSS when owned so other threads can run without the global lock held. |
| AUDITED | `src/nwnss/library/os/nebEventPort.c` | PORT | nwnss.neb | Explicit NEB/nebus service port; checked in 0683-0685. |
| AUDITED | `src/nwnss/library/os/nebEventPort.c` | PORT | nwnss.neb | Explicit NEB/nebus service port rechecked in 0740. No original NEB provider implementation is part of the delivered NSS source set beyond `neb.h`/`nebpub.h`/`nebmpk.h`; this file remains a bounded in-process userspace event-bus port and now covers the full public `nebpub.h` surface for link/test completeness. |
| AUDITED | `src/nwnss/library/os/pssmpk.c` | PORT | nwnss.pssmpk | pthread owner semantics checked/fixed in 0692. |
| AUDITED | `src/nwnss/library/stdlib/strtol.c` + `include/nwnss/library/xStdlib.h` | PORT + ORIG+FIX header | nwnss.stdlib | No LB_strtol original/sharedsrc found after full NSS/nss-common search; Novell/POSIX strtol semantics mapped to host libc and hardened in 0708. |
| TEMP | `src/nwnss/nssStartupNameGlobals.c` | TEMP | link smoke | Transition globals from nssStartup.c; should disappear later. |
@@ -290,7 +290,7 @@ even if it already compiles or has indirect test coverage.
| AUDITED | ORIG+FIX | nwnss.headers, namespace link smoke | `include/nwnss/internal/msgName.h` | Compared with original `shared/sdk/internal/msgName.h`; name-message layout kept. Differences are include-path normalization to `library/xUnicode.h`, `include/msgGen.h`, `include/nameSpace.h`, `include/hardLinkBeast.h`, plus whitespace/diff-check cleanup. |
| AUDITED | ORIG+FIX | nwnss.headers, cache link smoke | `include/nwnss/internal/nCache.h` | Compared with original `shared/sdk/internal/nCache.h`; name-cache API kept. Difference is include-path normalization to `include/xCache.h` only. |
| AUDITED | ORIG+FIX | link smoke | `include/nwnss/internal/nssFSHooks.h` | Compared with original `shared/sdk/internal/nssFSHooks.h`; FS hook/event macro surface kept. Differences are include-path normalization to `library/xUnicode.h` and `support/lnxmbINC/fshooks.h` plus whitespace/diff-check cleanup. Not included in the standalone header test because the original header depends on broader ENCP namespace constants. |
| AUDITED | PORT | nwnss.neb, nwnss.schedule | `include/nwnss/internal/nwnssZosCompat.h` | Mars ZOS/NEB compat override header; checked in 0687-0689. |
| AUDITED | PORT | nwnss.neb, nwnss.schedule | `include/nwnss/internal/nwnssZosCompat.h` | Mars ZOS/NEB compat override header; rechecked in 0739/0740. It deliberately redirects imported ZOS scheduling/event/import/file macros to userspace boundary functions while keeping NSS business logic out of the compatibility header. |
| AUDITED | ORIG | link smoke | `include/nwnss/internal/objectIDStore.h` | Byte-identical to original `shared/sdk/internal/objectIDStore.h`. |
| AUDITED | ORIG+FIX | nwnss.headers, link smoke | `include/nwnss/internal/pssConfig.h` | Compared with original `shared/sdk/internal/pssConfig.h`; PSS config layout/defaults kept. Differences are include-path normalization to `library/omni.h` and `include/hmc.h` plus whitespace cleanup. |
| AUDITED | ORIG+FIX | nwnss.headers, link smoke | `include/nwnss/internal/sbsMFL.h` | Compared with original `shared/sdk/internal/sbsMFL.h`; modified-file-list descriptors/prototypes kept. Differences are whitespace/diff-check cleanup only. |
@@ -587,7 +587,7 @@ even if it already compiles or has indirect test coverage.
| Status | Kind | Test coverage | File | Notes |
|---|---:|---|---|---|
| AUDITED | ORIG wrapper | link smoke | `src/nwnss/library/debug/otherErrorTables.c` | Restored to the original Novell wrapper shape: single `#include <otherErrorTables.c.h>`. The generated/base table flow is handled by imported buildtools and generated `nssErrorTable.c`. |
| AUDITED | ORIG+FIX | nwnss.pssdebug | `src/nwnss/library/debug/pssDebug.c` | Compared with original `public_core/library/debug/pssDebug.c`; debug logic kept. Differences are UNIX/userspace include handling, include-path normalization, disabled wio dependency in userspace, and whitespace. Test covers production debug macros; DBG_DebugFormatBinary is declared by the original header but not exercised directly because it is not part of the exported libnwnss ABI. |
| AUDITED | ORIG+FIX | nwnss.pssdebug | `src/nwnss/library/debug/pssDebug.c` | Compared with original `public_core/library/debug/pssDebug.c`; debug logic kept. Differences are UNIX/userspace include handling, include-path normalization, disabled WIO dependency in userspace, and whitespace. This remains a debug/console boundary only; no NSS runtime decisions depend on the host console port. Test covers production debug macros; DBG_DebugFormatBinary is declared by the original header but not exercised directly because it is not part of the exported libnwnss ABI. |
### Sources: library/eDir
@@ -647,7 +647,7 @@ even if it already compiles or has indirect test coverage.
| AUDITED | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | `src/nwnss/library/os/delay.c` | Compared with original `public_core/library/os/delay.c` and the original scheduler macros in `shared/sdk/internal/nssOSAPIs.h`; userspace keeps the scheduler API as real functions. `LB_delay`, `ZOS_Sleep`, `ZOS_ScheduleWorkToDo` and now `ZOS_YieldThread` preserve the original MPKNSS scheduling boundary by dropping/reacquiring the global lock when the current thread owns it; tests cover locked delay, schedule callbacks outside the lock and yield allowing another thread through the lock boundary. |
| AUDITED | ORIG+FIX | nwnss.inst | `src/nwnss/library/os/inst.c` | Compared with original `public_core/library/os/inst.c`; instrumentation harvest/reset/init logic kept. Differences are linux/module.h removal and include-path normalization; tests cover file/cache/Linux/BST counter harvest/reset and cyclic init wiring. |
| AUDITED | ORIG+FIX | nwnss.mailbox | `src/nwnss/library/os/mailbox.c` | Compared with original `public_core/library/os/mailbox.c`; mbInit/mbSetHigh behavior kept. Differences are procdefs/include-path normalization and whitespace cleanup; tests cover empty/full/FIFO, peek/drop, next/give and wraparound behavior. |
| AUDITED | PORT | nwnss.neb | `src/nwnss/library/os/nebEventPort.c` | Explicit NEB/nebus service port; checked in 0683-0685. |
| AUDITED | PORT | nwnss.neb | `src/nwnss/library/os/nebEventPort.c` | Explicit NEB/nebus service port rechecked in 0740. No original NEB provider implementation is part of the delivered NSS source set beyond `neb.h`/`nebpub.h`/`nebmpk.h`; this file remains a bounded in-process userspace event-bus port. It now covers the full public `nebpub.h` surface used for linking/tests (`GetEventBlocks`, `ReturnEventBlocks`, producer/consumer/filter registration and unregister, name queries, synchronous `ProduceEvent`). Filters are registered/unregistered for ABI compatibility but do not invent external NEB filtering semantics in the port. |
| AUDITED | PORT | nwnss.pssmpk | `src/nwnss/library/os/pssmpk.c` | pthread owner semantics checked/fixed in 0692. |
| AUDITED | ORIG+FIX/PORT | nwnss.snooze | `src/nwnss/library/os/snooze.c` | Compared with original `public_core/library/os/snooze.c`; snooze queue/timeout/roust logic kept. Differences are linux/module.h removal, include-path normalization and a legacy callback cast for secOneShot; tests cover empty roust behavior and the scheduler/snooze boundary remains covered by nwnss.schedule/nwnss.snooze. |
| AUDITED | ORIG+FIX | nwnss.worktodo | `src/nwnss/library/os/worktodo.c` | Compared with original `public_core/library/os/worktodo.c`; fillInWork field setup kept. Differences are procdefs/include-path normalization to `library/xStdlib.h`; tests cover resource tag, callback, reserved fields and NULL-user-parameter preservation. |
@@ -763,7 +763,7 @@ even if it already compiles or has indirect test coverage.
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/wWrapString.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/waprintf.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/wgetpos.c` | Must be compared against original source and classified. |
| AUDITED | ORIG+FIX/PORT | nwnss.wio | `src/nwnss/library/wio/wio.c` | Compared with original `public_core/library/wio/wio.c`; Linux/userspace screen I/O branch kept minimal and no-op friendly. Differences are include-path normalization, pssmpk visibility for userspace, whitespace cleanup and low-level output routed through host stdio-compatible helpers; tests cover printf/aprintf/wPrintf/wAPrintf/vprintf wrappers, fixed cursor fallback, wrap path and nonblocking key path. |
| AUDITED | ORIG+FIX/PORT | nwnss.wio | `src/nwnss/library/wio/wio.c` | Compared with original `public_core/library/wio/wio.c`; Linux/userspace screen I/O branch is intentionally minimal and no-op friendly. The non-Linux NetWare screen/key/pause logic is kept behind the original guard, while Linux/userspace output routes through host stdio-compatible helpers and preserves the MPKNSS lock drop/reacquire boundary around console output. Tests cover printf/aprintf/wPrintf/wAPrintf/vprintf wrappers, fixed cursor fallback, wrap path and nonblocking key path. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/wpause.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/wprintf.c` | Must be compared against original source and classified. |
| TODO | ORIG+FIX? | not yet classified | `src/nwnss/library/wio/wsetpos.c` | Must be compared against original source and classified. |

View File

@@ -21,9 +21,11 @@
#include <public/zOmni.h>
#include <public/neb.h>
#include <public/nebpub.h>
#include <library/stdlib.h>
#define MARS_NWE_NWNSS_NEB_MAX_CONSUMERS 128
#define MARS_NWE_NWNSS_NEB_MAX_PRODUCERS 128
#define MARS_NWE_NWNSS_NEB_MAX_FILTERS 64
#define MARS_NWE_NWNSS_NEB_NAME_LEN 128
struct NwnssNebConsumer
@@ -37,6 +39,7 @@ struct NwnssNebConsumer
LONG (*esr)(struct EventBlock *eventBlock);
char consumerName[MARS_NWE_NWNSS_NEB_NAME_LEN];
char eventName[MARS_NWE_NWNSS_NEB_NAME_LEN];
char filterName[MARS_NWE_NWNSS_NEB_NAME_LEN];
};
struct NwnssNebProducer
@@ -52,12 +55,22 @@ struct NwnssNebProducer
char eventName[MARS_NWE_NWNSS_NEB_NAME_LEN];
};
struct NwnssNebFilter
{
int used;
void *filterID;
LONG (*esr)(struct EventBlock *eventBlock);
char filterName[MARS_NWE_NWNSS_NEB_NAME_LEN];
};
static pthread_mutex_t nwnssNebLock = PTHREAD_MUTEX_INITIALIZER;
static struct NwnssNebConsumer nwnssNebConsumers[MARS_NWE_NWNSS_NEB_MAX_CONSUMERS];
static struct NwnssNebProducer nwnssNebProducers[MARS_NWE_NWNSS_NEB_MAX_PRODUCERS];
static struct NwnssNebFilter nwnssNebFilters[MARS_NWE_NWNSS_NEB_MAX_FILTERS];
static uintptr_t nwnssNebNextConsumerID = 1;
static uintptr_t nwnssNebNextProducerID = 1;
static uintptr_t nwnssNebNextEventID = 1;
static uintptr_t nwnssNebNextFilterID = 1;
static struct NwnssNebProducer *findProducerByID(void *producerID)
@@ -96,6 +109,36 @@ static struct NwnssNebConsumer *findConsumerByID(void *consumerID)
return NULL;
}
static struct NwnssNebFilter *findFilterByID(void *filterID)
{
for (unsigned i = 0; i < MARS_NWE_NWNSS_NEB_MAX_FILTERS; ++i)
{
if (nwnssNebFilters[i].used && nwnssNebFilters[i].filterID == filterID)
{
return &nwnssNebFilters[i];
}
}
return NULL;
}
static struct NwnssNebFilter *findFilterByName(const BYTE *filterName)
{
if (filterName == NULL)
{
return NULL;
}
for (unsigned i = 0; i < MARS_NWE_NWNSS_NEB_MAX_FILTERS; ++i)
{
if (nwnssNebFilters[i].used &&
strcmp(nwnssNebFilters[i].filterName, (const char *)filterName) == 0)
{
return &nwnssNebFilters[i];
}
}
return NULL;
}
static int eventNameMatches(const struct NwnssNebConsumer *consumer,
const struct EventBlock *eventBlock)
{
@@ -119,6 +162,109 @@ static int eventNameMatches(const struct NwnssNebConsumer *consumer,
return eventBlock->EBUserParameter == consumer->userParameter;
}
struct EventBlock *GetEventBlocks(void *ownerID, LONG numberOfEventBlocksToGet)
{
struct EventBlock *blocks;
(void)ownerID;
if (numberOfEventBlocksToGet <= 0)
{
return NULL;
}
blocks = zalloc((size_t)numberOfEventBlocksToGet * sizeof(*blocks));
if (blocks == NULL)
{
return NULL;
}
for (LONG i = 0; i < numberOfEventBlocksToGet; ++i)
{
blocks[i].EBVersion = NEB_EVENT_VERSION1;
blocks[i].EBStamp = EVENT_BLOCK_STAMP;
if (i + 1 < numberOfEventBlocksToGet)
{
blocks[i].EBILink = &blocks[i + 1];
}
}
return blocks;
}
LONG ReturnEventBlocks(struct EventBlock *eventBlock)
{
if (eventBlock == NULL)
{
return INVALID_PARAMETER;
}
free(eventBlock);
return SUCCESS;
}
LONG RegisterFilter(struct FilterRegistrationInfo *regFilter)
{
if (regFilter == NULL ||
regFilter->FRIFilterName == NULL ||
regFilter->FRIFilterID != NULL)
{
return INVALID_PARAMETER;
}
pthread_mutex_lock(&nwnssNebLock);
if (findFilterByName(regFilter->FRIFilterName) != NULL)
{
pthread_mutex_unlock(&nwnssNebLock);
return DUPLICATE_FILTER;
}
for (unsigned i = 0; i < MARS_NWE_NWNSS_NEB_MAX_FILTERS; ++i)
{
struct NwnssNebFilter *entry = &nwnssNebFilters[i];
if (!entry->used)
{
memset(entry, 0, sizeof(*entry));
entry->used = 1;
entry->filterID = (void *)nwnssNebNextFilterID++;
if (entry->filterID == NULL)
{
entry->filterID = (void *)nwnssNebNextFilterID++;
}
entry->esr = regFilter->FRIFilterESR;
snprintf(entry->filterName, sizeof(entry->filterName), "%s",
(const char *)regFilter->FRIFilterName);
regFilter->FRIFilterID = entry->filterID;
pthread_mutex_unlock(&nwnssNebLock);
return SUCCESS;
}
}
pthread_mutex_unlock(&nwnssNebLock);
return OUT_OF_RESOURCES;
}
LONG UnRegisterFilter(void *filterID)
{
if (filterID == NULL)
{
return INVALID_PARAMETER;
}
pthread_mutex_lock(&nwnssNebLock);
struct NwnssNebFilter *entry = findFilterByID(filterID);
if (entry == NULL)
{
pthread_mutex_unlock(&nwnssNebLock);
return INVALID_PARAMETER;
}
memset(entry, 0, sizeof(*entry));
pthread_mutex_unlock(&nwnssNebLock);
return SUCCESS;
}
LONG RegisterProducer(struct ProducerRegistrationInfo *regProducer)
{
if (regProducer == NULL ||
@@ -285,6 +431,11 @@ LONG RegisterConsumer(struct ConsumerRegistrationInfo *regConsumer)
snprintf(entry->eventName, sizeof(entry->eventName), "%s",
(const char *)regConsumer->CRIEventName);
}
if (regConsumer->CRIFilterName != NULL)
{
snprintf(entry->filterName, sizeof(entry->filterName), "%s",
(const char *)regConsumer->CRIFilterName);
}
regConsumer->CRIConsumerID = entry->consumerID;
pthread_mutex_unlock(&nwnssNebLock);
return SUCCESS;
@@ -387,6 +538,7 @@ LONG ProduceEvent(struct EventBlock *eventBlock)
for (unsigned i = 0; i < count; ++i)
{
LONG callbackStatus = EVENT_NOT_CONSUMED;
eventBlock->EBConsumingConsumer = snapshot[i].consumerID;
if (snapshot[i].callback != NULL)
{

View File

@@ -389,7 +389,6 @@ void LB__wioOutput(
#include <include/wio.h>
#include <include/pssmpk.h>
#include <include/pssmpk.h>
/**************************************************************************
* This is the LOW LEVEL write routine that outputs the given data

View File

@@ -11,6 +11,7 @@ static void *lastConsumingConsumer;
static char callOrder[8];
static int orderIndex;
static int esrCount;
static int filterCount;
static LONG nebTestCallback(struct EventBlock *eventBlock)
{
@@ -48,6 +49,12 @@ static LONG nebEsrCallback(struct EventBlock *eventBlock)
return EVENT_CONSUMED;
}
static LONG nebFilterCallback(struct EventBlock *eventBlock)
{
++filterCount;
return eventBlock->EBShortData.B32[0] == 99 ? EVENT_CONSUMED : EVENT_NOT_CONSUMED;
}
static void fillReg(struct ConsumerRegistrationInfo *reg,
const char *consumerName,
const char *eventName,
@@ -286,6 +293,78 @@ static int testProducerRegistrationAndZosMacros(void)
return rc;
}
static int testEventBlocksAndFilters(void)
{
struct EventBlock *blocks;
struct FilterRegistrationInfo filter;
struct FilterRegistrationInfo duplicate;
struct ConsumerRegistrationInfo consumer;
struct EventBlock eventBlock;
void *eventID = (void *)0x7777;
int rc = 0;
if (GetEventBlocks(NULL, 0) != NULL)
return 60;
blocks = GetEventBlocks(NULL, 2);
if (blocks == NULL)
return 61;
if (blocks[0].EBVersion != NEB_EVENT_VERSION1 ||
blocks[0].EBStamp != EVENT_BLOCK_STAMP ||
blocks[0].EBILink != &blocks[1] ||
blocks[1].EBILink != NULL)
rc = 62;
if (ReturnEventBlocks(blocks) != SUCCESS && rc == 0)
rc = 63;
if (ReturnEventBlocks(NULL) != (LONG)INVALID_PARAMETER && rc == 0)
rc = 64;
memset(&filter, 0, sizeof(filter));
filter.FRIVersion = NEB_FILTER_VERSION1;
filter.FRIFilterName = (BYTE *)"nwnss.neb.filter";
filter.FRIFilterESR = nebFilterCallback;
if (RegisterFilter(&filter) != SUCCESS && rc == 0)
rc = 65;
if (filter.FRIFilterID == NULL && rc == 0)
rc = 66;
memset(&duplicate, 0, sizeof(duplicate));
duplicate.FRIVersion = NEB_FILTER_VERSION1;
duplicate.FRIFilterName = (BYTE *)"nwnss.neb.filter";
if (RegisterFilter(&duplicate) != (LONG)DUPLICATE_FILTER && rc == 0)
rc = 67;
fillReg(&consumer, "nwnss.neb.filtered", "NSS.Test.Filtered", eventID,
SYNCHRONOUS_CONSUMER, 0, nebTestCallback, NULL);
consumer.CRIFilterName = (BYTE *)"nwnss.neb.filter";
if (RegisterConsumer(&consumer) != SUCCESS && rc == 0)
rc = 68;
memset(&eventBlock, 0, sizeof(eventBlock));
eventBlock.EBUserParameter = eventID;
eventBlock.EBShortData.B32[0] = 99;
callbackCount = 0;
filterCount = 0;
lastShortData = 0;
if (ProduceEvent(&eventBlock) != SUCCESS && rc == 0)
rc = 69;
else if (filterCount != 0 && rc == 0)
rc = 70;
else if (callbackCount != 1 && rc == 0)
rc = 71;
else if (lastShortData != 99 && rc == 0)
rc = 72;
if (UnRegisterConsumer(consumer.CRIConsumerID, eventID) != SUCCESS && rc == 0)
rc = 73;
if (UnRegisterFilter(filter.FRIFilterID) != SUCCESS && rc == 0)
rc = 74;
if (UnRegisterFilter(filter.FRIFilterID) != (LONG)INVALID_PARAMETER && rc == 0)
rc = 75;
return rc;
}
int main(void)
{
int rc;
@@ -296,6 +375,10 @@ int main(void)
return 101;
if (GetConsumerName(NULL, NULL) != (LONG)INVALID_PARAMETER)
return 102;
if (RegisterFilter(NULL) != (LONG)INVALID_PARAMETER)
return 103;
if (UnRegisterFilter(NULL) != (LONG)INVALID_PARAMETER)
return 104;
rc = testBasicRegisterNameDispatch();
if (rc != 0)
@@ -313,5 +396,9 @@ int main(void)
if (rc != 0)
return rc;
rc = testEventBlocksAndFilters();
if (rc != 0)
return rc;
return 0;
}