@@ -155,7 +155,6 @@ use cfg_if::cfg_if;
155
155
use crate :: { Error , Result } ;
156
156
use crate :: errno:: Errno ;
157
157
use libc:: { self , c_int, tcflag_t} ;
158
- use std:: cell:: { Ref , RefCell } ;
159
158
use std:: convert:: { From , TryFrom } ;
160
159
use std:: mem;
161
160
use std:: os:: unix:: io:: RawFd ;
@@ -167,9 +166,14 @@ use crate::unistd::Pid;
167
166
/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
168
167
/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
169
168
/// an open port using `tcgetattr()`.
170
- #[ derive( Clone , Debug , Eq , PartialEq ) ]
169
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
171
170
pub struct Termios {
172
- inner : RefCell < libc:: termios > ,
171
+ // The actual fields present in `libc::termios` vary from one platform to
172
+ // another. By only constructing `Termios` values from actual tcgetattr
173
+ // calls, we ensure that unknown fields have reasonable values. We just need
174
+ // to remember to update `inner` before it's read, and update the public
175
+ // fields after `inner` has been modified.
176
+ inner : libc:: termios ,
173
177
/// Input mode flags (see `termios.c_iflag` documentation)
174
178
pub input_flags : InputFlags ,
175
179
/// Output mode flags (see `termios.c_oflag` documentation)
@@ -187,39 +191,19 @@ impl Termios {
187
191
///
188
192
/// This is not part of `nix`'s public API because it requires additional work to maintain type
189
193
/// safety.
190
- pub ( crate ) fn get_libc_termios ( & self ) -> Ref < libc:: termios > {
191
- {
192
- let mut termios = self . inner . borrow_mut ( ) ;
193
- termios. c_iflag = self . input_flags . bits ( ) ;
194
- termios. c_oflag = self . output_flags . bits ( ) ;
195
- termios. c_cflag = self . control_flags . bits ( ) ;
196
- termios. c_lflag = self . local_flags . bits ( ) ;
197
- termios. c_cc = self . control_chars ;
198
- }
199
- self . inner . borrow ( )
200
- }
201
-
202
- /// Exposes the inner `libc::termios` datastore within `Termios`.
203
- ///
204
- /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
205
- /// not automatically update the safe wrapper type around it. In this case it should also be
206
- /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
207
- /// representation stay consistent.
208
- pub ( crate ) unsafe fn get_libc_termios_mut ( & mut self ) -> * mut libc:: termios {
209
- {
210
- let mut termios = self . inner . borrow_mut ( ) ;
211
- termios. c_iflag = self . input_flags . bits ( ) ;
212
- termios. c_oflag = self . output_flags . bits ( ) ;
213
- termios. c_cflag = self . control_flags . bits ( ) ;
214
- termios. c_lflag = self . local_flags . bits ( ) ;
215
- termios. c_cc = self . control_chars ;
216
- }
217
- self . inner . as_ptr ( )
194
+ pub ( crate ) fn get_libc_termios ( & self ) -> libc:: termios {
195
+ let mut termios = self . inner . clone ( ) ;
196
+ termios. c_iflag = self . input_flags . bits ( ) ;
197
+ termios. c_oflag = self . output_flags . bits ( ) ;
198
+ termios. c_cflag = self . control_flags . bits ( ) ;
199
+ termios. c_lflag = self . local_flags . bits ( ) ;
200
+ termios. c_cc = self . control_chars ;
201
+ termios
218
202
}
219
203
220
204
/// Updates the wrapper values from the internal `libc::termios` data structure.
221
- pub ( crate ) fn update_wrapper ( & mut self ) {
222
- let termios = * self . inner . borrow_mut ( ) ;
205
+ pub ( crate ) fn set_libc_termios ( & mut self , termios : & libc :: termios ) {
206
+ self . inner = * termios ;
223
207
self . input_flags = InputFlags :: from_bits_truncate ( termios. c_iflag ) ;
224
208
self . output_flags = OutputFlags :: from_bits_truncate ( termios. c_oflag ) ;
225
209
self . control_flags = ControlFlags :: from_bits_truncate ( termios. c_cflag ) ;
@@ -231,7 +215,7 @@ impl Termios {
231
215
impl From < libc:: termios > for Termios {
232
216
fn from ( termios : libc:: termios ) -> Self {
233
217
Termios {
234
- inner : RefCell :: new ( termios) ,
218
+ inner : termios,
235
219
input_flags : InputFlags :: from_bits_truncate ( termios. c_iflag ) ,
236
220
output_flags : OutputFlags :: from_bits_truncate ( termios. c_oflag ) ,
237
221
control_flags : ControlFlags :: from_bits_truncate ( termios. c_cflag ) ,
@@ -243,7 +227,7 @@ impl From<libc::termios> for Termios {
243
227
244
228
impl From < Termios > for libc:: termios {
245
229
fn from ( termios : Termios ) -> Self {
246
- termios. inner . into_inner ( )
230
+ termios. inner
247
231
}
248
232
}
249
233
@@ -881,7 +865,7 @@ cfg_if!{
881
865
/// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
882
866
pub fn cfgetispeed( termios: & Termios ) -> u32 {
883
867
let inner_termios = termios. get_libc_termios( ) ;
884
- unsafe { libc:: cfgetispeed( & * inner_termios) as u32 }
868
+ unsafe { libc:: cfgetispeed( & inner_termios) as u32 }
885
869
}
886
870
887
871
/// Get output baud rate (see
@@ -890,17 +874,17 @@ cfg_if!{
890
874
/// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
891
875
pub fn cfgetospeed( termios: & Termios ) -> u32 {
892
876
let inner_termios = termios. get_libc_termios( ) ;
893
- unsafe { libc:: cfgetospeed( & * inner_termios) as u32 }
877
+ unsafe { libc:: cfgetospeed( & inner_termios) as u32 }
894
878
}
895
879
896
880
/// Set input baud rate (see
897
881
/// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
898
882
///
899
883
/// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
900
884
pub fn cfsetispeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
901
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
902
- let res = unsafe { libc:: cfsetispeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
903
- termios. update_wrapper ( ) ;
885
+ let mut inner_termios = termios. get_libc_termios ( ) ;
886
+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
887
+ termios. set_libc_termios ( & inner_termios ) ;
904
888
Errno :: result( res) . map( drop)
905
889
}
906
890
@@ -909,9 +893,9 @@ cfg_if!{
909
893
///
910
894
/// `cfsetospeed()` sets the output baud rate in the given termios structure.
911
895
pub fn cfsetospeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
912
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
913
- let res = unsafe { libc:: cfsetospeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
914
- termios. update_wrapper ( ) ;
896
+ let mut inner_termios = termios. get_libc_termios ( ) ;
897
+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
898
+ termios. set_libc_termios ( & inner_termios ) ;
915
899
Errno :: result( res) . map( drop)
916
900
}
917
901
@@ -921,9 +905,9 @@ cfg_if!{
921
905
/// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
922
906
/// this is part of the 4.4BSD standard and not part of POSIX.
923
907
pub fn cfsetspeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
924
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
925
- let res = unsafe { libc:: cfsetspeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
926
- termios. update_wrapper ( ) ;
908
+ let mut inner_termios = termios. get_libc_termios ( ) ;
909
+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
910
+ termios. set_libc_termios ( & inner_termios ) ;
927
911
Errno :: result( res) . map( drop)
928
912
}
929
913
} else {
@@ -935,7 +919,7 @@ cfg_if!{
935
919
/// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
936
920
pub fn cfgetispeed( termios: & Termios ) -> BaudRate {
937
921
let inner_termios = termios. get_libc_termios( ) ;
938
- unsafe { libc:: cfgetispeed( & * inner_termios) } . try_into( ) . unwrap( )
922
+ unsafe { libc:: cfgetispeed( & inner_termios) } . try_into( ) . unwrap( )
939
923
}
940
924
941
925
/// Get output baud rate (see
@@ -944,17 +928,17 @@ cfg_if!{
944
928
/// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
945
929
pub fn cfgetospeed( termios: & Termios ) -> BaudRate {
946
930
let inner_termios = termios. get_libc_termios( ) ;
947
- unsafe { libc:: cfgetospeed( & * inner_termios) } . try_into( ) . unwrap( )
931
+ unsafe { libc:: cfgetospeed( & inner_termios) } . try_into( ) . unwrap( )
948
932
}
949
933
950
934
/// Set input baud rate (see
951
935
/// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
952
936
///
953
937
/// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
954
938
pub fn cfsetispeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
955
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
956
- let res = unsafe { libc:: cfsetispeed( inner_termios, baud as libc:: speed_t) } ;
957
- termios. update_wrapper ( ) ;
939
+ let mut inner_termios = termios. get_libc_termios ( ) ;
940
+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
941
+ termios. set_libc_termios ( & inner_termios ) ;
958
942
Errno :: result( res) . map( drop)
959
943
}
960
944
@@ -963,9 +947,9 @@ cfg_if!{
963
947
///
964
948
/// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
965
949
pub fn cfsetospeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
966
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
967
- let res = unsafe { libc:: cfsetospeed( inner_termios, baud as libc:: speed_t) } ;
968
- termios. update_wrapper ( ) ;
950
+ let mut inner_termios = termios. get_libc_termios ( ) ;
951
+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
952
+ termios. set_libc_termios ( & inner_termios ) ;
969
953
Errno :: result( res) . map( drop)
970
954
}
971
955
@@ -975,9 +959,9 @@ cfg_if!{
975
959
/// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
976
960
/// this is part of the 4.4BSD standard and not part of POSIX.
977
961
pub fn cfsetspeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
978
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
979
- let res = unsafe { libc:: cfsetspeed( inner_termios, baud as libc:: speed_t) } ;
980
- termios. update_wrapper ( ) ;
962
+ let mut inner_termios = termios. get_libc_termios ( ) ;
963
+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
964
+ termios. set_libc_termios ( & inner_termios ) ;
981
965
Errno :: result( res) . map( drop)
982
966
}
983
967
}
@@ -990,11 +974,11 @@ cfg_if!{
990
974
/// character, echoing is disabled, and all special input and output processing is disabled. Note
991
975
/// that this is a non-standard function, but is available on Linux and BSDs.
992
976
pub fn cfmakeraw ( termios : & mut Termios ) {
993
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
977
+ let mut inner_termios = termios. get_libc_termios ( ) ;
994
978
unsafe {
995
- libc:: cfmakeraw ( inner_termios) ;
979
+ libc:: cfmakeraw ( & mut inner_termios as * mut _ ) ;
996
980
}
997
- termios. update_wrapper ( ) ;
981
+ termios. set_libc_termios ( & inner_termios ) ;
998
982
}
999
983
1000
984
/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
@@ -1003,11 +987,11 @@ pub fn cfmakeraw(termios: &mut Termios) {
1003
987
/// Note that this is a non-standard function, available on FreeBSD.
1004
988
#[ cfg( target_os = "freebsd" ) ]
1005
989
pub fn cfmakesane ( termios : & mut Termios ) {
1006
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
990
+ let mut inner_termios = termios. get_libc_termios ( ) ;
1007
991
unsafe {
1008
- libc:: cfmakesane ( inner_termios) ;
992
+ libc:: cfmakesane ( & mut inner_termios as * mut _ ) ;
1009
993
}
1010
- termios. update_wrapper ( ) ;
994
+ termios. set_libc_termios ( & inner_termios ) ;
1011
995
}
1012
996
1013
997
/// Return the configuration of a port
@@ -1034,7 +1018,7 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
1034
1018
/// *any* of the parameters were successfully set, not only if all were set successfully.
1035
1019
pub fn tcsetattr ( fd : RawFd , actions : SetArg , termios : & Termios ) -> Result < ( ) > {
1036
1020
let inner_termios = termios. get_libc_termios ( ) ;
1037
- Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & * inner_termios) } ) . map ( drop)
1021
+ Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & inner_termios) } ) . map ( drop)
1038
1022
}
1039
1023
1040
1024
/// Block until all output data is written (see
0 commit comments