mirror of
https://github.com/X11Libre/xserver.git
synced 2026-11-14 05:14:45 +00:00
xaverius: expand registry tests for tombstone and DIX publication
Add real-header registry tests covering tombstone transitions, module-role finalize/shutdown ownership, and DIX-backed PhysicalDevice publication/duplicate-publish behavior using actual registry and resource APIs.
This commit is contained in:
parent
5c061f5f4d
commit
dbe1efc284
1 changed files with 172 additions and 30 deletions
|
|
@ -12,6 +12,11 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dix/dix_priv.h"
|
||||
#include "dix/resource_priv.h"
|
||||
#include "include/dixstruct.h"
|
||||
#include "include/resource.h"
|
||||
#include "os/client_priv.h"
|
||||
#include "tests-common.h"
|
||||
#include "xaverius_priv.h"
|
||||
|
||||
|
|
@ -90,7 +95,6 @@ xaverius_module_role_descriptor_validation(void)
|
|||
static void
|
||||
xaverius_identity_comparison(void)
|
||||
{
|
||||
/* PCI equality */
|
||||
{
|
||||
XaveriusDeviceIdentity a = { 0 };
|
||||
XaveriusDeviceIdentity b = { 0 };
|
||||
|
|
@ -101,7 +105,6 @@ xaverius_identity_comparison(void)
|
|||
assert(!xaverius_identity_equal(&a, &b));
|
||||
}
|
||||
|
||||
/* DRM equality */
|
||||
{
|
||||
XaveriusDeviceIdentity a = { 0 };
|
||||
XaveriusDeviceIdentity b = { 0 };
|
||||
|
|
@ -173,7 +176,6 @@ xaverius_ordering_key(void)
|
|||
assert(strncmp(buf, "pci:0000:01:00.0::", 18) == 0);
|
||||
assert(strstr(buf, "test-role") != NULL);
|
||||
|
||||
/* DRM identity produces different canonical key (ordering uses canonical identity) */
|
||||
{
|
||||
XaveriusDeviceIdentity drm = { 0 };
|
||||
drm.drm_major = 226;
|
||||
|
|
@ -185,13 +187,11 @@ xaverius_ordering_key(void)
|
|||
assert(strcmp(buf, dbuf) != 0);
|
||||
}
|
||||
|
||||
/* Too-small buffer must fail (no silent truncation) */
|
||||
{
|
||||
char tiny[8];
|
||||
assert(xaverius_create_ordering_key(tiny, sizeof(tiny), &pci, "long-owner-key") == XAVERIUS_REGISTRY_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
/* Bytewise ordering comparator */
|
||||
{
|
||||
char a[128], b[128];
|
||||
assert(xaverius_create_ordering_key(a, sizeof(a), &pci, "aaa") == XAVERIUS_REGISTRY_SUCCESS);
|
||||
|
|
@ -208,7 +208,20 @@ xaverius_module_role_ownership(void)
|
|||
XaveriusModuleRoleDescriptor desc;
|
||||
XaveriusModuleRole *role = NULL;
|
||||
|
||||
/* Successful create does not call hooks */
|
||||
/*
|
||||
* Ownership plan (module-owner original ref + binding refs):
|
||||
* - XaveriusModuleRoleCreate() creates and registers a role; no hook called.
|
||||
* The module owner holds the original role reference.
|
||||
* - XaveriusModuleRoleRetain/Release() are lifetime hook primitives.
|
||||
* - xaverius_binding_alloc() retains the role for a binding; xaverius_binding_free()
|
||||
* releases that binding reference (exactly once per binding lifetime).
|
||||
* - XaveriusModuleRoleFinalize() invokes the release hook once to drop the
|
||||
* module owner's original reference and frees server-owned role storage.
|
||||
* Caller must invoke finalize exactly once after all binding refs are gone.
|
||||
* - XaveriusRegistryFini() finalizes any remaining roles via Finalize() to
|
||||
* perform ordered shutdown cleanup.
|
||||
*/
|
||||
|
||||
make_valid_desc(&desc, "owner-a");
|
||||
reset_hook_counts();
|
||||
assert(XaveriusModuleRoleCreate(&desc, &role) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
|
|
@ -216,17 +229,16 @@ xaverius_module_role_ownership(void)
|
|||
assert(test_retain_calls == 0);
|
||||
assert(test_release_calls == 0);
|
||||
|
||||
/* Explicit retain/release balance */
|
||||
XaveriusModuleRoleRetain(role);
|
||||
assert(test_retain_calls == 1);
|
||||
XaveriusModuleRoleRelease(role);
|
||||
assert(test_release_calls == 1);
|
||||
|
||||
/* Finalize performs final release path */
|
||||
/* Finalize releases original owner reference and frees role storage. */
|
||||
XaveriusModuleRoleFinalize(role);
|
||||
assert(test_release_calls == 2);
|
||||
|
||||
/* Invalid descriptor: no hooks called */
|
||||
/* Invalid descriptors must not invoke hooks. */
|
||||
make_valid_desc(&desc, "owner-b");
|
||||
desc.abi_version = XAVERIUS_MODULE_ROLE_DESCRIPTOR_ABI_VERSION + 1;
|
||||
reset_hook_counts();
|
||||
|
|
@ -236,7 +248,6 @@ xaverius_module_role_ownership(void)
|
|||
assert(test_retain_calls == 0);
|
||||
assert(test_release_calls == 0);
|
||||
|
||||
/* Missing hook: rejected, no hooks called */
|
||||
make_valid_desc(&desc, "owner-c");
|
||||
desc.retain_module_role = NULL;
|
||||
reset_hook_counts();
|
||||
|
|
@ -257,7 +268,6 @@ test_query_snapshot_ok(struct _XaveriusDeviceBackendBinding *binding,
|
|||
snapshot_calls++;
|
||||
if (snapshot_result_mode != XAVERIUS_BACKEND_SUCCESS)
|
||||
return snapshot_result_mode;
|
||||
/* Registry deep-copies and frees the callback-provided snapshot buffer. */
|
||||
out->size = 16;
|
||||
out->data = calloc(1, out->size);
|
||||
assert(out->data != NULL);
|
||||
|
|
@ -312,7 +322,6 @@ xaverius_registry_registration_paths(void)
|
|||
|
||||
assert(XaveriusRegistryInit());
|
||||
|
||||
/* Pre-retain/pre-binding validation failures must not call role hooks */
|
||||
make_valid_desc(&desc, "reg-owner");
|
||||
reset_hook_counts();
|
||||
assert(XaveriusModuleRoleCreate(&desc, &role) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
|
|
@ -320,27 +329,25 @@ xaverius_registry_registration_paths(void)
|
|||
id.bus = 1;
|
||||
memset(id.driver_uuid, 0x44, sizeof(id.driver_uuid));
|
||||
|
||||
/* Missing snapshot callback -> INVALID_ARGUMENT, no retain/release */
|
||||
/* Pre-binding validation failures must not call role hooks. */
|
||||
setup_min_ops(&ops, true);
|
||||
ops.query_physical_snapshot = NULL;
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®, &dev, &dev_gen, &bind_gen) == XAVERIUS_REGISTRY_INVALID_ARGUMENT);
|
||||
assert(test_retain_calls == 0 && test_release_calls == 0);
|
||||
|
||||
/* Not-registered role generation -> NOT_REGISTERED, no hook calls */
|
||||
setup_min_ops(&ops, true);
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
reg.owner_role_generation = role->role_generation + 9999;
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®, &dev, &dev_gen, &bind_gen) == XAVERIUS_REGISTRY_NOT_REGISTERED);
|
||||
assert(test_retain_calls == 0 && test_release_calls == 0);
|
||||
|
||||
/* Invalid registration ABI -> INVALID_ARGUMENT, no hook calls */
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
reg.abi_version = XAVERIUS_DEVICE_BACKEND_REGISTRATION_ABI_VERSION + 1;
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®, &dev, &dev_gen, &bind_gen) == XAVERIUS_REGISTRY_INVALID_ARGUMENT);
|
||||
assert(test_retain_calls == 0 && test_release_calls == 0);
|
||||
|
||||
/* Snapshot callback failure after binding alloc: binding retain balanced by cleanup */
|
||||
/* Snapshot callback failure after binding alloc: retain/release balanced. */
|
||||
reg.abi_version = XAVERIUS_DEVICE_BACKEND_REGISTRATION_ABI_VERSION;
|
||||
snapshot_calls = 0;
|
||||
snapshot_result_mode = XAVERIUS_BACKEND_UNAVAILABLE;
|
||||
|
|
@ -351,7 +358,7 @@ xaverius_registry_registration_paths(void)
|
|||
assert(test_retain_calls == 1);
|
||||
assert(test_release_calls == 1);
|
||||
|
||||
/* Invalid snapshot content: balanced cleanup */
|
||||
/* Invalid snapshot content: retain/release balanced. */
|
||||
snapshot_result_mode = XAVERIUS_BACKEND_SUCCESS;
|
||||
ops.query_physical_snapshot = test_query_snapshot_bad;
|
||||
reg.ops = &ops;
|
||||
|
|
@ -362,7 +369,7 @@ xaverius_registry_registration_paths(void)
|
|||
assert(test_retain_calls == 1);
|
||||
assert(test_release_calls == 1);
|
||||
|
||||
/* Successful registration */
|
||||
/* Successful registration: binding retains role once. */
|
||||
setup_min_ops(&ops, true);
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
snapshot_calls = 0;
|
||||
|
|
@ -374,9 +381,9 @@ xaverius_registry_registration_paths(void)
|
|||
assert(test_retain_calls == 1);
|
||||
assert(test_release_calls == 0);
|
||||
assert(dev->binding != NULL);
|
||||
assert(dev->xid == 0); /* publication is separate */
|
||||
assert(dev->xid == 0);
|
||||
|
||||
/* Exact replay: additional caller ref, no new binding/retain */
|
||||
/* Exact replay: additional caller ref, no new binding/retain. */
|
||||
{
|
||||
XaveriusPhysicalDevice *dev2 = NULL;
|
||||
uint64_t dg2 = 0, bg2 = 0;
|
||||
|
|
@ -392,7 +399,7 @@ xaverius_registry_registration_paths(void)
|
|||
assert(dev->caller_refcount == ref_before);
|
||||
}
|
||||
|
||||
/* Conflict: same identity, different owning role */
|
||||
/* Conflict: same identity, different owning role -> no hook calls. */
|
||||
{
|
||||
XaveriusModuleRoleDescriptor desc2;
|
||||
XaveriusModuleRole *role2 = NULL;
|
||||
|
|
@ -401,31 +408,164 @@ xaverius_registry_registration_paths(void)
|
|||
XaveriusPhysicalDevice *devc = NULL;
|
||||
uint64_t dgc = 0, bgc = 0;
|
||||
make_valid_desc(&desc2, "reg-owner-2");
|
||||
reset_hook_counts();
|
||||
assert(XaveriusModuleRoleCreate(&desc2, &role2) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(test_retain_calls == 0 && test_release_calls == 0);
|
||||
setup_min_ops(&ops2, true);
|
||||
setup_min_reg(®2, &id, &ops2, role2);
|
||||
reset_hook_counts();
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®2, &devc, &dgc, &bgc) == XAVERIUS_REGISTRY_IDENTITY_CONFLICT);
|
||||
assert(test_retain_calls == 0);
|
||||
assert(test_release_calls == 0);
|
||||
|
||||
/* Binding removal releases exactly one retained binding role ref. */
|
||||
reset_hook_counts();
|
||||
assert(XaveriusRegistryRemoveDeviceBackendBinding(NULL, dev, dev_gen, role->role_generation, bind_gen) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(dev->binding == NULL);
|
||||
assert(test_release_calls == 1);
|
||||
|
||||
XaveriusPhysicalDeviceRelease(dev);
|
||||
|
||||
/* Shutdown finalizes remaining roles (owner original release once each). */
|
||||
reset_hook_counts();
|
||||
XaveriusRegistryFini();
|
||||
assert(test_release_calls == 2); /* role + role2 */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Binding removal releases exactly one retained binding role ref */
|
||||
reset_hook_counts();
|
||||
assert(XaveriusRegistryRemoveDeviceBackendBinding(NULL, dev, dev_gen, role->role_generation, bind_gen) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(dev->binding == NULL);
|
||||
assert(test_release_calls == 1);
|
||||
|
||||
/* Caller ref release is separate and does not free registry record */
|
||||
XaveriusPhysicalDeviceRelease(dev);
|
||||
|
||||
/* Registry shutdown cleans remaining records/resources.
|
||||
* (Exercise cleanup on a registry state without a registered DIX
|
||||
* PhysicalDevice resource type in this isolated unit-test process.) */
|
||||
XaveriusPhysicalDeviceType = 0;
|
||||
/* Fallback (not reached) */
|
||||
XaveriusRegistryFini();
|
||||
}
|
||||
|
||||
static void
|
||||
xaverius_registry_tombstone_lifecycle(void)
|
||||
{
|
||||
XaveriusModuleRoleDescriptor desc;
|
||||
XaveriusModuleRole *role = NULL;
|
||||
XaveriusDeviceIdentity id = { 0 };
|
||||
struct XaveriusDeviceBackendOps ops;
|
||||
XaveriusDeviceBackendRegistration reg;
|
||||
XaveriusPhysicalDevice *dev = NULL;
|
||||
uint64_t dev_gen = 0, bind_gen = 0;
|
||||
|
||||
assert(XaveriusRegistryInit());
|
||||
make_valid_desc(&desc, "tomb-owner");
|
||||
reset_hook_counts();
|
||||
assert(XaveriusModuleRoleCreate(&desc, &role) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
|
||||
id.bus = 7;
|
||||
id.function = 1;
|
||||
memset(id.driver_uuid, 0x55, sizeof(id.driver_uuid));
|
||||
setup_min_ops(&ops, true);
|
||||
snapshot_result_mode = XAVERIUS_BACKEND_SUCCESS;
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
|
||||
reset_hook_counts();
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®, &dev, &dev_gen, &bind_gen) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(dev != NULL);
|
||||
assert(test_retain_calls == 1 && test_release_calls == 0);
|
||||
assert(xaverius_physical_device_count == 1);
|
||||
assert(xaverius_tombstone_count == 0);
|
||||
|
||||
{
|
||||
XaveriusPhysicalDevice *obs_dev = NULL;
|
||||
uint64_t obs_gen = 0;
|
||||
const char source[] = "src-tomb";
|
||||
uint64_t obs_id = 1001;
|
||||
assert(XaveriusRegistryObserveDevice(NULL, &id, sizeof(id),
|
||||
source, sizeof(source),
|
||||
1, obs_id,
|
||||
&obs_dev, &obs_gen) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(obs_dev == dev);
|
||||
|
||||
/* Confirm removal moves device exactly once to tombstone list. */
|
||||
assert(XaveriusRegistryConfirmDeviceRemoved(NULL, dev, dev_gen, &id, sizeof(id)) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(dev->status == XAVERIUS_REGISTRY_REMOVED);
|
||||
assert(xaverius_physical_device_count == 0);
|
||||
assert(xaverius_tombstone_count == 1);
|
||||
assert(dev->xid == 0); /* unpublished device keeps no XID */
|
||||
|
||||
/* Second removal attempt must not move again. */
|
||||
assert(XaveriusRegistryConfirmDeviceRemoved(NULL, dev, dev_gen, &id, sizeof(id)) == XAVERIUS_REGISTRY_STALE_EVENT);
|
||||
assert(xaverius_physical_device_count == 0);
|
||||
assert(xaverius_tombstone_count == 1);
|
||||
}
|
||||
|
||||
/* Ordered shutdown frees tombstones and finalizes remaining role. */
|
||||
reset_hook_counts();
|
||||
XaveriusRegistryFini();
|
||||
assert(test_release_calls == 1); /* binding-retained role ref finalized on shutdown cleanup path */
|
||||
}
|
||||
|
||||
static void
|
||||
xaverius_registry_publish_dix(void)
|
||||
{
|
||||
static ClientRec test_client;
|
||||
static int dix_inited;
|
||||
XaveriusModuleRoleDescriptor desc;
|
||||
XaveriusModuleRole *role = NULL;
|
||||
XaveriusDeviceIdentity id = { 0 };
|
||||
struct XaveriusDeviceBackendOps ops;
|
||||
XaveriusDeviceBackendRegistration reg;
|
||||
XaveriusPhysicalDevice *dev = NULL;
|
||||
uint64_t dev_gen = 0, bind_gen = 0;
|
||||
void *res = NULL;
|
||||
int rc;
|
||||
|
||||
if (!dix_inited) {
|
||||
dixResetPrivates();
|
||||
memset(&test_client, 0, sizeof(test_client));
|
||||
test_client.index = 1;
|
||||
test_client.clientAsMask = ((XID)1 << CLIENTOFFSET);
|
||||
serverClient = &test_client;
|
||||
InitClient(serverClient, 0, (void *)NULL);
|
||||
assert(InitClientResources(serverClient));
|
||||
dix_inited = 1;
|
||||
}
|
||||
|
||||
XaveriusPhysicalDeviceType = 0;
|
||||
assert(XaveriusRegistryInit());
|
||||
make_valid_desc(&desc, "pub-owner");
|
||||
assert(XaveriusModuleRoleCreate(&desc, &role) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
|
||||
id.bus = 3;
|
||||
id.device = 2;
|
||||
memset(id.driver_uuid, 0x66, sizeof(id.driver_uuid));
|
||||
setup_min_ops(&ops, true);
|
||||
snapshot_result_mode = XAVERIUS_BACKEND_SUCCESS;
|
||||
setup_min_reg(®, &id, &ops, role);
|
||||
|
||||
assert(XaveriusRegistryRegisterDdxDevice(NULL, ®, &dev, &dev_gen, &bind_gen) == XAVERIUS_REGISTRY_SUCCESS);
|
||||
assert(dev != NULL);
|
||||
assert(dev->xid == 0);
|
||||
|
||||
/* Successful publication with real DIX resource registration. */
|
||||
assert(XaveriusPhysicalDevicePublish(dev) == true);
|
||||
assert(dev->xid != 0);
|
||||
res = NULL;
|
||||
rc = dixLookupResourceByType(&res, dev->xid, XaveriusPhysicalDeviceType,
|
||||
serverClient, DixReadAccess);
|
||||
assert(rc == Success);
|
||||
assert(res == dev);
|
||||
|
||||
/* Duplicate publication must fail and keep same XID/resource mapping. */
|
||||
{
|
||||
XID old = dev->xid;
|
||||
assert(XaveriusPhysicalDevicePublish(dev) == false);
|
||||
assert(dev->xid == old);
|
||||
res = NULL;
|
||||
rc = dixLookupResourceByType(&res, dev->xid, XaveriusPhysicalDeviceType,
|
||||
serverClient, DixReadAccess);
|
||||
assert(rc == Success);
|
||||
assert(res == dev);
|
||||
}
|
||||
|
||||
/* Ordered shutdown must release DIX wrapper and registry/tombstone state. */
|
||||
reset_hook_counts();
|
||||
XaveriusRegistryFini();
|
||||
assert(test_release_calls >= 1);
|
||||
}
|
||||
|
||||
const testfunc_t*
|
||||
xaverius_registry_test(void)
|
||||
{
|
||||
|
|
@ -435,6 +575,8 @@ xaverius_registry_test(void)
|
|||
xaverius_ordering_key,
|
||||
xaverius_module_role_ownership,
|
||||
xaverius_registry_registration_paths,
|
||||
xaverius_registry_tombstone_lifecycle,
|
||||
xaverius_registry_publish_dix,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue