Skip to content

Commit 5afff3c

Browse files
authored
Darwin: convenience API Part 2 (Issue 16691) (#21757)
* Issue 16691 - Darwin: convenience API Part 2 * Restyled change
1 parent 2a894d5 commit 5afff3c

18 files changed

+10443
-10737
lines changed

.restyled.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ exclude:
7373
- "examples/chef/sample_app_util/test_files/*.yaml"
7474
- "examples/chef/zzz_generated/**/*"
7575
- "src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm" # https://github.com/project-chip/connectedhomeip/issues/20236
76-
- "src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm"
7776

7877

7978
changed_paths:

src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.h

+26-6
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,37 @@ NS_ASSUME_NONNULL_BEGIN
2323

2424
typedef void (^MTRAsyncCallbackReadyHandler)(id context, NSUInteger retryCount);
2525

26-
// How to queue a new work item:
26+
// MTRAsyncCallbackQueue high level description
27+
// The MTRAsyncCallbackQueue was made to call one readyHandler
28+
// block at a time asynchronously, and the readyHandler is
29+
// expected to start/schedule a task. When the task finishes
30+
// asynchronously in the future (at any time, from any queue
31+
// or thread), it is expected to ask the workItem object to
32+
// either endWork or retryWork.
33+
34+
// Sequence of steps when queuing a work item:
2735
// - Create MTRAsyncCallbackQueueWorkItem object
2836
// - Create ready handler block (MTRAsyncCallbackReadyHandler)
29-
// - block is called when it's the work item's turn to do work
30-
// - its body is to do work with the device
37+
// - block is called when it's the WorkItem's turn to do work
38+
// - its body is to perform a task that is expected to end asynchronously in the future
3139
// - at the end of work, call on the work item object:
3240
// - endWork for success or failure
3341
// - retryWork for temporary failures
34-
// - Set the work handler block to the Item object
35-
// - Call enqueueWorkItem on the MTRDevice's work queue property
42+
// - Set the readyHandler block on the WorkItem object
43+
// - Call enqueueWorkItem on a MTRAsyncCallbackQueue
3644

3745
// A serial one-at-a-time queue for performing work items
3846
@interface MTRAsyncCallbackWorkQueue : NSObject
3947
- (instancetype)init NS_UNAVAILABLE;
4048
+ (instancetype)new NS_UNAVAILABLE;
4149

50+
// The context object is only held and passed back as a reference and is opaque to the work queue
51+
- (instancetype)initWithContext:(id _Nullable)context queue:(dispatch_queue_t)queue;
52+
53+
// Called by the work queue owner to clean up and cancel work items
54+
- (void)invalidate;
55+
56+
// Work items may be enqueued from any queue or thread
4257
- (void)enqueueWorkItem:(MTRAsyncCallbackQueueWorkItem *)item;
4358

4459
// TODO: Add a "set concurrency width" method to allow for more than 1 work item at a time
@@ -49,12 +64,17 @@ typedef void (^MTRAsyncCallbackReadyHandler)(id context, NSUInteger retryCount);
4964
- (instancetype)init NS_UNAVAILABLE;
5065
+ (instancetype)new NS_UNAVAILABLE;
5166

67+
// Both readyHandler and cancelHander will be called on the queue given to initWithQueue
5268
- (instancetype)initWithQueue:(dispatch_queue_t)queue;
5369
@property (nonatomic, strong) MTRAsyncCallbackReadyHandler readyHandler;
5470
@property (nonatomic, strong) dispatch_block_t cancelHandler;
5571

56-
// Called by Cluster object's after async work is done
72+
// Called by the creater of the work item when async work is done and should
73+
// be removed from the queue. The work queue will run the next work item.
5774
- (void)endWork;
75+
76+
// Called by the creater of the work item when async work should be retried.
77+
// The work queue will call this workItem's readyHandler again.
5878
- (void)retryWork;
5979
@end
6080

src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm

+18-30
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
#import <dispatch/dispatch.h>
1919
#import <os/lock.h>
2020

21-
#import "MTRAsyncCallbackWorkQueue_Internal.h"
21+
#import "MTRAsyncCallbackWorkQueue.h"
2222
#import "MTRLogging.h"
2323

2424
#pragma mark - Class extensions
2525

2626
@interface MTRAsyncCallbackWorkQueue ()
27+
// The lock protects the internal state of the work queue so that these may be called from any queue or thread:
28+
// -enqueueWorkItem:
29+
// -invalidate
30+
// -endWork:
31+
// -retryWork:
2732
@property (nonatomic, readonly) os_unfair_lock lock;
2833
@property (nonatomic, strong, readonly) id context;
2934
@property (nonatomic, strong, readonly) dispatch_queue_t queue;
@@ -81,7 +86,8 @@ - (void)invalidate
8186
[invalidateItems removeAllObjects];
8287
}
8388

84-
- (void)endWork:(MTRAsyncCallbackQueueWorkItem *)workItem
89+
// called after executing a work item
90+
- (void)_postProcessWorkItem:(MTRAsyncCallbackQueueWorkItem *)workItem retry:(BOOL)retry
8591
{
8692
os_unfair_lock_lock(&_lock);
8793
// sanity check if running
@@ -102,41 +108,25 @@ - (void)endWork:(MTRAsyncCallbackQueueWorkItem *)workItem
102108
return;
103109
}
104110

