@@ -1594,94 +1594,109 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
15941594
15951595#ifdef THREADED_DELTA_SEARCH
15961596
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+
15971606struct thread_params {
15981607 pthread_t thread ;
15991608 struct object_entry * * list ;
16001609 unsigned list_size ;
16011610 unsigned remaining ;
16021611 int window ;
16031612 int depth ;
1613+ int working ;
1614+ int data_ready ;
1615+ pthread_mutex_t mutex ;
1616+ pthread_cond_t cond ;
16041617 unsigned * processed ;
16051618};
16061619
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 ;
16111621
16121622static void * threaded_find_deltas (void * arg )
16131623{
16141624 struct thread_params * me = arg ;
16151625
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 ) {
16261627 find_deltas (me -> list , & me -> remaining ,
16271628 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 );
16281648 }
1649+ /* leave ->working 1 so that this doesn't get more work assigned */
1650+ return NULL ;
16291651}
16301652
16311653static void ll_find_deltas (struct object_entry * * list , unsigned list_size ,
16321654 int window , int depth , unsigned * processed )
16331655{
1634- struct thread_params * target , p [delta_search_threads ];
1656+ struct thread_params p [delta_search_threads ];
16351657 int i , ret , active_threads = 0 ;
16361658
16371659 if (delta_search_threads <= 1 ) {
16381660 find_deltas (list , & list_size , window , depth , processed );
16391661 return ;
16401662 }
16411663
1642- pthread_mutex_lock (& data_provider );
1643- pthread_mutex_lock (& data_ready );
1644-
1645- /* Start work threads. */
1664+ /* Partition the work amongst work threads. */
16461665 for (i = 0 ; i < delta_search_threads ; i ++ ) {
1666+ unsigned sub_size = list_size / (delta_search_threads - i );
1667+
16471668 p [i ].window = window ;
16481669 p [i ].depth = depth ;
16491670 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 );
16701675
16711676 /* try to split chunks on "path" boundaries */
16721677 while (sub_size < list_size && list [sub_size ]-> hash &&
16731678 list [sub_size ]-> hash == list [sub_size - 1 ]-> hash )
16741679 sub_size ++ ;
16751680
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 ;
16801684
16811685 list += sub_size ;
16821686 list_size -= sub_size ;
16831687 }
16841688
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+
16851700 /*
16861701 * Now let's wait for work completion. Each time a thread is done
16871702 * with its work, we steal half of the remaining work from the
@@ -1690,13 +1705,21 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
16901705 * until the remaining object list segments are simply too short
16911706 * to be worth splitting anymore.
16921707 */
1693- do {
1708+ while (active_threads ) {
1709+ struct thread_params * target = NULL ;
16941710 struct thread_params * victim = NULL ;
16951711 unsigned sub_size = 0 ;
1696- pthread_mutex_lock (& data_provider );
1697- target = data_requester ;
16981712
16991713 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+
17001723 for (i = 0 ; i < delta_search_threads ; i ++ )
17011724 if (p [i ].remaining > 2 * window &&
17021725 (!victim || victim -> remaining < p [i ].remaining ))
@@ -1723,17 +1746,23 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
17231746 victim -> list_size -= sub_size ;
17241747 victim -> remaining -= sub_size ;
17251748 }
1726- progress_unlock ();
1727-
17281749 target -> list_size = sub_size ;
17291750 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 );
17311758
17321759 if (!sub_size ) {
17331760 pthread_join (target -> thread , NULL );
1761+ pthread_cond_destroy (& target -> cond );
1762+ pthread_mutex_destroy (& target -> mutex );
17341763 active_threads -- ;
17351764 }
1736- } while ( active_threads );
1765+ }
17371766}
17381767
17391768#else
0 commit comments