@@ -275,7 +275,10 @@ where
275
275
276
276
self . send_goal_response ( request_id, true ) ?;
277
277
278
- self . goal_handles . lock ( ) . unwrap ( ) . insert ( uuid, Arc :: clone ( & goal_handle) ) ;
278
+ self . goal_handles
279
+ . lock ( )
280
+ . unwrap ( )
281
+ . insert ( uuid, Arc :: clone ( & goal_handle) ) ;
279
282
280
283
if response == GoalResponse :: AcceptAndExecute {
281
284
goal_handle. execute ( ) ?;
@@ -289,8 +292,157 @@ where
289
292
Ok ( ( ) )
290
293
}
291
294
295
+ fn take_cancel_request ( & self ) -> Result < ( action_msgs__srv__CancelGoal_Request , rmw_request_id_t ) , RclrsError > {
296
+ let mut request_id = rmw_request_id_t {
297
+ writer_guid : [ 0 ; 16 ] ,
298
+ sequence_number : 0 ,
299
+ } ;
300
+ // SAFETY: No preconditions
301
+ let mut request_rmw = unsafe { rcl_action_get_zero_initialized_cancel_request ( ) } ;
302
+ let handle = & * self . handle . lock ( ) ;
303
+ unsafe {
304
+ // SAFETY: The action server is locked by the handle. The request_id is a
305
+ // zero-initialized rmw_request_id_t, and the request_rmw is a zero-initialized
306
+ // action_msgs__srv__CancelGoal_Request.
307
+ rcl_action_take_cancel_request (
308
+ handle,
309
+ & mut request_id,
310
+ & mut request_rmw as * mut _ as * mut _ ,
311
+ )
312
+ }
313
+ . ok ( ) ?;
314
+
315
+ Ok ( ( request_rmw, request_id) )
316
+ }
317
+
318
+ fn send_cancel_response (
319
+ & self ,
320
+ mut request_id : rmw_request_id_t ,
321
+ response_rmw : & mut action_msgs__srv__CancelGoal_Response ,
322
+ ) -> Result < ( ) , RclrsError > {
323
+ let handle = & * self . handle . lock ( ) ;
324
+ let result = unsafe {
325
+ // SAFETY: The action server handle is locked and so synchronized with other functions.
326
+ // The request_id and response are both uniquely owned or borrowed, and so neither will
327
+ // mutate during this function call.
328
+ rcl_action_send_cancel_response (
329
+ handle,
330
+ & mut request_id,
331
+ response_rmw as * mut _ as * mut _ ,
332
+ )
333
+ }
334
+ . ok ( ) ;
335
+ match result {
336
+ Ok ( ( ) ) => Ok ( ( ) ) ,
337
+ Err ( RclrsError :: RclError {
338
+ code : RclReturnCode :: Timeout ,
339
+ ..
340
+ } ) => {
341
+ // TODO(nwn): Log an error and continue.
342
+ // (See https://github.com/ros2/rclcpp/pull/2215 for reasoning.)
343
+ Ok ( ( ) )
344
+ }
345
+ _ => result,
346
+ }
347
+ }
348
+
292
349
fn execute_cancel_request ( & self ) -> Result < ( ) , RclrsError > {
293
- todo ! ( )
350
+ let ( request, request_id) = match self . take_cancel_request ( ) {
351
+ Ok ( res) => res,
352
+ Err ( RclrsError :: RclError {
353
+ code : RclReturnCode :: ServiceTakeFailed ,
354
+ ..
355
+ } ) => {
356
+ // Spurious wakeup – this may happen even when a waitset indicated that this
357
+ // action was ready, so it shouldn't be an error.
358
+ return Ok ( ( ) ) ;
359
+ }
360
+ Err ( err) => return Err ( err) ,
361
+ } ;
362
+
363
+ let mut response_rmw = {
364
+ // SAFETY: No preconditions
365
+ let mut response_rmw = unsafe { rcl_action_get_zero_initialized_cancel_response ( ) } ;
366
+ unsafe {
367
+ // SAFETY: The action server is locked by the handle. The request was initialized
368
+ // by rcl_action, and the response is a zero-initialized
369
+ // rcl_action_cancel_response_t.
370
+ rcl_action_process_cancel_request (
371
+ & * self . handle . lock ( ) ,
372
+ & request,
373
+ & mut response_rmw as * mut _ ,
374
+ )
375
+ }
376
+ . ok ( ) ?;
377
+
378
+ DropGuard :: new ( response_rmw, |mut response_rmw| unsafe {
379
+ // SAFETY: The response was initialized by rcl_action_process_cancel_request().
380
+ // Later modifications only truncate the size of the array and shift elements,
381
+ // without modifying the data pointer or capacity.
382
+ rcl_action_cancel_response_fini ( & mut response_rmw) ;
383
+ } )
384
+ } ;
385
+
386
+ let num_candidates = response_rmw. msg . goals_canceling . size ;
387
+ let mut num_accepted = 0 ;
388
+ for idx in 0 ..response_rmw. msg . goals_canceling . size {
389
+ let goal_info = unsafe {
390
+ // SAFETY: The array pointed to by response_rmw.msg.goals_canceling.data is
391
+ // guaranteed to contain at least response_rmw.msg.goals_canceling.size members.
392
+ & * response_rmw. msg . goals_canceling . data . add ( idx)
393
+ } ;
394
+ let goal_uuid = GoalUuid ( goal_info. goal_id . uuid ) ;
395
+
396
+ let response = {
397
+ if let Some ( goal_handle) = self . goal_handles . lock ( ) . unwrap ( ) . get ( & goal_uuid) {
398
+ let response: CancelResponse = todo ! ( "Call self.cancel_callback(goal_handle)" ) ;
399
+ if response == CancelResponse :: Accept {
400
+ // Still reject the request if the goal is no longer cancellable.
401
+ if goal_handle. cancel ( ) . is_ok ( ) {
402
+ CancelResponse :: Accept
403
+ } else {
404
+ CancelResponse :: Reject
405
+ }
406
+ } else {
407
+ CancelResponse :: Reject
408
+ }
409
+ } else {
410
+ CancelResponse :: Reject
411
+ }
412
+ } ;
413
+
414
+ if response == CancelResponse :: Accept {
415
+ // Shift the accepted entry back to the first rejected slot, if necessary.
416
+ if num_accepted < idx {
417
+ let goal_info_slot = unsafe {
418
+ // SAFETY: The array pointed to by response_rmw.msg.goals_canceling.data is
419
+ // guaranteed to contain at least response_rmw.msg.goals_canceling.size
420
+ // members. Since `num_accepted` is strictly less than `idx`, it is a
421
+ // distinct element of the array, so there is no mutable aliasing.
422
+ & mut * response_rmw. msg . goals_canceling . data . add ( num_accepted)
423
+ } ;
424
+ }
425
+ num_accepted += 1 ;
426
+ }
427
+ }
428
+ response_rmw. msg . goals_canceling . size = num_accepted;
429
+
430
+ // If the user rejects all individual cancel requests, consider the entire request as
431
+ // having been rejected.
432
+ if num_accepted == 0 && num_candidates > 0 {
433
+ // TODO(nwn): Include action_msgs__srv__CancelGoal_Response__ERROR_REJECTED in the rcl
434
+ // bindings.
435
+ response_rmw. msg . return_code = 1 ;
436
+ }
437
+
438
+ // If any goal states changed, publish a status update.
439
+ if num_accepted > 0 {
440
+ self . publish_status ( ) ?;
441
+ }
442
+
443
+ self . send_cancel_response ( request_id, & mut response_rmw. msg ) ?;
444
+
445
+ Ok ( ( ) )
294
446
}
295
447
296
448
fn execute_result_request ( & self ) -> Result < ( ) , RclrsError > {
@@ -319,7 +471,7 @@ where
319
471
let uuid = GoalUuid ( expired_goal. goal_id . uuid ) ;
320
472
self . goal_handles . lock ( ) . unwrap ( ) . remove ( & uuid) ;
321
473
} else {
322
- break
474
+ break ;
323
475
}
324
476
}
325
477
0 commit comments