105-
// since work is done, remove from queue and call ready on the next item
106-
[self.items removeObjectAtIndex:0];
111+
// if work item is done (no need to retry), remove from queue and call ready on the next item
112+
if (!retry) {
113+
[self.items removeObjectAtIndex:0];
114+
}
107115

108116
// when "concurrency width" is implemented this will be decremented instead
109117
self.runningWorkItemCount = 0;
110118
[self _callNextReadyWorkItem];
111119
os_unfair_lock_unlock(&_lock);
112120
}
113121

114-
- (void)retryWork:(MTRAsyncCallbackQueueWorkItem *)workItem
122+
- (void)endWork:(MTRAsyncCallbackQueueWorkItem *)workItem
115123
{
116-
// reset BOOL and call again
117-
os_unfair_lock_lock(&_lock);
118-
// sanity check if running
119-
if (!self.runningWorkItemCount) {
120-
// something is wrong with state - nothing is currently running
121-
os_unfair_lock_unlock(&_lock);
122-
MTR_LOG_ERROR("retryWork: no work is running on work queue");
123-
return;
124-
}
125-
126-
// sanity check the same work item is running
127-
// when "concurrency width" is implemented need to check first N items
128-
MTRAsyncCallbackQueueWorkItem * firstWorkItem = self.items.firstObject;
129-
if (firstWorkItem != workItem) {
130-
// something is wrong with this work item - should not be currently running
131-
os_unfair_lock_unlock(&_lock);
132-
MTR_LOG_ERROR("retryWork: work item is not first on work queue");
133-
return;
134-
}
124+
[self _postProcessWorkItem:workItem retry:NO];
125+
}
135126

136-
// when "concurrency width" is implemented this will be decremented instead
137-
self.runningWorkItemCount = 0;
138-
[self _callNextReadyWorkItem];
139-
os_unfair_lock_unlock(&_lock);
127+
- (void)retryWork:(MTRAsyncCallbackQueueWorkItem *)workItem
128+
{
129+
[self _postProcessWorkItem:workItem retry:YES];
140130
}
141131

142132
// assume lock is held while calling this
@@ -166,13 +156,11 @@ - (instancetype)initWithQueue:(dispatch_queue_t)queue
166156
return self;
167157
}
168158

169-
// Called by Cluster object's after async work is done
170159
- (void)endWork
171160
{
172161
[self.workQueue endWork:self];
173162
}
174163

175-
// Called by Cluster object's after async work is done
176164
- (void)retryWork
177165
{
178166
[self.workQueue retryWork:self];

src/darwin/Framework/CHIP/MTRBaseDevice.h

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
3030
*
3131
* MTRAttributePathKey : MTRAttributePath object. Included for attribute value.
3232
* MTRCommandPathKey : MTRCommandPath object. Included for command response.
33+
* MTREventPathKey : MTREventPath object. Included for event value.
3334
* MTRErrorKey : NSError object. Included to indicate an error.
3435
* MTRDataKey: Data-value NSDictionary object.
3536
* Included when there is data and when there is no error.
@@ -67,11 +68,18 @@ NS_ASSUME_NONNULL_BEGIN
6768
* MTRDataKey : Data-value NSDictionary object.
6869
*/
6970
typedef void (^MTRDeviceResponseHandler)(NSArray<NSDictionary<NSString *, id> *> * _Nullable values, NSError * _Nullable error);
71+
72+
/**
73+
* Handler for -subscribeWithQueue: attribute and event reports
74+
*
75+
* @param values This array contains MTRAttributeReport objects for attribute reports, and MTREventReport objects for event reports
76+
*/
7077
typedef void (^MTRDeviceReportHandler)(NSArray * values);
7178
typedef void (^MTRDeviceErrorHandler)(NSError * error);
7279

7380
extern NSString * const MTRAttributePathKey;
7481
extern NSString * const MTRCommandPathKey;
82+
extern NSString * const MTREventPathKey;
7583
extern NSString * const MTRDataKey;
7684
extern NSString * const MTRErrorKey;
7785
extern NSString * const MTRTypeKey;

src/darwin/Framework/CHIP/MTRBaseDevice.mm

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050

5151
NSString * const MTRAttributePathKey = @"attributePath";
5252
NSString * const MTRCommandPathKey = @"commandPath";
53+
NSString * const MTREventPathKey = @"eventPath";
5354
NSString * const MTRDataKey = @"data";
5455
NSString * const MTRErrorKey = @"error";
5556
NSString * const MTRTypeKey = @"type";

src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ NS_ASSUME_NONNULL_BEGIN
6868
- (instancetype)initWithPath:(const chip::app::ConcreteDataAttributePath &)path;
6969
@end
7070

71+
@interface MTREventPath ()
72+
- (instancetype)initWithPath:(const chip::app::ConcreteEventPath &)path;
73+
@end
74+
7175
@interface MTRCommandPath ()
7276
- (instancetype)initWithPath:(const chip::app::ConcreteCommandPath &)path;
7377
@end

0 commit comments

Comments
 (0)