vdl-tls.c
changeset 608 0fe0080331a8
parent 606 2de97e7a3f84
equal deleted inserted replaced
607:c50c2680a03e 608:0fe0080331a8
    11 #include "vdl-linkmap.h"
    11 #include "vdl-linkmap.h"
    12 #include "vdl-file.h"
    12 #include "vdl-file.h"
    13 
    13 
    14 #define TLS_EXTRA_STATIC_ALLOC 1000
    14 #define TLS_EXTRA_STATIC_ALLOC 1000
    15 
    15 
    16 static unsigned long
       
    17 allocate_tls_index (void)
       
    18 {
       
    19   // This is the slowest but simplest implementation possible
       
    20   // For each possible module index, we try to find a module
       
    21   // which has been already assigned that module index.
       
    22   // If it has been already assigned, we try another one, otherwise,
       
    23   // we return it.
       
    24   unsigned long i;
       
    25   unsigned long ul_max = 0;
       
    26   ul_max = ~ul_max;
       
    27   struct VdlList *linkmap = vdl_linkmap_copy ();
       
    28   for (i = 1; i < ul_max; i++)
       
    29     {
       
    30       void **cur;
       
    31       for (cur = vdl_list_begin (linkmap); cur != vdl_list_end (linkmap); cur = vdl_list_next (cur))
       
    32 	{
       
    33 	  struct VdlFile *item = *cur;
       
    34 	  if (item->tls_initialized &&
       
    35 	      item->has_tls && 
       
    36 	      item->tls_index == i)
       
    37 	    {
       
    38 	      break;
       
    39 	    }
       
    40 	}
       
    41       if (cur == vdl_list_end (linkmap))
       
    42 	{
       
    43 	  vdl_list_delete (linkmap);
       
    44 	  return i;
       
    45 	}
       
    46     }
       
    47   VDL_LOG_ASSERT (0, "All tls module indexes are used up ? impossible !");
       
    48   return 0; // quiet compiler
       
    49 }
       
    50 
       
    51 static void
    16 static void
    52 file_initialize (struct VdlFile *file)
    17 file_initialize (struct VdlFile *file)
    53 {
    18 {
    54   VDL_LOG_FUNCTION ("file=%s, initialized=%u", file->name, file->tls_initialized);
    19   VDL_LOG_FUNCTION ("file=%s, initialized=%u", file->name, file->tls_initialized);
    55   if (file->tls_initialized)
    20   if (file->tls_initialized)
    63     {
    28     {
    64       file->has_tls = 0;
    29       file->has_tls = 0;
    65       file->tls_initialized = 1;
    30       file->tls_initialized = 1;
    66       return;
    31       return;
    67     }
    32     }
    68   // note that the call below is _before tls_initialized = 1 because
       
    69   // it does matter. allocate_tls_index looks into the global g_vdl.link_map
       
    70   unsigned long tls_index = allocate_tls_index ();
       
    71   file->has_tls = 1;
    33   file->has_tls = 1;
    72   file->tls_initialized = 1;
    34   file->tls_initialized = 1;
    73   file->tls_tmpl_start = file->load_base + pt_tls->p_vaddr;
    35   file->tls_tmpl_start = file->load_base + pt_tls->p_vaddr;
    74   file->tls_tmpl_size = pt_tls->p_filesz;
    36   file->tls_tmpl_size = pt_tls->p_filesz;
    75   file->tls_init_zero_size = pt_tls->p_memsz - pt_tls->p_filesz;
    37   file->tls_init_zero_size = pt_tls->p_memsz - pt_tls->p_filesz;
    76   file->tls_align = pt_tls->p_align;
    38   file->tls_align = pt_tls->p_align;
    77   file->tls_index = tls_index;
    39   file->tls_index = g_vdl.tls_next_index;
    78   file->tls_is_static = (dt_flags & DF_STATIC_TLS)?1:0;
    40   file->tls_is_static = (dt_flags & DF_STATIC_TLS)?1:0;
    79   file->tls_tmpl_gen = g_vdl.tls_gen;
    41   file->tls_tmpl_gen = g_vdl.tls_gen;
       
    42   // XXX: the next_index increment code below is bad for many reasons.
       
    43   // Instead, we should try to reuse tls indexes that are not used anymore
       
    44   // to ensure that the tls index we use is as small as possible to ensure
       
    45   // that the dtv array is as small as possible. we should keep
       
    46   // track of all allocated indexes in a global list.
       
    47   g_vdl.tls_next_index++;
    80   g_vdl.tls_gen++;
    48   g_vdl.tls_gen++;
    81   g_vdl.tls_n_dtv++;
    49   g_vdl.tls_n_dtv++;
    82   VDL_LOG_DEBUG ("file=%s tmpl_size=%lu zero_size=%lu\n", 
    50   VDL_LOG_DEBUG ("file=%s tmpl_size=%lu zero_size=%lu\n", 
    83 		 file->name, file->tls_tmpl_size, 
    51 		 file->name, file->tls_tmpl_size, 
    84 		 file->tls_init_zero_size);
    52 		 file->tls_init_zero_size);
   124 {
    92 {
   125   // We calculate the size of the memory needed for the 
    93   // We calculate the size of the memory needed for the 
   126   // static and local tls model. We also initialize correctly
    94   // static and local tls model. We also initialize correctly
   127   // the tls_offset field to be able to perform relocations
    95   // the tls_offset field to be able to perform relocations
   128   // next (the TLS relocations need the tls_offset field).
    96   // next (the TLS relocations need the tls_offset field).
   129   unsigned long tcb_size = 0;
    97   unsigned long tcb_size = g_vdl.tls_static_current_size;
   130   unsigned long n_dtv = 0;
    98   unsigned long n_dtv = 0;
   131   unsigned long max_align = 1;
    99   unsigned long max_align = g_vdl.tls_static_align;
   132   void **cur;
   100   void **cur;
   133   for (cur = vdl_list_begin (list); 
   101   for (cur = vdl_list_begin (list); 
   134        cur != vdl_list_end (list); 
   102        cur != vdl_list_end (list); 
   135        cur = vdl_list_next (cur))
   103        cur = vdl_list_next (cur))
   136     {
   104     {
   159 bool
   127 bool
   160 vdl_tls_file_initialize (struct VdlList *files)
   128 vdl_tls_file_initialize (struct VdlList *files)
   161 {
   129 {
   162   file_list_initialize (files);
   130   file_list_initialize (files);
   163   struct static_tls static_tls = initialize_static_tls (files);
   131   struct static_tls static_tls = initialize_static_tls (files);
   164   long new_size = vdl_utils_align_up (g_vdl.tls_static_current_size + static_tls.size, 
   132   if (static_tls.size < g_vdl.tls_static_total_size)
   165 				      static_tls.align);
   133     {
   166   if (new_size < g_vdl.tls_static_total_size)
   134       g_vdl.tls_static_current_size = static_tls.size;
   167     {
   135       g_vdl.tls_static_align = static_tls.align;
   168       g_vdl.tls_static_current_size = new_size;
       
   169       return true;
   136       return true;
   170     }
   137     }
   171   return false;
   138   return false;
   172 }
   139 }
   173 
   140 
   206   g_vdl.tls_gen = 1;
   173   g_vdl.tls_gen = 1;
   207   // We gather tls information for each module. 
   174   // We gather tls information for each module. 
   208   file_list_initialize (list);
   175   file_list_initialize (list);
   209   // then perform initial setup of the static tls area
   176   // then perform initial setup of the static tls area
   210   struct static_tls static_tls = initialize_static_tls (list);
   177   struct static_tls static_tls = initialize_static_tls (list);
   211   g_vdl.tls_static_current_size = vdl_utils_align_up (static_tls.size, static_tls.align);
   178   g_vdl.tls_static_current_size = static_tls.size;
   212   g_vdl.tls_static_total_size = vdl_utils_align_up (g_vdl.tls_static_current_size + TLS_EXTRA_STATIC_ALLOC,
   179   g_vdl.tls_static_total_size = vdl_utils_align_up (g_vdl.tls_static_current_size + TLS_EXTRA_STATIC_ALLOC,
   213 						    static_tls.align);
   180 						    static_tls.align);
   214   g_vdl.tls_static_align = static_tls.align;
   181   g_vdl.tls_static_align = static_tls.align;
   215   g_vdl.tls_tcb_created = false;
       
   216 }
   182 }
   217 
   183 
   218 unsigned long
   184 unsigned long
   219 vdl_tls_tcb_allocate (void)
   185 vdl_tls_tcb_allocate (void)
   220 {
   186 {
   221   // we allocate continuous memory for the set of tls blocks + libpthread TCB
   187   // we allocate continuous memory for the set of tls blocks + libpthread TCB
   222   unsigned long tcb_size = g_vdl.tls_static_total_size;
   188   unsigned long tcb_size = g_vdl.tls_static_total_size;
   223   g_vdl.tls_tcb_created = true;
       
   224   unsigned long total_size = tcb_size + CONFIG_TCB_SIZE; // specific to variant II
   189   unsigned long total_size = tcb_size + CONFIG_TCB_SIZE; // specific to variant II
   225   unsigned long buffer = (unsigned long) vdl_alloc_malloc (total_size);
   190   unsigned long buffer = (unsigned long) vdl_alloc_malloc (total_size);
   226   vdl_memset ((void*)buffer, 0, total_size);
   191   vdl_memset ((void*)buffer, 0, total_size);
   227   unsigned long tcb = buffer + tcb_size;
   192   unsigned long tcb = buffer + tcb_size;
   228   // complete setup of TCB
   193   // complete setup of TCB
   359   // extract the dtv from it
   324   // extract the dtv from it
   360   struct dtv_t *dtv;
   325   struct dtv_t *dtv;
   361   vdl_memcpy (&dtv, (void*)(tp+CONFIG_TCB_DTV_OFFSET), sizeof (dtv));
   326   vdl_memcpy (&dtv, (void*)(tp+CONFIG_TCB_DTV_OFFSET), sizeof (dtv));
   362   return dtv;
   327   return dtv;
   363 }
   328 }
   364 static void
   329 void
   365 update_dtv (void)
   330 vdl_tls_dtv_update (void)
   366 {
   331 {
   367   VDL_LOG_FUNCTION ("");
   332   VDL_LOG_FUNCTION ("");
   368   unsigned long tp = machine_thread_pointer_get ();
   333   unsigned long tp = machine_thread_pointer_get ();
   369   struct dtv_t *dtv = get_current_dtv ();
   334   struct dtv_t *dtv = get_current_dtv ();
   370   unsigned long dtv_size = dtv[-1].value;
   335   unsigned long dtv_size = dtv[-1].value;
   371   VDL_LOG_ASSERT (dtv[0].gen != g_vdl.tls_gen, 
   336   if (dtv[0].gen == g_vdl.tls_gen)
   372 		  "dtv is not up-to-date");
   337     {
       
   338       return;
       
   339     }
   373 
   340 
   374   // first, we update the currently-available entries of the dtv.
   341   // first, we update the currently-available entries of the dtv.
   375   {
   342   {
   376       unsigned long module;
   343       unsigned long module;
   377       for (module = 1; module <= dtv_size; module++)
   344       for (module = 1; module <= dtv_size; module++)
   440 	  // the module has been loaded and then unloaded before
   407 	  // the module has been loaded and then unloaded before
   441 	  // we updated our dtv so, well,
   408 	  // we updated our dtv so, well,
   442 	  // nothing to do here, just skip this empty entry
   409 	  // nothing to do here, just skip this empty entry
   443 	  continue;
   410 	  continue;
   444 	}
   411 	}
   445       VDL_LOG_ASSERT (!file->tls_is_static, "tls modules with static tls blocks should never"
   412       if (file->tls_is_static)
   446 		      "be initialized here");
   413 	{
       
   414 	  signed long tcb = machine_thread_pointer_get ();
       
   415 	  signed long dtvi = tcb + file->tls_offset;
       
   416 	  new_dtv[file->tls_index].value = dtvi;
       
   417 	  new_dtv[file->tls_index].is_static = 1;
       
   418 	  new_dtv[file->tls_index].gen = file->tls_tmpl_gen;
       
   419 	  // copy the template in the module tls block
       
   420 	  vdl_memcpy ((void*)dtvi, (void*)file->tls_tmpl_start, file->tls_tmpl_size);
       
   421 	  vdl_memset ((void*)(dtvi + file->tls_tmpl_size), 0, file->tls_init_zero_size);
       
   422 	}
   447     }
   423     }
   448   // now that the dtv is updated, update the generation
   424   // now that the dtv is updated, update the generation
   449   new_dtv[0].gen = g_vdl.tls_gen;
   425   new_dtv[0].gen = g_vdl.tls_gen;
   450   // finally, clear the old dtv
   426   // finally, clear the old dtv
   451   vdl_alloc_free (&dtv[-1]);
   427   vdl_alloc_free (&dtv[-1]);
   492       dtv[module].is_static = 0;
   468       dtv[module].is_static = 0;
   493       // and return the requested value
   469       // and return the requested value
   494       return dtv[module].value + offset;
   470       return dtv[module].value + offset;
   495     }
   471     }
   496   // we know for sure that the dtv is _not_ uptodate now
   472   // we know for sure that the dtv is _not_ uptodate now
   497   update_dtv ();
   473   vdl_tls_dtv_update ();
   498 
   474 
   499   // now that the dtv is supposed to be uptodate, attempt to make
   475   // now that the dtv is supposed to be uptodate, attempt to make
   500   // the request again
   476   // the request again
   501   return vdl_tls_get_addr_slow (module, offset);
   477   return vdl_tls_get_addr_slow (module, offset);
   502 }
   478 }