1594
1595
#ifdef THREADED_DELTA_SEARCH
1596
1597
+/*
1598
+ * The main thread waits on the condition that (at least) one of the workers
1599
+ * has stopped working (which is indicated in the .working member of
1600
+ * struct thread_params).
1601
+ * When a work thread has completed its work, it sets .working to 0 and
1602
+ * signals the main thread and waits on the condition that .data_ready
1603
+ * becomes 1.
1604
+ */
1605
+
1606
struct thread_params {
1607
pthread_t thread;
1608
struct object_entry **list;
1610
unsigned remaining;
1611
int window;
1612
int depth;
1613
+ int working;
1614
+ int data_ready;
1615
+ pthread_mutex_t mutex;
1616
+ pthread_cond_t cond;
1617
unsigned *processed;
1618
};
1619
1607
-static pthread_mutex_t data_request = PTHREAD_MUTEX_INITIALIZER;
1608
-static pthread_mutex_t data_ready = PTHREAD_MUTEX_INITIALIZER;
1609
-static pthread_mutex_t data_provider = PTHREAD_MUTEX_INITIALIZER;
1610
-static struct thread_params *data_requester;
1620
+static pthread_cond_t progress_cond = PTHREAD_COND_INITIALIZER;
1621
1622
static void *threaded_find_deltas(void *arg)
1623
{
1624
struct thread_params *me = arg;
1625
1616
- for (;;) {
1617
- pthread_mutex_lock(&data_request);
1618
- data_requester = me;
1619
- pthread_mutex_unlock(&data_provider);
1620
- pthread_mutex_lock(&data_ready);
1621
- pthread_mutex_unlock(&data_request);
1622
-
1623
- if (!me->remaining)
1624
- return NULL;
1625
-
1626
+ while (me->remaining) {
1627
find_deltas(me->list, &me->remaining,
1628
me->window, me->depth, me->processed);
1629
+
1630
+ progress_lock();
1631
+ me->working = 0;
1632
+ pthread_cond_signal(&progress_cond);
1633
+ progress_unlock();
1634
+
1635
+ /*
1636
+ * We must not set ->data_ready before we wait on the
1637
+ * condition because the main thread may have set it to 1
1638
+ * before we get here. In order to be sure that new
1639
+ * work is available if we see 1 in ->data_ready, it
1640
+ * was initialized to 0 before this thread was spawned
1641
+ * and we reset it to 0 right away.
1642
+ */
1643
+ pthread_mutex_lock(&me->mutex);
1644
+ while (!me->data_ready)
1645
+ pthread_cond_wait(&me->cond, &me->mutex);
1646
+ me->data_ready = 0;
1647
+ pthread_mutex_unlock(&me->mutex);
1648
}
1649
+ /* leave ->working 1 so that this doesn't get more work assigned */
1650
+ return NULL;
1651
}
1652
1653
static void ll_find_deltas(struct object_entry **list, unsigned list_size,
1654
int window, int depth, unsigned *processed)
1655
{
1634
- struct thread_params *target, p[delta_search_threads];
1656
+ struct thread_params p[delta_search_threads];
1657
int i, ret, active_threads = 0;
1658
1659
if (delta_search_threads <= 1) {
1661
return;
1662
}
1663
1642
- pthread_mutex_lock(&data_provider);
1643
- pthread_mutex_lock(&data_ready);
1644
-
1645
- /* Start work threads. */
1664
+ /* Partition the work amongst work threads. */
1665
for (i = 0; i < delta_search_threads; i++) {
1666
+ unsigned sub_size = list_size / (delta_search_threads - i);
1667
+
1668
p[i].window = window;
1669
p[i].depth = depth;
1670
p[i].processed = processed;
1650
- p[i].remaining = 0;
1651
- ret = pthread_create(&p[i].thread, NULL,
1652
- threaded_find_deltas, &p[i]);
1653
- if (ret)
1654
- die("unable to create thread: %s", strerror(ret));
1655
- active_threads++;
1656
- }
1657
-
1658
- /* Then partition the work amongst them. */
1659
- for (i = 0; i < delta_search_threads; i++) {
1660
- unsigned sub_size = list_size / (delta_search_threads - i);
1661
-
1662
- pthread_mutex_lock(&data_provider);
1663
- target = data_requester;
1664
- if (!sub_size) {
1665
- pthread_mutex_unlock(&data_ready);
1666
- pthread_join(target->thread, NULL);
1667
- active_threads--;
1668
- continue;
1669
- }
1671
+ p[i].working = 1;
1672
+ p[i].data_ready = 0;
1673
+ pthread_mutex_init(&p[i].mutex, NULL);
1674
+ pthread_cond_init(&p[i].cond, NULL);
1675
1676
/* try to split chunks on "path" boundaries */
1677
while (sub_size < list_size && list[sub_size]->hash &&
1678
list[sub_size]->hash == list[sub_size-1]->hash)
1679
sub_size++;
1680
1676
- target->list = list;
1677
- target->list_size = sub_size;
1678
- target->remaining = sub_size;
1679
- pthread_mutex_unlock(&data_ready);
1681
+ p[i].list = list;
1682
+ p[i].list_size = sub_size;
1683
+ p[i].remaining = sub_size;
1684
1685
list += sub_size;
1686
list_size -= sub_size;
1687
}
1688
1689
+ /* Start work threads. */
1690
+ for (i = 0; i < delta_search_threads; i++) {
1691
+ if (!p[i].list_size)
1692
+ continue;
1693
+ ret = pthread_create(&p[i].thread, NULL,
1694
+ threaded_find_deltas, &p[i]);
1695
+ if (ret)
1696
+ die("unable to create thread: %s", strerror(ret));
1697
+ active_threads++;
1698
+ }
1699
+
1700
/*
1701
* Now let's wait for work completion. Each time a thread is done
1702
* with its work, we steal half of the remaining work from the
1705
* until the remaining object list segments are simply too short
1706
* to be worth splitting anymore.
1707
*/
1693
- do {
1708
+ while (active_threads) {
1709
+ struct thread_params *target = NULL;
1710
struct thread_params *victim = NULL;
1711
unsigned sub_size = 0;
1696
- pthread_mutex_lock(&data_provider);
1697
- target = data_requester;
1712
1713
progress_lock();
1714
+ for (;;) {
1715
+ for (i = 0; !target && i < delta_search_threads; i++)
1716
+ if (!p[i].working)
1717
+ target = &p[i];
1718
+ if (target)
1719
+ break;
1720
+ pthread_cond_wait(&progress_cond, &progress_mutex);
1721
+ }
1722
+
1723
for (i = 0; i < delta_search_threads; i++)
1724
if (p[i].remaining > 2*window &&
1725
(!victim || victim->remaining < p[i].remaining))
1746
victim->list_size -= sub_size;
1747
victim->remaining -= sub_size;
1748
}
1726
- progress_unlock();
1727
-
1749
target->list_size = sub_size;
1750
target->remaining = sub_size;
1730
- pthread_mutex_unlock(&data_ready);
1751
+ target->working = 1;
1752
+ progress_unlock();
1753
+
1754
+ pthread_mutex_lock(&target->mutex);
1755
+ target->data_ready = 1;
1756
+ pthread_cond_signal(&target->cond);
1757
+ pthread_mutex_unlock(&target->mutex);
1758
1759
if (!sub_size) {
1760
pthread_join(target->thread, NULL);
1761
+ pthread_cond_destroy(&target->cond);
1762
+ pthread_mutex_destroy(&target->mutex);
1763
active_threads--;
1764
}
1736
- } while (active_threads);
1765
+ }
1766
}
1767
1768
#else