View | Details | Raw Unified | Return to bug 20370
Collapse All | Expand All

(-)a/malloc/arena.c (-5 / +211 lines)
Lines 77-82 static mutex_t free_list_lock = _LIBC_LOCK_INITIALIZER; Link Here
77
static size_t narenas = 1;
77
static size_t narenas = 1;
78
static mstate free_list;
78
static mstate free_list;
79
79
80
static void
81
write_message (const char *string)
82
{
83
  write (STDERR_FILENO, string, strlen (string));
84
}
85
86
static void
87
check_attachment (void)
88
{
89
  if (thread_arena != NULL)
90
    {
91
      mutex_lock (&free_list_lock);
92
      if (thread_arena->attached_threads == 0)
93
	{
94
	  char buf[256];
95
	  __snprintf (buf, sizeof (buf),
96
		      "Current arena %p has zero attached threads.",
97
		      thread_arena);
98
	  write_message (buf);
99
	  for (mstate p = &main_arena; ; )
100
	    {
101
	      __snprintf (buf, sizeof (buf),  "  %p (next_free: %p) %zu%s\n",
102
			  p, p->next_free, p->attached_threads,
103
			  p == thread_arena ? " *" : "");
104
	      write_message (buf);
105
	      p = p->next;
106
	      if (p == &main_arena)
107
		break;
108
	    }
109
	  abort ();
110
	}
111
      mutex_unlock (&free_list_lock);
112
    }
113
}
114
115
static void
116
check_free_list_nolock (const char *func, const char *place)
117
{
118
  size_t list_length = 0;
119
  for (mstate current = free_list; current != NULL;
120
       current = current->next_free)
121
    {
122
      ++list_length;
123
124
      /* See if the arena appears in the first list_length - 1
125
	 arenas as well.  */
126
      mstate p = free_list;
127
      for (int j = 1; j < list_length; ++j)
128
	{
129
	  if (p == current)
130
	  {
131
	    char buf[256];
132
	    __snprintf (buf, sizeof (buf),
133
			"Arena free list cycle detected (%s, %s):\n",
134
			func, place);
135
	    write_message (buf);
136
	    /* Start from the beginning and print the first
137
	       list_length items.  */
138
	    p = free_list;
139
	    for (int j = 0; j < list_length; ++j)
140
	      {
141
		__snprintf (buf, sizeof (buf),  "  %p %zu%s\n",
142
			    p, p->attached_threads,
143
			    p == current ? " *" : "");
144
		write_message (buf);
145
		p = p->next_free;
146
	      }
147
	    __snprintf (buf, sizeof (buf), "Total arena count: %zu\n",
148
			atomic_load_relaxed (&narenas));
149
	    write_message (buf);
150
151
	    for (p = &main_arena; ; )
152
	      {
153
		__snprintf (buf, sizeof (buf),  "  %p (next_free: %p) %zu%s\n",
154
			    p, p->next_free, p->attached_threads,
155
			    p == current ? " *" : "");
156
		write_message (buf);
157
		p = p->next;
158
		if (p == &main_arena)
159
		  break;
160
	      }
161
	    abort ();
162
	  }
163
	  p = p->next_free;
164
	}
165
    }
166
}
167
168
static void
169
check_free_list (const char *func, const char *place)
170
{
171
  mutex_lock (&free_list_lock);
172
  check_free_list_nolock (func, place);
173
  mutex_unlock (&free_list_lock);
174
}
175
80
/* list_lock prevents concurrent writes to the next member of struct
176
/* list_lock prevents concurrent writes to the next member of struct
81
   malloc_state objects.
177
   malloc_state objects.
82
178
Lines 106-111 int __malloc_initialized = -1; Link Here
106
   in the new arena. */
202
   in the new arena. */
107
203
108
#define arena_get(ptr, size) do { \
204
#define arena_get(ptr, size) do { \
205
    check_attachment ();						\
109
      ptr = thread_arena;						      \
206
      ptr = thread_arena;						      \
110
      arena_lock (ptr, size);						      \
207
      arena_lock (ptr, size);						      \
111
  } while (0)
208
  } while (0)
Lines 670-675 _int_new_arena (size_t size) Link Here
670
  thread_arena = a;
767
  thread_arena = a;
671
  mutex_init (&a->mutex);
768
  mutex_init (&a->mutex);
672
769
770
  check_free_list (__func__, "before link-in");
771
673
  (void) mutex_lock (&list_lock);
772
  (void) mutex_lock (&list_lock);
674
773
675
  /* Add the new arena to the global list.  */
774
  /* Add the new arena to the global list.  */
Lines 682-690 _int_new_arena (size_t size) Link Here
682
781
683
  (void) mutex_unlock (&list_lock);
782
  (void) mutex_unlock (&list_lock);
684
783
784
  check_free_list (__func__, "before detach");
685
  (void) mutex_lock (&free_list_lock);
785
  (void) mutex_lock (&free_list_lock);
