@@ -44,6 +44,7 @@ test() ->
4444 ok = test_timeout_call (),
4545 ok = test_timeout_cast (),
4646 ok = test_timeout_info (),
47+ ok = test_timeout_tuple_return (),
4748 ok = test_register (),
4849 ok = test_call_unregistered (),
4950 ok = test_cast_unregistered (),
@@ -316,6 +317,73 @@ test_timeout_info_repeats(Pid, Sleep) ->
316317 test_timeout_info_repeats (Pid , 2 * Sleep )
317318 end .
318319
320+ test_timeout_tuple_return () ->
321+ case get_otp_version () of
322+ Version when Version =:= atomvm orelse (is_integer (Version ) andalso Version >= 28 ) ->
323+ Self = self (),
324+ % % test timeout tuple in init
325+ {ok , Pid0 } = gen_server :start (? MODULE , {timeout , Self }, []),
326+ ok =
327+ receive
328+ {reply_from_timeout , init } ->
329+ ok
330+ after 1000 ->
331+ {error , no_timeout_reply_after_init }
332+ end ,
333+ gen_server :stop (Pid0 ),
334+
335+ % % test timeout tuple in continue, and proceed through callback tests
336+ {ok , Pid1 } = gen_server :start (? MODULE , {continue_timeout , Self }, []),
337+ ok =
338+ receive
339+ {reply_from_timeout , continue } ->
340+ ok
341+ after 1000 ->
342+ {error , no_timeout_reply_after_continue }
343+ end ,
344+
345+ % % Test handle_call
346+ {ok , Ref } = gen_server :call (Pid1 , {req_timeout_reply , Self }),
347+ ok =
348+ receive
349+ {reply_from_timeout , Ref } ->
350+ ok
351+ after 2000 ->
352+ {error , no_timeout_reply_after_call }
353+ end ,
354+
355+ % % Test handle_cast
356+ gen_server :cast (Pid1 , {req_timeout_reply , Self }),
357+ ok =
358+ receive
359+ {reply_from_timeout , cast } ->
360+ ok
361+ after 2000 ->
362+ {error , no_timeout_reply_after_cast }
363+ end ,
364+
365+ % % Test handle_info
366+ gen_server :cast (Pid1 , {request_info_timeout , Self }),
367+ ok =
368+ receive
369+ {reply_from_timeout , info } ->
370+ ok
371+ after 2000 ->
372+ {error , no_info_timeout_reply }
373+ end ,
374+ gen_server :stop (Pid1 ),
375+
376+ {ok , Pid2 } = gen_server :start (? MODULE , [], []),
377+ 0 = gen_server :call (Pid2 , get_num_timeouts ),
378+ ok = gen_server :cast (Pid2 , {tuple_timeout , 10 }),
379+ timer :sleep (100 ),
380+ 10 = gen_server :call (Pid2 , get_num_timeouts ),
381+
382+ gen_server :stop (Pid2 );
383+ _ ->
384+ ok
385+ end .
386+
319387test_register () ->
320388 {ok , Pid } = gen_server :start ({local , ? MODULE }, ? MODULE , [], []),
321389 Pid = whereis (? MODULE ),
@@ -436,6 +504,10 @@ init({continue, Pid}) ->
436504 io :format (" init(continue) -> ~p~n " , [Pid ]),
437505 self () ! {after_continue , Pid },
438506 {ok , [], {continue , {message , Pid }}};
507+ init ({timeout , Pid }) ->
508+ {ok , [], {timeout , 1 , {timeout_reply , Pid , init }}};
509+ init ({continue_timeout , Pid }) ->
510+ {ok , [], {continue , {timeout_reply , Pid }}};
439511init (_ ) ->
440512 {ok , # state {}}.
441513
@@ -451,7 +523,9 @@ handle_continue({message, Pid}, State) ->
451523handle_continue ({message , Pid , From }, State ) ->
452524 Pid ! {self (), continue },
453525 gen_server :reply (From , ok ),
454- {noreply , State }.
526+ {noreply , State };
527+ handle_continue ({timeout_reply , Pid }, State ) ->
528+ {noreply , State , {timeout , 1 , {timeout_reply , Pid , continue }}}.
455529
456530handle_call (ping , _From , State ) ->
457531 {reply , pong , State };
@@ -493,7 +567,10 @@ handle_call(crash_me, _From, State) ->
493567 exit (crash_me ),
494568 {reply , noop , State };
495569handle_call (crash_in_terminate , _From , State ) ->
496- {reply , ok , State # state {crash_in_terminate = true }}.
570+ {reply , ok , State # state {crash_in_terminate = true }};
571+ handle_call ({req_timeout_reply , Replyto }, _From , State ) ->
572+ Ref = make_ref (),
573+ {reply , {ok , Ref }, State , {timeout , 1 , {timeout_reply , Replyto , Ref }}}.
497574
498575handle_cast ({continue_noreply , Pid }, State ) ->
499576 self () ! {after_continue , Pid },
@@ -504,8 +581,14 @@ handle_cast(ping, #state{num_casts = NumCasts} = State) ->
504581 {noreply , State # state {num_casts = NumCasts + 1 }};
505582handle_cast ({cast_timeout , Timeout }, State ) ->
506583 {noreply , State , Timeout };
584+ handle_cast ({tuple_timeout , Timeouts }, State ) ->
585+ {noreply , State , {timeout , 1 , {do_tuple_timeouts , Timeouts }}};
507586handle_cast ({set_info_timeout , Timeout }, State ) ->
508587 {noreply , State # state {info_timeout = Timeout }};
588+ handle_cast ({req_timeout_reply , Pid }, State ) ->
589+ {noreply , State , {timeout , 1 , {timeout_reply , Pid , cast }}};
590+ handle_cast ({request_info_timeout , Pid }, State ) ->
591+ {noreply , State , {timeout , 1 , {request_info_timeout , Pid }}};
509592handle_cast (_Request , State ) ->
510593 {noreply , State }.
511594
@@ -536,6 +619,19 @@ handle_info(timeout, #state{num_timeouts = NumTimeouts, info_timeout = InfoTimeo
536619 Other ->
537620 {noreply , NewState , Other }
538621 end ;
622+ handle_info ({timeout_reply , From , Tag } = _Info , State ) ->
623+ From ! {reply_from_timeout , Tag },
624+ {noreply , State };
625+ handle_info ({request_info_timeout , From }, State ) ->
626+ {noreply , State , {timeout , 1 , {info_timeout_reply , From }}};
627+ handle_info ({info_timeout_reply , From }, State ) ->
628+ From ! {reply_from_timeout , info },
629+ {noreply , State };
630+ handle_info ({do_tuple_timeouts , 0 }, State ) ->
631+ {noreply , State };
632+ handle_info ({do_tuple_timeouts , Timeouts }, # state {num_timeouts = TimeoutCt } = State ) ->
633+ {noreply , State # state {num_timeouts = TimeoutCt + 1 },
634+ {timeout , 1 , {do_tuple_timeouts , Timeouts - 1 }}};
539635handle_info (_Info , # state {info_timeout = InfoTimeout } = State ) ->
540636 case InfoTimeout of
541637 none ->
0 commit comments