+/* Play back queued responses */
+static int
+syncprov_qplay( Operation *op, slap_overinst *on, syncops *so )
+{
+ syncres *sr;
+ Entry *e;
+ opcookie opc;
+ int rc = 0;
+
+ opc.son = on;
+
+ for (;;) {
+ ldap_pvt_thread_mutex_lock( &so->s_mutex );
+ sr = so->s_res;
+ if ( sr )
+ so->s_res = sr->s_next;
+ if ( !so->s_res )
+ so->s_restail = NULL;
+ ldap_pvt_thread_mutex_unlock( &so->s_mutex );
+
+ if ( !sr || so->s_op->o_abandon )
+ break;
+
+ opc.sdn = sr->s_dn;
+ opc.sndn = sr->s_ndn;
+ opc.suuid = sr->s_uuid;
+ opc.sctxcsn = sr->s_csn;
+ opc.sreference = sr->s_isreference;
+ e = NULL;
+
+ if ( sr->s_mode != LDAP_SYNC_DELETE ) {
+ rc = overlay_entry_get_ov( op, &opc.sndn, NULL, NULL, 0, &e, on );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_SYNC, "syncprov_qplay: failed to get %s, "
+ "error (%d), ignoring...\n", opc.sndn.bv_val, rc, 0 );
+ ch_free( sr );
+ rc = 0;
+ continue;
+ }
+ }
+ rc = syncprov_sendresp( op, &opc, so, &e, sr->s_mode );
+
+ if ( e ) {
+ overlay_entry_release_ov( op, e, 0, on );
+ }
+
+ ch_free( sr );
+
+ if ( rc )
+ break;
+ }
+ return rc;
+}
+
+/* runqueue task for playing back queued responses */
+static void *
+syncprov_qtask( void *ctx, void *arg )
+{
+ struct re_s *rtask = arg;
+ syncops *so = rtask->arg;
+ slap_overinst *on = so->s_op->o_private;
+ OperationBuffer opbuf;
+ Operation *op;
+ BackendDB be;
+ int rc;
+
+ op = (Operation *) &opbuf;
+ *op = *so->s_op;
+ op->o_hdr = (Opheader *)(op+1);
+ op->o_controls = (void **)(op->o_hdr+1);
+ memset( op->o_controls, 0, SLAP_MAX_CIDS * sizeof(void *));
+
+ *op->o_hdr = *so->s_op->o_hdr;
+
+ op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx);
+ op->o_tmpmfuncs = &slap_sl_mfuncs;
+ op->o_threadctx = ctx;
+
+ /* syncprov_qplay expects a fake db */
+ be = *so->s_op->o_bd;
+ be.be_flags |= SLAP_DBFLAG_OVERLAY;
+ op->o_bd = &be;
+ op->o_private = NULL;
+ op->o_callback = NULL;
+
+ rc = syncprov_qplay( op, on, so );
+
+ /* decrement use count... */
+ syncprov_free_syncop( so );
+
+ /* wait until we get explicitly scheduled again */
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
+ if ( rc == 0 ) {
+ ldap_pvt_runqueue_resched( &slapd_rq, rtask, 1 );
+ } else {
+ /* bail out on any error */
+ ldap_pvt_runqueue_remove( &slapd_rq, rtask );
+ }
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ return NULL;
+}
+
+/* Start the task to play back queued psearch responses */