49
49
#include "rcutils/time.h"
50
50
#include "rcutils/types/hash_map.h"
51
51
52
+ #include "./rwlock.h"
53
+
52
54
53
55
#define RCUTILS_LOGGING_SEPARATOR_CHAR '.'
54
56
@@ -90,6 +92,7 @@ static const char * g_rcutils_logging_default_output_format =
90
92
static rcutils_allocator_t g_rcutils_logging_allocator ;
91
93
92
94
static rcutils_logging_output_handler_t g_rcutils_logging_output_handler = NULL ;
95
+ static rcutils_rwlock_t g_rcutils_logging_map_lock ;
93
96
static rcutils_hash_map_t g_rcutils_logging_severities_map ;
94
97
95
98
// If this is false, attempts to use the severities map will be skipped.
@@ -645,6 +648,10 @@ rcutils_ret_t rcutils_logging_initialize_with_allocator(rcutils_allocator_t allo
645
648
return RCUTILS_RET_ERROR ;
646
649
}
647
650
651
+ g_rcutils_logging_map_lock = rcutils_get_zero_initialized_rwlock ();
652
+ // TODO(clalancette): Error checking
653
+ rcutils_rwlock_init (& g_rcutils_logging_map_lock , allocator );
654
+
648
655
parse_and_create_handlers_list ();
649
656
650
657
g_rcutils_logging_severities_map_valid = true;
@@ -665,6 +672,7 @@ rcutils_ret_t rcutils_logging_shutdown(void)
665
672
// Iterate over the map, getting every key so we can free it
666
673
char * key = NULL ;
667
674
int level ;
675
+ rcutils_rwlock_write_lock (& g_rcutils_logging_map_lock );
668
676
rcutils_ret_t hash_map_ret = rcutils_hash_map_get_next_key_and_data (
669
677
& g_rcutils_logging_severities_map , NULL , & key , & level );
670
678
while (RCUTILS_RET_OK == hash_map_ret ) {
@@ -688,6 +696,9 @@ rcutils_ret_t rcutils_logging_shutdown(void)
688
696
rcutils_get_error_string ().str );
689
697
ret = RCUTILS_RET_LOGGING_SEVERITY_MAP_INVALID ;
690
698
}
699
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
700
+ rcutils_rwlock_fini (& g_rcutils_logging_map_lock );
701
+
691
702
g_rcutils_logging_severities_map_valid = false;
692
703
}
693
704
g_num_log_msg_handlers = 0 ;
@@ -775,6 +786,18 @@ static rcutils_ret_t add_key_to_hash_map(const char * name, int level, bool set_
775
786
// Check if key already exists, to avoid extra memory allocation
776
787
// If the key already exists, then rcutils_hash_map_set will not maintain the key we give it,
777
788
// so we do not need to copy the name
789
+ if (set_by_user ) {
790
+ rcutils_rwlock_write_lock (& g_rcutils_logging_map_lock );
791
+ } else {
792
+ // In the specific case where this is not being set by the user, we know
793
+ // that this is a cache set. Just try to get the lock here; if we fail,
794
+ // the worst case is that we don't cache this in the map and we'll try
795
+ // again next time.
796
+ rcutils_ret_t lockret = rcutils_rwlock_write_trylock (& g_rcutils_logging_map_lock );
797
+ if (lockret != RCUTILS_RET_OK ) {
798
+ return RCUTILS_RET_OK ;
799
+ }
800
+ }
778
801
bool already_exists = rcutils_hash_map_key_exists (& g_rcutils_logging_severities_map , & copy_name );
779
802
780
803
if (!already_exists ) {
@@ -783,6 +806,7 @@ static rcutils_ret_t add_key_to_hash_map(const char * name, int level, bool set_
783
806
if (copy_name == NULL ) {
784
807
// Don't report an error to the error handling machinery; some uses of this function are for
785
808
// caching so this is not necessarily fatal.
809
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
786
810
return RCUTILS_RET_ERROR ;
787
811
}
788
812
}
@@ -800,16 +824,21 @@ static rcutils_ret_t add_key_to_hash_map(const char * name, int level, bool set_
800
824
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING (
801
825
"Error setting severity level for logger named '%s': %s" ,
802
826
name , rcutils_get_error_string ().str );
827
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
803
828
return RCUTILS_RET_ERROR ;
804
829
}
805
830
831
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
832
+
806
833
return RCUTILS_RET_OK ;
807
834
}
808
835
809
836
static rcutils_ret_t get_severity_level (const char * name , int * severity )
810
837
{
838
+ rcutils_rwlock_read_lock (& g_rcutils_logging_map_lock );
811
839
rcutils_ret_t ret =
812
840
rcutils_hash_map_get (& g_rcutils_logging_severities_map , & name , severity );
841
+ rcutils_rwlock_read_unlock (& g_rcutils_logging_map_lock );
813
842
if (ret != RCUTILS_RET_OK ) {
814
843
// One possible response is RCUTILS_RET_NOT_FOUND, but the higher layers may be OK with that.
815
844
return ret ;
@@ -845,7 +874,9 @@ int rcutils_logging_get_logger_leveln(const char * name, size_t name_length)
845
874
}
846
875
847
876
int severity ;
877
+ rcutils_rwlock_read_lock (& g_rcutils_logging_map_lock );
848
878
rcutils_ret_t ret = get_severity_level (short_name , & severity );
879
+ rcutils_rwlock_read_unlock (& g_rcutils_logging_map_lock );
849
880
g_rcutils_logging_allocator .deallocate (short_name , g_rcutils_logging_allocator .state );
850
881
if (ret != RCUTILS_RET_OK ) {
851
882
// The error message was already set by get_severity_level
@@ -863,8 +894,10 @@ int rcutils_logging_get_logger_effective_level(const char * name)
863
894
}
864
895
865
896
size_t hash_map_size ;
897
+ rcutils_rwlock_read_lock (& g_rcutils_logging_map_lock );
866
898
rcutils_ret_t hash_map_ret = rcutils_hash_map_get_size (
867
899
& g_rcutils_logging_severities_map , & hash_map_size );
900
+ rcutils_rwlock_read_unlock (& g_rcutils_logging_map_lock );
868
901
if (hash_map_ret != RCUTILS_RET_OK ) {
869
902
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING (
870
903
"Error getting severity level for logger named '%s': %s" ,
@@ -943,20 +976,18 @@ int rcutils_logging_get_logger_effective_level(const char * name)
943
976
severity = g_rcutils_logging_default_logger_level ;
944
977
}
945
978
946
- // TODO(wjwwood): restore or replace this optimization when thread-safety is addressed
947
- // see: https://github.com/ros2/rcutils/pull/393
948
- // // If the calculated severity is anything but UNSET, we place it into the hashmap for speedier
949
- // // lookup next time. If the severity is UNSET, we don't bother because we are going to have to
950
- // // walk the hierarchy next time anyway.
951
- // if (severity != RCUTILS_LOG_SEVERITY_UNSET) {
952
- // ret = add_key_to_hash_map(name, severity, false);
953
- // if (ret != RCUTILS_RET_OK) {
954
- // // Continue on if we failed to add the key to the hashmap.
955
- // // This will affect performance but is not fatal.
956
- // RCUTILS_SAFE_FWRITE_TO_STDERR(
957
- // "Failed to cache severity; this is not fatal but will impact performance\n");
958
- // }
959
- // }
979
+ // If the calculated severity is anything but UNSET, we place it into the hashmap for speedier
980
+ // lookup next time. If the severity is UNSET, we don't bother because we are going to have to
981
+ // walk the hierarchy next time anyway.
982
+ if (severity != RCUTILS_LOG_SEVERITY_UNSET ) {
983
+ ret = add_key_to_hash_map (name , severity , false);
984
+ if (ret != RCUTILS_RET_OK ) {
985
+ // Continue on if we failed to add the key to the hashmap.
986
+ // This will affect performance but is not fatal.
987
+ RCUTILS_SAFE_FWRITE_TO_STDERR (
988
+ "Failed to cache severity; this is not fatal but will impact performance\n" );
989
+ }
990
+ }
960
991
961
992
return severity ;
962
993
}
@@ -990,6 +1021,13 @@ rcutils_ret_t rcutils_logging_set_logger_level(const char * name, int level)
990
1021
991
1022
size_t name_length = strlen (name );
992
1023
1024
+ // TODO(clalancette): We could *almost* make this a read lock, except for the fact that the loop
1025
+ // below might unset keys. If we find that this write lock is a bottleneck, we could split
1026
+ // that unsetting of keys into a separate function which acquires the write lock itself.
1027
+ // However, don't forget that when unlocking as read and relocking as write, you have to
1028
+ // double-check that the thing you were operating on still exists (since it may have been
1029
+ // changed in the meantime).
1030
+ rcutils_rwlock_write_lock (& g_rcutils_logging_map_lock );
993
1031
if (rcutils_hash_map_key_exists (& g_rcutils_logging_severities_map , & name )) {
994
1032
// Iterate over the entire contents of the severities map, looking for entries that start with
995
1033
// this key name. For any ones that match, check whether the user explicitly set them. If the
@@ -1029,6 +1067,7 @@ rcutils_ret_t rcutils_logging_set_logger_level(const char * name, int level)
1029
1067
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING (
1030
1068
"Error accessing hash map when setting logger level for '%s': %s" ,
1031
1069
name , rcutils_get_error_string ().str );
1070
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
1032
1071
return hash_map_ret ;
1033
1072
}
1034
1073
@@ -1042,12 +1081,14 @@ rcutils_ret_t rcutils_logging_set_logger_level(const char * name, int level)
1042
1081
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING (
1043
1082
"Error clearing old severity level for logger named '%s': %s" ,
1044
1083
name , rcutils_get_error_string ().str );
1084
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
1045
1085
return unset_ret ;
1046
1086
}
1047
1087
g_rcutils_logging_allocator .deallocate (previous_key , g_rcutils_logging_allocator .state );
1048
1088
}
1049
1089
}
1050
1090
}
1091
+ rcutils_rwlock_write_unlock (& g_rcutils_logging_map_lock );
1051
1092
1052
1093
rcutils_ret_t add_key_ret = add_key_to_hash_map (name , level , true);
1053
1094
if (add_key_ret != RCUTILS_RET_OK ) {
0 commit comments