20
20
#import " MTRServerAttribute_Internal.h"
21
21
#import " MTRServerCluster_Internal.h"
22
22
#import " MTRServerEndpoint_Internal.h"
23
+ #import " MTRUnfairLock.h"
24
+ #import " NSDataSpanConversion.h"
25
+
23
26
#import < Matter/MTRClusterConstants.h>
24
27
#import < Matter/MTRServerCluster.h>
25
28
26
- #import " NSDataSpanConversion.h"
27
-
28
29
#include < app/AttributeAccessInterface.h>
29
30
#include < app/clusters/descriptor/descriptor.h>
30
31
#include < app/data-model/PreEncodedValue.h>
@@ -71,11 +72,28 @@ @implementation MTRServerCluster {
71
72
std::unique_ptr<MTRServerAttributeAccessInterface> _attributeAccessInterface;
72
73
// We can't use something like std::unique_ptr<EmberAfAttributeMetadata[]>
73
74
// because EmberAfAttributeMetadata does not have a default constructor, so
74
- // we can't alloc and then initializer later.
75
+ // we can't alloc and then initialize later.
75
76
std::vector<EmberAfAttributeMetadata> _matterAttributeMetadata;
76
77
77
78
std::unique_ptr<CommandId[]> _matterAcceptedCommandList;
78
79
std::unique_ptr<CommandId[]> _matterGeneratedCommandList;
80
+
81
+ NSSet <MTRAccessGrant *> * _matterAccessGrants;
82
+
83
+ chip::EndpointId _parentEndpoint;
84
+
85
+ // _acceptedCommands and _generatedCommands are touched directly by our API
86
+ // consumer.
87
+ NSArray <NSNumber *> * _acceptedCommands;
88
+ NSArray <NSNumber *> * _generatedCommands;
89
+
90
+ /* *
91
+ * _lock always protects access to: _accessGrants, _attributes,
92
+ * _deviceController, _attributeAccessInterface, _matterAttributeMetadata,
93
+ * _matterAccessGrants, _parentEndpoint, _acceptedCommands,
94
+ * _generatedCommands, _matterAcceptedCommandList, _matterGeneratedCommandList.
95
+ */
96
+ os_unfair_lock _lock;
79
97
}
80
98
81
99
- (nullable instancetype )initWithClusterID : (NSNumber *)clusterID revision : (NSNumber *)revision
@@ -117,6 +135,7 @@ - (instancetype)initInternalWithClusterID:(NSNumber *)clusterID revision:(NSNumb
117
135
return nil ;
118
136
}
119
137
138
+ _lock = OS_UNFAIR_LOCK_INIT;
120
139
_clusterID = [clusterID copy ];
121
140
_clusterRevision = [revision copy ];
122
141
_accessGrants = [[NSMutableSet alloc ] init ];
@@ -141,6 +160,8 @@ - (instancetype)initInternalWithClusterID:(NSNumber *)clusterID revision:(NSNumb
141
160
142
161
- (void )updateMatterAccessGrants
143
162
{
163
+ os_unfair_lock_assert_owner (&_lock);
164
+
144
165
MTRDeviceController * deviceController = _deviceController;
145
166
if (deviceController == nil ) {
146
167
// _matterAccessGrants will be updated when we get bound to a controller.
@@ -149,27 +170,41 @@ - (void)updateMatterAccessGrants
149
170
150
171
NSSet * grants = [_accessGrants copy ];
151
172
[deviceController asyncDispatchToMatterQueue: ^{
173
+ std::lock_guard lock (self->_lock );
152
174
self->_matterAccessGrants = grants;
153
175
}
154
176
errorHandler: nil ];
155
177
}
156
178
157
179
- (void )addAccessGrant : (MTRAccessGrant *)accessGrant
158
180
{
181
+ std::lock_guard lock (self->_lock );
182
+
159
183
[_accessGrants addObject: accessGrant];
160
184
161
185
[self updateMatterAccessGrants ];
162
186
}
163
187
164
188
- (void )removeAccessGrant : (MTRAccessGrant *)accessGrant ;
165
189
{
190
+ std::lock_guard lock (self->_lock );
191
+
166
192
[_accessGrants removeObject: accessGrant];
167
193
168
194
[self updateMatterAccessGrants ];
169
195
}
170
196
197
+ - (NSArray <MTRAccessGrant *> *)matterAccessGrants
198
+ {
199
+ std::lock_guard lock (self->_lock );
200
+
201
+ return [_matterAccessGrants allObjects ];
202
+ }
203
+
171
204
- (BOOL )addAttribute : (MTRServerAttribute *)attribute
172
205
{
206
+ std::lock_guard lock (self->_lock );
207
+
173
208
MTRDeviceController * deviceController = _deviceController;
174
209
if (deviceController != nil ) {
175
210
MTR_LOG_ERROR (" Cannot add attribute on cluster %llx which is already in use" , _clusterID.unsignedLongLongValue );
@@ -213,6 +248,8 @@ - (BOOL)addAttribute:(MTRServerAttribute *)attribute
213
248
214
249
- (BOOL )associateWithController : (nullable MTRDeviceController *)controller
215
250
{
251
+ std::lock_guard lock (self->_lock );
252
+
216
253
MTRDeviceController * existingController = _deviceController;
217
254
if (existingController != nil ) {
218
255
#if MTR_PER_CONTROLLER_STORAGE_ENABLED
@@ -313,14 +350,16 @@ - (BOOL)associateWithController:(nullable MTRDeviceController *)controller
313
350
314
351
_deviceController = controller;
315
352
316
- MTR_LOG_DEFAULT (" Associated %@, attribute count %llu, with controller" , self,
353
+ MTR_LOG_DEFAULT (" Associated %@, attribute count %llu, with controller" , [ self _descriptionWhileLocked ] ,
317
354
static_cast <unsigned long long >(attributeCount));
318
355
319
356
return YES ;
320
357
}
321
358
322
359
- (void )invalidate
323
360
{
361
+ std::lock_guard lock (_lock);
362
+
324
363
// Undo any work associateWithController did.
325
364
for (MTRServerAttribute * attr in _attributes) {
326
365
[attr invalidate ];
@@ -342,6 +381,8 @@ - (void)registerMatterCluster
342
381
{
343
382
assertChipStackLockedByCurrentThread ();
344
383
384
+ std::lock_guard lock (_lock);
385
+
345
386
if (!registerAttributeAccessOverride (_attributeAccessInterface.get ())) {
346
387
// This should only happen if we somehow managed to register an
347
388
// AttributeAccessInterface for the same (endpoint, cluster) pair.
@@ -354,45 +395,93 @@ - (void)unregisterMatterCluster
354
395
{
355
396
assertChipStackLockedByCurrentThread ();
356
397
398
+ std::lock_guard lock (_lock);
399
+
357
400
if (_attributeAccessInterface != nullptr ) {
358
401
unregisterAttributeAccessOverride (_attributeAccessInterface.get ());
359
402
}
360
403
}
361
404
362
405
- (NSArray <MTRAccessGrant *> *)accessGrants
363
406
{
407
+ std::lock_guard lock (_lock);
408
+
364
409
return [_accessGrants allObjects ];
365
410
}
366
411
367
412
- (NSArray <MTRServerAttribute *> *)attributes
368
413
{
414
+ std::lock_guard lock (_lock);
415
+
369
416
return [_attributes copy ];
370
417
}
371
418
372
- - (void ) setParentEndpoint : ( EndpointId)endpoint
419
+ - (BOOL ) addToEndpoint : (chip:: EndpointId)endpoint
373
420
{
421
+ std::lock_guard lock (_lock);
422
+
423
+ if (_parentEndpoint != kInvalidEndpointId ) {
424
+ MTR_LOG_ERROR (" Cannot add cluster " ChipLogFormatMEI " to endpoint %" PRIu32 " ; already added to endpoint %" PRIu32,
425
+ ChipLogValueMEI (_clusterID.unsignedLongLongValue ), endpoint, _parentEndpoint);
426
+ return NO ;
427
+ }
428
+
374
429
_parentEndpoint = endpoint;
375
430
// Update it on all the attributes, in case the attributes were added to us
376
431
// before we were added to the endpoint.
377
432
for (MTRServerAttribute * attr in _attributes) {
378
433
[attr updateParentCluster: ConcreteClusterPath (endpoint, static_cast <ClusterId>(_clusterID.unsignedLongLongValue))];
379
434
}
435
+ return YES ;
436
+ }
437
+
438
+ - (chip::EndpointId)parentEndpoint
439
+ {
440
+ std::lock_guard lock (_lock);
441
+ return _parentEndpoint;
380
442
}
381
443
382
444
- (Span<const EmberAfAttributeMetadata>)matterAttributeMetadata
383
445
{
384
446
// This is always called after our _matterAttributeMetadata has been set up
385
447
// by associateWithController.
448
+ std::lock_guard lock (_lock);
386
449
return Span<const EmberAfAttributeMetadata>(_matterAttributeMetadata.data (), _matterAttributeMetadata.size ());
387
450
}
388
451
452
+ - (void )setAcceptedCommands : (NSArray <NSNumber *> *)acceptedCommands
453
+ {
454
+ std::lock_guard lock (_lock);
455
+ _acceptedCommands = [acceptedCommands copy ];
456
+ }
457
+
458
+ - (NSArray <NSNumber *> *)acceptedCommands
459
+ {
460
+ std::lock_guard lock (_lock);
461
+ return [_acceptedCommands copy ];
462
+ }
463
+
464
+ - (void )setGeneratedCommands : (NSArray <NSNumber *> *)generatedCommands
465
+ {
466
+ std::lock_guard lock (_lock);
467
+ _generatedCommands = [generatedCommands copy ];
468
+ }
469
+
470
+ - (NSArray <NSNumber *> *)generatedCommands
471
+ {
472
+ std::lock_guard lock (_lock);
473
+ return [_generatedCommands copy ];
474
+ }
475
+
389
476
- (CommandId *)matterAcceptedCommands
390
477
{
478
+ std::lock_guard lock (_lock);
391
479
return _matterAcceptedCommandList.get ();
392
480
}
393
481
394
482
- (CommandId *)matterGeneratedCommands
395
483
{
484
+ std::lock_guard lock (_lock);
396
485
return _matterGeneratedCommandList.get ();
397
486
}
398
487
@@ -413,6 +502,13 @@ - (CommandId *)matterGeneratedCommands
413
502
414
503
- (NSString *)description
415
504
{
505
+ std::lock_guard lock (_lock);
506
+ return [self _descriptionWhileLocked ];
507
+ }
508
+
509
+ - (NSString *)_descriptionWhileLocked
510
+ {
511
+ os_unfair_lock_assert_owner (&_lock);
416
512
return [NSString stringWithFormat: @" <MTRServerCluster endpoint %u , id " ChipLogFormatMEI " >" ,
417
513
_parentEndpoint, ChipLogValueMEI (_clusterID.unsignedLongLongValue)];
418
514
}
0 commit comments