77
88-module (rabbit_writer ).
99
10+ -behavior (gen_server ).
11+
1012% % This module backs writer processes ("writers"). The responsibility of
1113% % a writer is to serialise protocol methods and write them to the socket.
1214% % Every writer is associated with a channel and normally it's the channel
2729-include (" rabbit.hrl" ).
2830-export ([start /6 , start_link /6 , start /7 , start_link /7 , start /8 , start_link /8 ]).
2931
30- -export ([system_continue /3 , system_terminate /4 , system_code_change /4 ]).
32+ -export ([init /1 ,
33+ handle_call /3 ,
34+ handle_cast /2 ,
35+ handle_info /2 ,
36+ terminate /2 ,
37+ code_change /3 ]).
3138
3239-export ([send_command /2 , send_command /3 ,
3340 send_command_sync /2 , send_command_sync /3 ,
3744-export ([internal_send_command /4 , internal_send_command /6 ]).
3845-export ([msg_size /1 , maybe_gc_large_msg /1 , maybe_gc_large_msg /2 ]).
3946
40- % % internal
41- -export ([enter_mainloop /2 , mainloop /2 , mainloop1 /2 ]).
42-
4347-record (wstate , {
4448 % % socket (port)
4549 sock ,
97101 rabbit_types :proc_name (), boolean (), undefined |non_neg_integer ()) ->
98102 rabbit_types :ok (pid ()).
99103
100- -spec system_code_change (_ ,_ ,_ ,_ ) -> {'ok' ,_ }.
101- -spec system_continue (_ ,_ ,# wstate {}) -> any ().
102- -spec system_terminate (_ ,_ ,_ ,_ ) -> no_return ().
103-
104104-spec send_command (pid (), rabbit_framing :amqp_method_record ()) -> 'ok' .
105105-spec send_command
106106 (pid (), rabbit_framing :amqp_method_record (), rabbit_types :content ()) ->
@@ -161,13 +161,15 @@ start(Sock, Channel, FrameMax, Protocol, ReaderPid, Identity,
161161 ReaderWantsStats , GCThreshold ) ->
162162 State = initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid ,
163163 ReaderWantsStats , GCThreshold ),
164- {ok , proc_lib :spawn (? MODULE , enter_mainloop , [Identity , State ])}.
164+ Options = [{hibernate_after , ? HIBERNATE_AFTER }],
165+ gen_server :start (? MODULE , [Identity , State ], Options ).
165166
166167start_link (Sock , Channel , FrameMax , Protocol , ReaderPid , Identity ,
167168 ReaderWantsStats , GCThreshold ) ->
168169 State = initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid ,
169170 ReaderWantsStats , GCThreshold ),
170- {ok , proc_lib :spawn_link (? MODULE , enter_mainloop , [Identity , State ])}.
171+ Options = [{hibernate_after , ? HIBERNATE_AFTER }],
172+ gen_server :start_link (? MODULE , [Identity , State ], Options ).
171173
172174initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid , ReaderWantsStats , GCThreshold ) ->
173175 (case ReaderWantsStats of
@@ -182,49 +184,57 @@ initial_state(Sock, Channel, FrameMax, Protocol, ReaderPid, ReaderWantsStats, GC
182184 writer_gc_threshold = GCThreshold },
183185 # wstate .stats_timer ).
184186
185- system_continue (Parent , Deb , State ) ->
186- mainloop (Deb , State # wstate {reader = Parent }).
187-
188- system_terminate (Reason , _Parent , _Deb , _State ) ->
189- exit (Reason ).
190-
191- system_code_change (Misc , _Module , _OldVsn , _Extra ) ->
192- {ok , Misc }.
193-
194- enter_mainloop (Identity , State ) ->
187+ init ([Identity , State ]) ->
195188 ? LG_PROCESS_TYPE (writer ),
196- Deb = sys :debug_options ([]),
197189 ? store_proc_name (Identity ),
198- mainloop ( Deb , State ) .
190+ { ok , State } .
199191
200- mainloop ( Deb , State ) ->
192+ handle_call ({ send_command_sync , MethodRecord }, _From , State ) ->
201193 try
202- mainloop1 (Deb , State )
194+ State1 = internal_flush (
195+ internal_send_command_async (MethodRecord , State )),
196+ {reply , ok , State1 , 0 }
203197 catch
204- exit :Error -> # wstate {reader = ReaderPid , channel = Channel } = State ,
205- ReaderPid ! {channel_exit , Channel , Error }
206- end ,
207- done .
208-
209- mainloop1 (Deb , State = # wstate {pending = []}) ->
210- receive
211- Message -> {Deb1 , State1 } = handle_message (Deb , Message , State ),
212- ? MODULE :mainloop1 (Deb1 , State1 )
213- after ? HIBERNATE_AFTER ->
214- erlang :hibernate (? MODULE , mainloop , [Deb , State ])
198+ _Class :Reason ->
199+ {stop , {shutdown , Reason }, State }
215200 end ;
216- mainloop1 (Deb , State ) ->
217- receive
218- Message -> {Deb1 , State1 } = handle_message (Deb , Message , State ),
219- ? MODULE :mainloop1 (Deb1 , State1 )
220- after 0 ->
221- ? MODULE :mainloop1 (Deb , internal_flush (State ))
201+ handle_call ({send_command_sync , MethodRecord , Content }, _From , State ) ->
202+ try
203+ State1 = internal_flush (
204+ internal_send_command_async (MethodRecord , Content , State )),
205+ {reply , ok , State1 , 0 }
206+ catch
207+ _Class :Reason ->
208+ {stop , {shutdown , Reason }, State }
209+ end ;
210+ handle_call (flush , _From , State ) ->
211+ try
212+ State1 = internal_flush (State ),
213+ {reply , ok , State1 , 0 }
214+ catch
215+ _Class :Reason ->
216+ {stop , {shutdown , Reason }, State }
222217 end .
223218
224- handle_message (Deb , {system , From , Req }, State = # wstate {reader = Parent }) ->
225- sys :handle_system_msg (Req , From , Parent , ? MODULE , Deb , State );
226- handle_message (Deb , Message , State ) ->
227- {Deb , handle_message (Message , State )}.
219+ handle_cast (_Message , State ) ->
220+ {noreply , State , 0 }.
221+
222+ handle_info (timeout , State ) ->
223+ try
224+ State1 = internal_flush (State ),
225+ {noreply , State1 }
226+ catch
227+ _Class :Reason ->
228+ {stop , {shutdown , Reason }, State }
229+ end ;
230+ handle_info (Message , State ) ->
231+ try
232+ State1 = handle_message (Message , State ),
233+ {noreply , State1 , 0 }
234+ catch
235+ _Class :Reason ->
236+ {stop , {shutdown , Reason }, State }
237+ end .
228238
229239handle_message ({send_command , MethodRecord }, State ) ->
230240 internal_send_command_async (MethodRecord , State );
@@ -236,21 +246,6 @@ handle_message({send_command_flow, MethodRecord, Sender}, State) ->
236246handle_message ({send_command_flow , MethodRecord , Content , Sender }, State ) ->
237247 credit_flow :ack (Sender ),
238248 internal_send_command_async (MethodRecord , Content , State );
239- handle_message ({'$gen_call' , From , {send_command_sync , MethodRecord }}, State ) ->
240- State1 = internal_flush (
241- internal_send_command_async (MethodRecord , State )),
242- gen_server :reply (From , ok ),
243- State1 ;
244- handle_message ({'$gen_call' , From , {send_command_sync , MethodRecord , Content }},
245- State ) ->
246- State1 = internal_flush (
247- internal_send_command_async (MethodRecord , Content , State )),
248- gen_server :reply (From , ok ),
249- State1 ;
250- handle_message ({'$gen_call' , From , flush }, State ) ->
251- State1 = internal_flush (State ),
252- gen_server :reply (From , ok ),
253- State1 ;
254249handle_message ({send_command_and_notify , QPid , ChPid , MethodRecord }, State ) ->
255250 State1 = internal_send_command_async (MethodRecord , State ),
256251 rabbit_amqqueue_common :notify_sent (QPid , ChPid ),
@@ -277,6 +272,14 @@ handle_message({ok, _Ref} = Msg, State) ->
277272handle_message (Message , _State ) ->
278273 exit ({writer , message_not_understood , Message }).
279274
275+ terminate (Reason , State ) ->
276+ # wstate {reader = ReaderPid , channel = Channel } = State ,
277+ ReaderPid ! {channel_exit , Channel , Reason },
278+ ok .
279+
280+ code_change (_OldVsn , State , _Extra ) ->
281+ {ok , State }.
282+
280283% %---------------------------------------------------------------------------
281284
282285send_command (W , MethodRecord ) ->
@@ -316,8 +319,7 @@ flush(W) -> call(W, flush).
316319% %---------------------------------------------------------------------------
317320
318321call (Pid , Msg ) ->
319- {ok , Res } = gen :call (Pid , '$gen_call' , Msg , infinity ),
320- Res .
322+ gen_server :call (Pid , Msg , infinity ).
321323
322324% %---------------------------------------------------------------------------
323325
0 commit comments