From 549d694d34837471e6aa3e6447edb54e70bd5254 Mon Sep 17 00:00:00 2001 From: Joe Esquibel Date: Sat, 5 Sep 2026 08:43:57 -0400 Subject: [PATCH] feat(core-engine): jcl sync_locks counts the exclusive-ENQ dispositions (#2733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #2733 was filed as a design question with two acceptable outcomes. Taking option (a): add the narrowed rule and accept the documented overlap with io. DISP=OLD and DISP=MOD request an exclusive system ENQ on a dataset; DISP=SHR requests shared access. That is a lock acquisition declared in the job deck -- the construct sync_locks already measures through each language's own idiom (cobol's EXEC CICS ENQ, abap's ENQUEUE_/DEQUEUE_, solidity's nonReentrant). Declining would have left z/OS's only native serialization construct unmeasured for the whole language. #2610's rejection of a cleanup rule on DISP=(...,DELETE/CATLG) does not carry over: a second-positional disposition rides along on essentially every DISP=, so that rule would have re-counted the whole operand. This shape is 48 of the corpus's 525 DISP= occurrences (~9%), across 15 of 186 files -- SHR (429) is the shared-access default every job asks for and NEW (48, including an omitted first positional) is an allocation, not contention over an existing resource. The residual overlap is real and accepted, which is the engine's existing posture where the meanings genuinely differ: jcl's own COND=((4,LT),EVEN) counts safety AND safety_bypasses, haskell's finally counts cleanup and safety. test_jcl_sync_locks_overlaps_io_by_design pins it so a later change re-makes the decision rather than drifting silently. Golden masters re-blessed: 15 differences per mode, all Thread Synchronization Locks on those same 15 jcl files, summing to 48. No other language moved and no topology ripple. Also corrects docs/language_status/jcl.md, whose §3 was missing dead_code and spec_exposure (added by #2732, never documented) and whose §6 strict-test count was stale at 65. Co-Authored-By: Claude Opus 5 (1M context) --- docs/language_status/jcl.md | 12 ++- .../language_standards/languages/jcl.py | 30 ++++++++ tests/extraction/languages/test_jcl_strict.py | 75 +++++++++++++++++++ tests/golden_master_audit.json | 34 ++++----- tests/golden_master_zero_dep_audit.json | 34 ++++----- 5 files changed, 148 insertions(+), 37 deletions(-) diff --git a/docs/language_status/jcl.md b/docs/language_status/jcl.md index 970602075..e0cb173be 100644 --- a/docs/language_status/jcl.md +++ b/docs/language_status/jcl.md @@ -34,6 +34,7 @@ **Resource Management** - `io`: Matches dataset definitions and I/O routing such as `DSN`, `DSNAME`, `SYSOUT`, `SYSPRINT`, `DISP=`. +- `sync_locks`: Matches `DISP=OLD` / `DISP=MOD` — the dispositions that request an **exclusive system ENQ** on a dataset, z/OS's native serialization idiom (`DISP=SHR` requests shared access and `DISP=NEW` allocates, so neither counts). Added by [#2733](https://github.com/squid-protocol/gitgalaxy/issues/2733). Every hit is also an `io` hit, since `io` counts the bare `DISP=` keyword; that overlap is accepted deliberately because the shape is narrow (48 hits in 15 of the corpus's 186 `.jcl`/`.prc`/`.bms` files, ~9% of its 525 `DISP=` occurrences; 429 of the remaining 477 are `DISP=SHR` and the other 48 allocate — `DISP=(NEW,…)`, or an omitted first positional that defaults to it) and the two meanings genuinely differ, the same way `COND=((4,LT),EVEN)` counts both `safety` and `safety_bypasses`. Contrast §4's `cleanup`, where the overlap would have covered essentially every disposition. **State Mutation** - `state_mutation`: Matches JCL symbolic variable assignments via `SET`. @@ -44,6 +45,8 @@ - `ownership`: Matches ownership/maintainer comments like `//* Author:` (counted on the comment stream since #2610 — previously it only worked by accident on the code stream, see §10). - `telemetry`: Matches `MSGLEVEL=` / `MSGCLASS=` (job-log verbosity and routing — JCL's observability dials). Added by #2610. - `planned_debt` / `fragile_debt`: The shared `GLOBAL_PLANNED_DEBT` / `GLOBAL_FRAGILE_DEBT` comment-anchored patterns (same wiring as cobol) — a `//* TODO ...` / `//* HACK ...` banner in a job deck now counts. Added by #2610; structurally dead before it because JCL's comment stream was always empty (§10). +- `dead_code`: Matches a JCL statement commented out by turning `//` into `//*` (`//*STEP1 EXEC PGM=IEFBR14`), distinguished from an ordinary prose banner that merely contains the keyword. Added by [#2732](https://github.com/squid-protocol/gitgalaxy/issues/2732). +- `spec_exposure`: Matches the generic traceability tag in a `//*` comment (`//* [SPEC-4412] ...`). Added by #2732. ## 4. What GitGalaxy explicitly does not track @@ -52,7 +55,8 @@ - `cleanup`: None — **a deliberate decision, not an oversight** (#2610): the honest JCL cleanup idiom is `DISP=(...,DELETE)`, but `DISP=` already feeds the `io` rule, so a cleanup rule would double-count every disposition. Recorded in the keyword-rosetta deviation ledger - (`jcl-2610-rebaseline-residual-morphology`) as intended morphology. + (`jcl-2610-rebaseline-residual-morphology`) as intended morphology. #2733 revisited the same + overlap for `sync_locks` and decided the other way — see §3 for why the two dispositions split. - `globals`: None — JCL has no scoped-vs-global variable distinction (`SET` symbolics are already `state_mutation`; a `JOBLIB`/`STEPLIB` rule was considered and rejected because those DD statements would inflate `io` and `dependency_links`). @@ -76,8 +80,10 @@ None currently. ([#2415](https://github.com/squid-protocol/gitgalaxy/issues/2415 ## 6. Test depth - **Extraction-gauntlet tests**: 42 cases in `tests/extraction/languages/test_jcl.py` -- **Strict-signature tests**: 65 cases in `tests/extraction/languages/test_jcl_strict.py` - (grew 51 → 65 with #2610's COND-partition semantics, JES3-guard, and ReDoS detonation cases) +- **Strict-signature tests**: 80 cases in `tests/extraction/languages/test_jcl_strict.py` + (51 → 65 with #2610's COND-partition semantics, JES3-guard and ReDoS detonation cases; + 65 → 74 with #2732's `dead_code`/`spec_exposure` rules; 74 → 80 with #2733's `sync_locks` + disposition partition, io-overlap pin and ReDoS case) ## 7. Relevant closed work diff --git a/gitgalaxy/standards/language_standards/languages/jcl.py b/gitgalaxy/standards/language_standards/languages/jcl.py index 735db4613..e7cc3be80 100644 --- a/gitgalaxy/standards/language_standards/languages/jcl.py +++ b/gitgalaxy/standards/language_standards/languages/jcl.py @@ -116,6 +116,36 @@ # both `\s+` gaps bounded to `[ \t]+` for the same cross-line reason. "state_mutation": re.compile(r"^[ \t]*//[A-Za-z0-9_#$@]*[ \t]+SET[ \t]+[A-Za-z0-9_#$@]+=", re.M | re.I), "concurrency": None, + # #2733: dataset disposition IS z/OS's serialization primitive. + # `DISP=OLD` and `DISP=MOD` request an exclusive system ENQ on the + # dataset; `DISP=SHR` requests shared access. In a batch shop that is + # the construct engineers reason about when two jobs contend for a + # resource -- a lock acquisition declared in the job deck -- which is + # what sync_locks measures through each language's own idiom elsewhere + # (cobol's `EXEC CICS ENQ`, abap's `ENQUEUE_`/`DEQUEUE_`, solidity's + # `nonReentrant`). + # Narrowed to OLD/MOD deliberately: SHR is the shared-access default + # every job asks for, and NEW is an allocation rather than contention + # over an already-existing resource -- neither declares a + # serialization decision. On the language-crucible corpus that is 48 + # hits across 15 of 186 files, ~9% of the 525 `DISP=` occurrences; of + # the remaining 477, 429 are `DISP=SHR` and 48 allocate (`DISP=(NEW,`, + # or an omitted first positional -- `DISP=(,PASS)` -- that defaults to + # it). + # The residual overlap with `io` (which counts the bare `DISP=` + # keyword) is accepted, not avoided. #2610 rejected a `cleanup` rule on + # `DISP=(...,DELETE/CATLG)` because a second-positional disposition + # rides along on essentially every `DISP=`, so that rule would have + # re-counted the whole operand; this shape is a small, semantically + # distinct subset instead. The engine already tolerates deliberate + # overlaps where the meanings genuinely differ -- jcl's own + # `COND=((4,LT),EVEN)` counts safety AND safety_bypasses, and haskell's + # `finally` counts cleanup and safety. + # Unanchored like the other operand rules (io/safety/telemetry): a DD + # statement's DISP= routinely sits on a `//` continuation line rather + # than the line carrying the ddname, the same real-corpus shape the + # args rule's #2482 note documents. + "sync_locks": re.compile(r"\bDISP=\(?(?:OLD|MOD)\b", re.I), "ui_framework": None, "closures": None, "globals": None, diff --git a/tests/extraction/languages/test_jcl_strict.py b/tests/extraction/languages/test_jcl_strict.py index f8cc37f10..cb8d94440 100644 --- a/tests/extraction/languages/test_jcl_strict.py +++ b/tests/extraction/languages/test_jcl_strict.py @@ -106,6 +106,11 @@ ("dead_code", "//*CREL005 JOB ,,CLASS=A,MSGCLASS=H,", "//* PROC statements are documented in the runbook"), ("dead_code", "//* SET COUNTER=1", "//* JOB scheduling notes live in the runbook"), ("dead_code", "//* INCLUDE MEMBER=OLDPROC", "//* INCLUDE the operations team on any change"), + # #2733: sync_locks = the exclusive-ENQ dispositions. DISP=SHR (shared + # access, the default request) and DISP=NEW (allocation) are excluded. + ("sync_locks", "//SYSLIN DD DISP=OLD,DSN=HLQ.SAMPLE.OBJ(SAM1)", "//STEPLIB DD DSN=SYS1.LINKLIB,DISP=SHR"), + ("sync_locks", "//DD1 DD DSN=HLQ.CUSTRPT,DISP=(MOD,DELETE,DELETE),", "//SYSUT2 DD DISP=(NEW,CATLG),DSN=HLQ.OUT"), + ("sync_locks", "//SYSLIN DD DSNAME=&&LOADSET,DISP=(OLD,DELETE)", "//S1 EXEC PGM=IEBGENER,PARM='OLDMODE'"), # #2732: spec_exposure = the generic traceability tag, `//*`-anchored ("spec_exposure", "//* [SPEC-4412] see the change request", "//* nothing traceable here"), ("spec_exposure", "//* raised under [audit] last quarter", "//* the behaviour is [specified] upstream"), @@ -363,6 +368,76 @@ def test_jcl_cond_bypass_redos_immunity(): assert_redos_immune(pattern, "//X EXEC PGM=Y,COND=(" + "A" * 100000, timeout_sec=3.0) +def test_jcl_sync_locks_only_the_exclusive_enq_dispositions(): + """ + #2733: DISP=OLD/MOD request an exclusive system ENQ on the dataset; DISP=SHR + and DISP=NEW do not declare contention over an existing resource and must + stay out of the lock signal. The rule is a deliberately narrow subset of the + `DISP=` operand `io` already counts (~9% of corpus occurrences), so the + exclusions are the substance of the design -- assert them directly rather + than trusting the positive cases alone. + """ + sync_locks = JCL_RULES["sync_locks"] + + for exclusive in ( + "//STEPLIB DD DSN=SYS1.LINKLIB,DISP=OLD", + "//SYSLIN DD DISP=(OLD,DELETE),DSN=&&LOADSET", + "//DD1 DD DSN=HLQ.CUSTRPT,DISP=(MOD,DELETE,DELETE),", + "//SYSUT1 DD DISP=(MOD,PASS),SPACE=(CYL,(1,1))", + ): + assert sync_locks.search(exclusive), f"missed an exclusive-ENQ disposition: {exclusive!r}" + + for shared_or_new in ( + "//STEPLIB DD DSN=SYS1.LINKLIB,DISP=SHR", + "//SYSUT2 DD DISP=(NEW,CATLG,DELETE),DSN=HLQ.OUT", + "//SYSUT3 DD DISP=(,PASS),UNIT=SYSDA", + ): + assert not sync_locks.search(shared_or_new), f"counted a non-exclusive disposition: {shared_or_new!r}" + + # The disposition keyword itself is required -- a bare OLD/MOD token + # elsewhere on the statement (a PARM value, a dataset name) is not a lock. + for not_a_disposition in ( + "//S1 EXEC PGM=IEBGENER,PARM='OLDMODE'", + "//SYSUT1 DD DSN=HLQ.OLD.BACKUP,DISP=SHR", + "//SYSUT1 DD DISP=OLDER", + "//SYSUT1 DD DISPOSITION=OLD", + ): + assert not sync_locks.search(not_a_disposition), f"false positive: {not_a_disposition!r}" + + # Operand-anchored, not line-anchored: DISP= routinely sits on a `//` + # continuation line rather than the line carrying the ddname (the #2482 + # shape), exactly as io/safety/telemetry already assume. + continuation = "//SYSUT1 DD DSN=HLQ.WORK,\n// DISP=(MOD,DELETE,DELETE),\n// UNIT=SYSDA" + assert sync_locks.search(continuation) + + +def test_jcl_sync_locks_overlaps_io_by_design(): + """ + #2733: every sync_locks hit is also an `io` hit, because `io` counts the + bare `DISP=` keyword. That overlap is the design decision the issue records + (accepted for a narrow OLD/MOD subset, unlike the broad `cleanup` rule + #2610 rejected), so pin it as intended behaviour -- if a later change makes + the two rules disjoint, that is a decision to re-make, not a silent drift. + """ + sync_locks = JCL_RULES["sync_locks"] + io = JCL_RULES["io"] + + exclusive = "//SYSLIN DD DISP=(OLD,DELETE),DSN=&&LOADSET" + assert sync_locks.search(exclusive) and io.search(exclusive) + + # ...but the converse does not hold: the overwhelming majority of DISP= + # occurrences (427 of 525 in the corpus) are DISP=SHR, io-only. + shared = "//STEPLIB DD DSN=SYS1.LINKLIB,DISP=SHR" + assert io.search(shared) and not sync_locks.search(shared) + + +def test_jcl_sync_locks_redos_immunity(): + """#2733: no nesting and no unbounded repetition, but hold the line on it.""" + pattern = JCL_RULES["sync_locks"] + assert_redos_immune(pattern, "//X DD " + "DISP=(" * 20000, timeout_sec=3.0) + assert_redos_immune(pattern, "//X DD DISP=(" + "OLD" * 50000, timeout_sec=3.0) + + def test_jcl_dead_code_counts_through_the_real_comment_stream(): """ #2732: end-to-end proof that jcl's two new comment-stream rules actually diff --git a/tests/golden_master_audit.json b/tests/golden_master_audit.json index a43e9e0ae..e0bfbb76a 100644 --- a/tests/golden_master_audit.json +++ b/tests/golden_master_audit.json @@ -12,8 +12,8 @@ }, "Target Root Name": "data", "Absolute Project Path": "/home/joe/nyx_projects/language-crucible/data", - "Analysis ISO Timestamp": "2026-09-05T02:29:59.884225+00:00", - "Total Scan Duration": "50.71 seconds" + "Analysis ISO Timestamp": "2026-09-05T12:35:39.127619+00:00", + "Total Scan Duration": "50.2 seconds" }, "Source Control Footprint (Immutable Anchor)": { "Active Branch": "HEAD", @@ -814662,7 +814662,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -828254,7 +828254,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 3, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -829595,7 +829595,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -858041,7 +858041,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859455,7 +859455,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859638,7 +859638,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859834,7 +859834,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -871807,7 +871807,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 7, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -871993,7 +871993,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 5, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872167,7 +872167,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872677,7 +872677,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 7, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872863,7 +872863,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873086,7 +873086,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873299,7 +873299,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873519,7 +873519,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 3, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, diff --git a/tests/golden_master_zero_dep_audit.json b/tests/golden_master_zero_dep_audit.json index b3ef95521..328cd7203 100644 --- a/tests/golden_master_zero_dep_audit.json +++ b/tests/golden_master_zero_dep_audit.json @@ -12,8 +12,8 @@ }, "Target Root Name": "data", "Absolute Project Path": "/home/joe/nyx_projects/language-crucible/data", - "Analysis ISO Timestamp": "2026-09-05T02:30:54.498732+00:00", - "Total Scan Duration": "44.43 seconds" + "Analysis ISO Timestamp": "2026-09-05T12:36:33.704016+00:00", + "Total Scan Duration": "44.54 seconds" }, "Source Control Footprint (Immutable Anchor)": { "Active Branch": "HEAD", @@ -814662,7 +814662,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -828254,7 +828254,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 3, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -829595,7 +829595,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -858041,7 +858041,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859455,7 +859455,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859638,7 +859638,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -859834,7 +859834,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 2, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -871807,7 +871807,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 7, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -871993,7 +871993,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 5, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872167,7 +872167,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872677,7 +872677,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 7, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -872863,7 +872863,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873086,7 +873086,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 4, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873299,7 +873299,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 1, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0, @@ -873519,7 +873519,7 @@ "Fatal Aborts & Exceptions": 0, "Thread Sleeps & Blocking Waits": 0, "Bitwise Operations": 0, - "Thread Synchronization Locks": 0, + "Thread Synchronization Locks": 3, "Immutable Data Declarations": 0, "Resource Deallocation & Cleanup": 0, "Private / Encapsulated Scopes": 0,