Branch: Tag:

2013-08-12

2013-08-12 12:45:11 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Calendar.Timezone.Runtime_timezone_compiler: Improve reentrancy.

The runtime timezone compiler was not thread safe, and could
fail with the compiler error "Undefined identifier forever."
when multiple concurrent threads compiled the same timezone.

Potentially fixes [bug 6816] #1:1.

730:       }();    -  class Rule (string id) +  class Rule(string id)    { -  mapping rules=([]); -  +     array(string) lines = ({});    -  int amt=0; -  +     void add_line(string line)    {    lines += ({ line });    } -  +  };    -  +  class RuleCompiler(string id, array(string) lines) +  { +  mapping rules=([]); +  +  int amt=0; +     void add(string line)    {    array a= array_sscanf(line, replace("%s %s %s %s %s %s %s %[^\t ]",
944: Inside #if defined(RTTZC_TIMING)
  #ifdef RTTZC_TIMING    float t1=time(t);   #endif + #ifdef RTTZC_DEBUG +  werror("Compiling rule %s\n", id); + #endif       foreach(lines, string line) add(line);   
979:    {    string id;    -  array rules=({}); -  +     array(string) lines = ({});       array(string) aliases = ({});
999:    {    lines += ({ line });    } +  };    -  +  class ZoneCompiler(string id, array(string) lines, array(string) aliases) +  { +  array rules=({}); +     void add(string line)    {    array a= array_sscanf(line, replace("%s %s %s %s",
1185: Inside #if defined(RTTZC_TIMING)
  #ifdef RTTZC_TIMING    float t1=time(t);   #endif + #ifdef RTTZC_DEBUG +  werror("Compiling zone %s\n", zone_name); + #endif       rules = ({});    foreach(lines, string line) add(line);
1269:    float t1=time(t);   #endif    -  rule_cache = ([]); -  zone_cache = ([]); +  mapping(string:Zone) new_zones = ([]); +  mapping(string:Rule) new_rules = ([]);       mapping(string:string) zone_aliases = ([]);   
1285:    string rule_name, interval;    if (sscanf(line, "Rule%*[ \t]%[^ \t]%*[ \t]%s",    rule_name, interval) == 4) { -  Rule r = rules[rule_name]; +  Rule r = new_rules[rule_name];    if (!r) { -  r = rules[rule_name] = Rule(rule_name); +  r = new_rules[rule_name] = Rule(rule_name);    }    r->add_line(interval);    } else {
1298:    if (sscanf(line, "Zone%*[ \t]%[^ \t]%*[ \t]%s",    zone_name, zone_info) == 4) {    // werror("Creating zone %O.\n", zone_name); -  Zone z = current_zone = zones[zone_name] = Zone(zone_name); +  Zone z = current_zone = new_zones[zone_name] = Zone(zone_name);    z->add_line(zone_info);    } else {    werror("Failed to parse directive %O.\n", line);
1310:    Zone z = zones[zone_name];    if (z) {    z->add_alias(zone_alias); -  zones[zone_alias] = z; -  } else if (zone_cache[zone_name]) { -  zone_cache[zone_alias] = zone_cache[zone_name]; +  new_zones[zone_alias] = z;    } else {    // werror("Deferred alias: %O ==> %O.\n", zone_alias, zone_name);    zone_aliases[zone_alias] = zone_name;
1338:    // Fixup the zone aliases.    foreach(zone_aliases; string zone_alias; string zone_name) {    Zone z; -  if ((z = zones[zone_name])) { +  if ((z = new_zones[zone_name])) {    z->add_alias(zone_alias); -  zones[zone_alias] = z; -  } else if (!(zone_cache[zone_alias] = zone_cache[zone_name])) { +  new_zones[zone_alias] = z; +  } else {    werror("Zone %O is a link to a nonexistant zone %O.\n",    zone_alias, zone_name);    }    } -  +  +  zones = new_zones; +  rules = new_rules; +  +  rule_cache = ([]); +  zone_cache = ([]);    }       object find_zone(string s)
1366:    return zone_cache[s] = find_zone(a[0]);    return UNDEFINED;    } -  ret = z->compile(); +  ret = ZoneCompiler(z->id, z->lines, z->aliases)->compile();    foreach(z->aliases, string zone_alias) {    zone_cache[zone_alias] = ret;    m_delete(zones, zone_alias);
1383:    if (ret) return ret;    Rule r;    if (!(r = rules[s])) return UNDEFINED; -  ret = rule_cache[s] = r->compile(); +  ret = rule_cache[s] = RuleCompiler(s, r->lines)->compile();    m_delete(rules, s);    return ret;    }