7
7
8
8
-module (rabbit_writer ).
9
9
10
+ -behavior (gen_server ).
11
+
10
12
% % This module backs writer processes ("writers"). The responsibility of
11
13
% % a writer is to serialise protocol methods and write them to the socket.
12
14
% % Every writer is associated with a channel and normally it's the channel
27
29
-include (" rabbit.hrl" ).
28
30
-export ([start /6 , start_link /6 , start /7 , start_link /7 , start /8 , start_link /8 ]).
29
31
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 ]).
31
38
32
39
-export ([send_command /2 , send_command /3 ,
33
40
send_command_sync /2 , send_command_sync /3 ,
37
44
-export ([internal_send_command /4 , internal_send_command /6 ]).
38
45
-export ([msg_size /1 , maybe_gc_large_msg /1 , maybe_gc_large_msg /2 ]).
39
46
40
- % % internal
41
- -export ([enter_mainloop /2 , mainloop /2 , mainloop1 /2 ]).
42
-
43
47
-record (wstate , {
44
48
% % socket (port)
45
49
sock ,
97
101
rabbit_types :proc_name (), boolean (), undefined |non_neg_integer ()) ->
98
102
rabbit_types :ok (pid ()).
99
103
100
- -spec system_code_change (_ ,_ ,_ ,_ ) -> {'ok' ,_ }.
101
- -spec system_continue (_ ,_ ,# wstate {}) -> any ().
102
- -spec system_terminate (_ ,_ ,_ ,_ ) -> no_return ().
103
-
104
104
-spec send_command (pid (), rabbit_framing :amqp_method_record ()) -> 'ok' .
105
105
-spec send_command
106
106
(pid (), rabbit_framing :amqp_method_record (), rabbit_types :content ()) ->
@@ -161,13 +161,15 @@ start(Sock, Channel, FrameMax, Protocol, ReaderPid, Identity,
161
161
ReaderWantsStats , GCThreshold ) ->
162
162
State = initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid ,
163
163
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 ).
165
166
166
167
start_link (Sock , Channel , FrameMax , Protocol , ReaderPid , Identity ,
167
168
ReaderWantsStats , GCThreshold ) ->
168
169
State = initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid ,
169
170
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 ).
171
173
172
174
initial_state (Sock , Channel , FrameMax , Protocol , ReaderPid , ReaderWantsStats , GCThreshold ) ->
173
175
(case ReaderWantsStats of
@@ -182,49 +184,57 @@ initial_state(Sock, Channel, FrameMax, Protocol, ReaderPid, ReaderWantsStats, GC
182
184
writer_gc_threshold = GCThreshold },
183
185
# wstate .stats_timer ).
184
186
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 ]) ->
195
188
? LG_PROCESS_TYPE (writer ),
196
- Deb = sys :debug_options ([]),
197
189
? store_proc_name (Identity ),
198
- mainloop ( Deb , State ) .
190
+ { ok , State } .
199
191
200
- mainloop ( Deb , State ) ->
192
+ handle_call ({ send_command_sync , MethodRecord }, _From , State ) ->
201
193
try
202
- mainloop1 (Deb , State )
194
+ State1 = internal_flush (
195
+ internal_send_command_async (MethodRecord , State )),
196
+ {reply , ok , State1 , 0 }
203
197
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 }
215
200
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 }
222
217
end .
223
218
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 .
228
238
229
239
handle_message ({send_command , MethodRecord }, State ) ->
230
240
internal_send_command_async (MethodRecord , State );
@@ -236,21 +246,6 @@ handle_message({send_command_flow, MethodRecord, Sender}, State) ->
236
246
handle_message ({send_command_flow , MethodRecord , Content , Sender }, State ) ->
237
247
credit_flow :ack (Sender ),
238
248
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 ;
254
249
handle_message ({send_command_and_notify , QPid , ChPid , MethodRecord }, State ) ->
255
250
State1 = internal_send_command_async (MethodRecord , State ),
256
251
rabbit_amqqueue_common :notify_sent (QPid , ChPid ),
@@ -277,6 +272,14 @@ handle_message({ok, _Ref} = Msg, State) ->
277
272
handle_message (Message , _State ) ->
278
273
exit ({writer , message_not_understood , Message }).
279
274
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
+
280
283
% %---------------------------------------------------------------------------
281
284
282
285
send_command (W , MethodRecord ) ->
@@ -316,8 +319,7 @@ flush(W) -> call(W, flush).
316
319
% %---------------------------------------------------------------------------
317
320
318
321
call (Pid , Msg ) ->
319
- {ok , Res } = gen :call (Pid , '$gen_call' , Msg , infinity ),
320
- Res .
322
+ gen_server :call (Pid , Msg , infinity ).
321
323
322
324
% %---------------------------------------------------------------------------
323
325
0 commit comments