686
  detach_arena (replaced_arena);
786
  detach_arena (replaced_arena);
687
  (void) mutex_unlock (&free_list_lock);
787
  (void) mutex_unlock (&free_list_lock);
788
  check_free_list (__func__, "after detach");
688
789
689
  /* Lock this arena.  NB: Another thread may have been attached to
790
  /* Lock this arena.  NB: Another thread may have been attached to
690
     this arena because the arena is now accessible from the
791
     this arena because the arena is now accessible from the
Lines 702-712 _int_new_arena (size_t size) Link Here
702
}
803
}
703
804
704
805
705
/* Remove an arena from free_list.  The arena may be in use because it
806
/* Remove an arena from free_list.  */
706
   was attached concurrently to a thread by reused_arena below.  */
707
static mstate
807
static mstate
708
get_free_list (void)
808
get_free_list (void)
709
{
809
{
810
  check_free_list (__func__, "start");
710
  mstate replaced_arena = thread_arena;
811
  mstate replaced_arena = thread_arena;
711
  mstate result = free_list;
812
  mstate result = free_list;
712
  if (result != NULL)
813
  if (result != NULL)
Lines 718-724 get_free_list (void) Link Here
718
	  free_list = result->next_free;
819
	  free_list = result->next_free;
719
820
720
	  /* The arena will be attached to this thread.  */
821
	  /* The arena will be attached to this thread.  */
721
	  ++result->attached_threads;
822
	  assert (result->attached_threads == 0);
823
	  result->attached_threads = 1;
722
824
723
	  detach_arena (replaced_arena);
825
	  detach_arena (replaced_arena);
724
	}
826
	}
Lines 732-740 get_free_list (void) Link Here
732
        }
834
        }
733
    }
835
    }
734
836
837
  check_attachment ();
838
  if (result != NULL)
839
    {
840
      (void) mutex_lock (&free_list_lock);
841
      check_free_list_nolock (__func__, "after detach/attach");
842
      /* We know that the free list does not contain a loop.   */
843
      for (mstate p = free_list; p != NULL; p = p->next_free)
844
	if (p == result)
845
	  {
846
	    char buf[256];
847
	    __snprintf (buf, sizeof (buf),
848
			"get_free_list returns arena %p still on free list:",
849
			thread_arena);
850
	    write_message (buf);
851
852
	    for (p = free_list; p != NULL; p = p->next_free)
853
	      {
854
		__snprintf (buf, sizeof (buf),  "  %p %zu%s\n",
855
			    p, p->attached_threads,
856
			    p == result ? " *" : "");
857
		write_message (buf);
858
	      }
859
860
	    for (p = &main_arena; ; )
861
	      {
862
		__snprintf (buf, sizeof (buf),  "  %p (next_free: %p) %zu%s\n",
863
			    p, p->next_free, p->attached_threads,
864
			    p == result ? " *" : "");
865
		write_message (buf);
866
		p = p->next;
867
		if (p == &main_arena)
868
		  break;
869
	      }
870
	    abort ();
871
	  }
872
      (void) mutex_unlock (&free_list_lock);
873
    }
874
735
  return result;
875
  return result;
736
}
876
}
737
877
878
/* Remove the arena from the free list (if it is present).
879
   free_list_lock must have been acquired by the caller.  */
880
static void
881
remove_from_free_list (mstate arena)
882
{
883
  mstate *previous = &free_list;
884
  for (mstate p = free_list; p != NULL; p = p->next_free)
885
    {
886
      assert (p->attached_threads == 0);
887
      if (p == arena)
888
	{
889
	  /* Remove the requested arena from the list.  */
890
	  *previous = p->next_free;
891
	  break;
892
	}
893
      else
894
	previous = &p->next_free;
895
    }
896
}
897
738
/* Lock and return an arena that can be reused for memory allocation.
898
/* Lock and return an arena that can be reused for memory allocation.
739
   Avoid AVOID_ARENA as we have already failed to allocate memory in
899
   Avoid AVOID_ARENA as we have already failed to allocate memory in
740
   it and it is currently locked.  */
900
   it and it is currently locked.  */
Lines 782-796 reused_arena (mstate avoid_arena) Link Here
782
  (void) mutex_lock (&result->mutex);
942
  (void) mutex_lock (&result->mutex);
783
943
784
out:
944
out:
785
  /* Attach the arena to the current thread.  Note that we may have
945
  /* Attach the arena to the current thread.  */
786
     selected an arena which was on free_list.  */
787
  {
946
  {
788
    /* Update the arena thread attachment counters.   */
947
    /* Update the arena thread attachment counters.   */
948
    check_free_list (__func__, "before detach");
789
    mstate replaced_arena = thread_arena;
949
    mstate replaced_arena = thread_arena;
790
    (void) mutex_lock (&free_list_lock);
950
    (void) mutex_lock (&free_list_lock);
791
    detach_arena (replaced_arena);
951
    detach_arena (replaced_arena);
952
953
    /* We may have picked up an arena on the free list.  We need to
954
       preserve the invariant that no arena on the free list has a
955
       positive attached_threads counter (otherwise,
956
       arena_thread_freeres cannot use the counter to determine if the
957
       arena needs to be put on the free list).  We unconditionally
958
       remove the selected arena from the free list.  The caller of
959
       reused_arena checked the free list and observed it to be empty,
960
       so the list is very short.  */
961
    remove_from_free_list (result);
962
792
    ++result->attached_threads;
963
    ++result->attached_threads;
964
793
    (void) mutex_unlock (&free_list_lock);
965
    (void) mutex_unlock (&free_list_lock);
966
    check_free_list (__func__, "after detach");
794
  }
967
  }
795
968
796
  LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
969
  LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
Lines 804-809 static mstate Link Here
804
internal_function
977
internal_function
805
arena_get2 (size_t size, mstate avoid_arena)
978
arena_get2 (size_t size, mstate avoid_arena)
806
{
979
{
980
  check_attachment ();				\
807
  mstate a;
981
  mstate a;
808
982
809
  static size_t narenas_limit;
983
  static size_t narenas_limit;
Lines 848-853 arena_get2 (size_t size, mstate avoid_arena) Link Here
848
      else
1022
      else
849
        a = reused_arena (avoid_arena);
1023
        a = reused_arena (avoid_arena);
850
    }
1024
    }
1025
  check_attachment ();				\
851
  return a;
1026
  return a;
852
}
1027
}
853
1028
Lines 887-901 arena_thread_freeres (void) Link Here
887
  if (a != NULL)
1062
  if (a != NULL)
888
    {
1063
    {
889
      (void) mutex_lock (&free_list_lock);
1064
      (void) mutex_lock (&free_list_lock);
1065
      check_free_list_nolock (__func__, "before detach");
890
      /* If this was the last attached thread for this arena, put the
1066
      /* If this was the last attached thread for this arena, put the
891
	 arena on the free list.  */
1067
	 arena on the free list.  */
892
      assert (a->attached_threads > 0);
1068
      assert (a->attached_threads > 0);
893
      if (--a->attached_threads == 0)
1069
      if (--a->attached_threads == 0)
894
	{
1070
	{
1071
	  for (mstate p = free_list; p != NULL; p = p->next_free)
1072
	    if (p == a)
1073
	      {
1074
		char buf[256];
1075
		__snprintf (buf, sizeof (buf),
1076
			    "Pushing %p to the free list creates a loop\n", a);
1077
		write_message (buf);
1078
		for (mstate p = free_list; p != NULL; p = p->next_free)
1079
		  {
1080
		    __snprintf (buf, sizeof (buf),  "  %p %zu%s\n",
1081
				p, p->attached_threads,
1082
				p == a ? " *" : "");
1083
		    write_message (buf);
1084
		  }
1085
1086
		write_message ("Arenas:\n");
1087
		size_t arena_number = 0;
1088
		for (mstate p = &main_arena; ; )
1089
		  {
1090
		    __snprintf (buf, sizeof (buf),  "  (%zu) %p (next_free: %p) %zu%s\n",
1091
				arena_number++, p, p->next_free, p->attached_threads,
1092
				p == a ? " *" : "");
1093
		    write_message (buf);
1094
		    p = p->next;
1095
		    if (p == &main_arena)
1096
		      break;
1097
		  }
1098
		abort ();
1099
	    }
895
	  a->next_free = free_list;
1100
	  a->next_free = free_list;
896
	  free_list = a;
1101
	  free_list = a;
897
	}
1102
	}
898
      (void) mutex_unlock (&free_list_lock);
1103
      (void) mutex_unlock (&free_list_lock);
1104
      check_free_list (__func__, "after detach");
899
    }
1105
    }
900
}
1106
}
901
text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
1107
text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
(-)a/malloc/tst-malloc-thread-exit.c (-2 / +4 lines)
Lines 157-162 outer_thread (void *closure) Link Here
157
  return NULL;
157
  return NULL;
158
}
158
}
159
159
160
#undef TIMEOUT
161
#define TIMEOUT 600
162
160
static int
163
static int
161
do_test (void)
164
do_test (void)
162
{
165
{
Lines 172-179 do_test (void) Link Here
172
175
173
  /* Leave some room for shutting down all threads gracefully.  */
176
  /* Leave some room for shutting down all threads gracefully.  */
174
  int timeout = 3;
177
  int timeout = 3;
175
  if (timeout > TIMEOUT)
178
  timeout = TIMEOUT - 1;
176
    timeout = TIMEOUT - 1;
177
179
178
  pthread_t *threads = calloc (sizeof (*threads), outer_thread_count);
180
  pthread_t *threads = calloc (sizeof (*threads), outer_thread_count);
179
  if (threads == NULL)
181
  if (threads == NULL)

Return to bug 20370