*** a/doc/src/sgml/ref/pg_receivexlog.sgml
--- b/doc/src/sgml/ref/pg_receivexlog.sgml
***************
*** 106,111 **** PostgreSQL documentation
--- 106,121 ----
       </varlistentry>
  
       <varlistentry>
+       <term><option>-S</option></term>
+       <term><option>--syncstandby</option></term>
+       <listitem>
+        <para>
+         Allow <application>pg_receivexlog</application> to be used as synchronous standby.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
+      <varlistentry>
        <term><option>-v</option></term>
        <term><option>--verbose</option></term>
        <listitem>
*** a/src/backend/replication/syncrep.c
--- b/src/backend/replication/syncrep.c
***************
*** 376,385 **** SyncRepReleaseWaiters(void)
  	/*
  	 * If this WALSender is serving a standby that is not on the list of
  	 * potential standbys then we have nothing to do. If we are still starting
! 	 * up or still running base backup, then leave quickly also.
  	 */
  	if (MyWalSnd->sync_standby_priority == 0 ||
! 		MyWalSnd->state < WALSNDSTATE_STREAMING)
  		return;
  
  	/*
--- 376,387 ----
  	/*
  	 * If this WALSender is serving a standby that is not on the list of
  	 * potential standbys then we have nothing to do. If we are still starting
! 	 * up, still running base backup or the current flush position is still
! 	 * invalid, then leave quickly also.
  	 */
  	if (MyWalSnd->sync_standby_priority == 0 ||
! 		MyWalSnd->state < WALSNDSTATE_STREAMING ||
! 		XLogRecPtrIsInvalid(MyWalSnd->flush))
  		return;
  
  	/*
***************
*** 399,405 **** SyncRepReleaseWaiters(void)
  			walsnd->state == WALSNDSTATE_STREAMING &&
  			walsnd->sync_standby_priority > 0 &&
  			(priority == 0 ||
! 			 priority > walsnd->sync_standby_priority))
  		{
  			priority = walsnd->sync_standby_priority;
  			syncWalSnd = walsnd;
--- 401,408 ----
  			walsnd->state == WALSNDSTATE_STREAMING &&
  			walsnd->sync_standby_priority > 0 &&
  			(priority == 0 ||
! 			 priority > walsnd->sync_standby_priority) &&
! 			!XLogRecPtrIsInvalid(walsnd->flush))
  		{
  			priority = walsnd->sync_standby_priority;
  			syncWalSnd = walsnd;
*** a/src/backend/replication/walreceiver.c
--- b/src/backend/replication/walreceiver.c
***************
*** 281,286 **** WalReceiverMain(void)
--- 281,291 ----
  	walrcv_connect(conninfo, startpoint);
  	DisableWalRcvImmediateExit();
  
+ 	/* Initialize LogstreamResult, reply_message and feedback_message */
+ 	LogstreamResult.Write = LogstreamResult.Flush = GetXLogReplayRecPtr(NULL);
+ 	MemSet(&reply_message, 0, sizeof(reply_message));
+ 	MemSet(&feedback_message, 0, sizeof(feedback_message));
+ 
  	/* Loop until end-of-streaming or error */
  	for (;;)
  	{
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 1501,1512 **** pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
  
  		if (walsnd->pid != 0)
  		{
! 			sync_priority[i] = walsnd->sync_standby_priority;
  
  			if (walsnd->state == WALSNDSTATE_STREAMING &&
  				walsnd->sync_standby_priority > 0 &&
  				(priority == 0 ||
! 				 priority > walsnd->sync_standby_priority))
  			{
  				priority = walsnd->sync_standby_priority;
  				sync_standby = i;
--- 1501,1519 ----
  
  		if (walsnd->pid != 0)
  		{
! 			/*
! 			 * Treat the standby like pg_basebackup background process
! 			 * which always returns an invalid flush location, as an
! 			 * asynchronous standby.
! 			 */
! 			sync_priority[i] = XLogRecPtrIsInvalid(walsnd->flush) ?
! 				0 : walsnd->sync_standby_priority;
  
  			if (walsnd->state == WALSNDSTATE_STREAMING &&
  				walsnd->sync_standby_priority > 0 &&
  				(priority == 0 ||
! 				 priority > walsnd->sync_standby_priority) &&
! 				!XLogRecPtrIsInvalid(walsnd->flush))
  			{
  				priority = walsnd->sync_standby_priority;
  				sync_standby = i;
*** a/src/bin/pg_basebackup/pg_basebackup.c
--- b/src/bin/pg_basebackup/pg_basebackup.c
***************
*** 234,240 **** LogStreamerMain(logstreamer_param *param)
  {
  	if (!ReceiveXlogStream(param->bgconn, param->startptr, param->timeline,
  						   param->sysidentifier, param->xlogdir,
! 						reached_end_position, standby_message_timeout, true))
  
  		/*
  		 * Any errors will already have been reported in the function process,
--- 234,241 ----
  {
  	if (!ReceiveXlogStream(param->bgconn, param->startptr, param->timeline,
  						   param->sysidentifier, param->xlogdir,
! 						reached_end_position, standby_message_timeout,
! 						   true, false))
  
  		/*
  		 * Any errors will already have been reported in the function process,
*** a/src/bin/pg_basebackup/pg_receivexlog.c
--- b/src/bin/pg_basebackup/pg_receivexlog.c
***************
*** 40,45 ****
--- 40,46 ----
  char	   *basedir = NULL;
  int			verbose = 0;
  int			noloop = 0;
+ bool			syncstandby = false;
  int			standby_message_timeout = 10 * 1000;		/* 10 sec = default */
  volatile bool time_to_abort = false;
  
***************
*** 59,64 **** usage(void)
--- 60,66 ----
  	printf(_("\nOptions:\n"));
  	printf(_("  -D, --directory=DIR      receive transaction log files into this directory\n"));
  	printf(_("  -n, --noloop             do not loop on connection lost\n"));
+ 	printf(_("  -S, --syncstandby        allow pg_receivexlog to be used as synchronous standby\n"));
  	printf(_("  -v, --verbose            output verbose messages\n"));
  	printf(_("  -V, --version            output version information, then exit\n"));
  	printf(_("  -?, --help               show this help, then exit\n"));
***************
*** 272,279 **** StreamLog(void)
  				timeline);
  
  	ReceiveXlogStream(conn, startpos, timeline, NULL, basedir,
! 					  stop_streaming,
! 					  standby_message_timeout, false);
  
  	PQfinish(conn);
  }
--- 274,281 ----
  				timeline);
  
  	ReceiveXlogStream(conn, startpos, timeline, NULL, basedir,
! 					  stop_streaming, standby_message_timeout,
! 					  false, syncstandby);
  
  	PQfinish(conn);
  }
***************
*** 305,310 **** main(int argc, char **argv)
--- 307,313 ----
  		{"no-password", no_argument, NULL, 'w'},
  		{"password", no_argument, NULL, 'W'},
  		{"statusint", required_argument, NULL, 's'},
+ 		{"syncstandby", no_argument, NULL, 'S'},
  		{"verbose", no_argument, NULL, 'v'},
  		{NULL, 0, NULL, 0}
  	};
***************
*** 330,336 **** main(int argc, char **argv)
  		}
  	}
  
! 	while ((c = getopt_long(argc, argv, "D:h:p:U:s:nwWv",
  							long_options, &option_index)) != -1)
  	{
  		switch (c)
--- 333,339 ----
  		}
  	}
  
! 	while ((c = getopt_long(argc, argv, "D:h:p:U:s:nSwWv",
  							long_options, &option_index)) != -1)
  	{
  		switch (c)
***************
*** 368,373 **** main(int argc, char **argv)
--- 371,379 ----
  					exit(1);
  				}
  				break;
+ 			case 'S':
+ 				syncstandby = true;
+ 				break;
  			case 'n':
  				noloop = 1;
  				break;
*** a/src/bin/pg_basebackup/receivelog.c
--- b/src/bin/pg_basebackup/receivelog.c
***************
*** 264,270 **** localTimestampDifferenceExceeds(TimestampTz start_time,
   * Note: The log position *must* be at a log segment start!
   */
  bool
! ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysidentifier, char *basedir, stream_stop_callback stream_stop, int standby_message_timeout, bool rename_partial)
  {
  	char		query[128];
  	char		current_walfile_name[MAXPGPATH];
--- 264,274 ----
   * Note: The log position *must* be at a log segment start!
   */
  bool
! ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline,
! 				  char *sysidentifier, char *basedir,
! 				  stream_stop_callback stream_stop,
! 				  int standby_message_timeout,
! 				  bool rename_partial, bool syncstandby)
  {
  	char		query[128];
  	char		current_walfile_name[MAXPGPATH];
***************
*** 273,278 **** ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
--- 277,285 ----
  	int			walfile = -1;
  	int64		last_status = -1;
  	XLogRecPtr	blockpos = InvalidXLogRecPtr;
+ 	XLogRecPtr	flushpos = InvalidXLogRecPtr;
+ 	char		replybuf[sizeof(StandbyReplyMessage) + 1];
+ 	StandbyReplyMessage *replymsg = (StandbyReplyMessage *) (replybuf + 1);
  
  	if (sysidentifier != NULL)
  	{
***************
*** 351,366 **** ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
  		 * Potentially send a status message to the master
  		 */
  		now = localGetCurrentTimestamp();
! 		if (standby_message_timeout > 0 &&
! 			localTimestampDifferenceExceeds(last_status, now,
! 											standby_message_timeout))
  		{
  			/* Time to send feedback! */
! 			char		replybuf[sizeof(StandbyReplyMessage) + 1];
! 			StandbyReplyMessage *replymsg = (StandbyReplyMessage *) (replybuf + 1);
! 
! 			replymsg->write = InvalidXLogRecPtr;
! 			replymsg->flush = InvalidXLogRecPtr;
  			replymsg->apply = InvalidXLogRecPtr;
  			replymsg->sendTime = now;
  			replybuf[0] = 'r';
--- 358,373 ----
  		 * Potentially send a status message to the master
  		 */
  		now = localGetCurrentTimestamp();
! 		if ((standby_message_timeout > 0 &&
! 			 localTimestampDifferenceExceeds(last_status, now,
! 											 standby_message_timeout)) ||
! 			(syncstandby &&
! 			 (!XLByteEQ(replymsg->write, blockpos) ||
! 			  !XLByteEQ(replymsg->flush, flushpos))))
  		{
  			/* Time to send feedback! */
! 			replymsg->write = blockpos;
! 			replymsg->flush = syncstandby ? flushpos : InvalidXLogRecPtr;
  			replymsg->apply = InvalidXLogRecPtr;
  			replymsg->sendTime = now;
  			replybuf[0] = 'r';
***************
*** 550,555 **** ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
--- 557,563 ----
  
  				walfile = -1;
  				xlogoff = 0;
+ 				flushpos = blockpos;
  
  				if (stream_stop != NULL)
  				{
*** a/src/bin/pg_basebackup/receivelog.h
--- b/src/bin/pg_basebackup/receivelog.h
***************
*** 13,16 **** extern bool ReceiveXlogStream(PGconn *conn,
  				  char *basedir,
  				  stream_stop_callback stream_stop,
  				  int standby_message_timeout,
! 				  bool rename_partial);
--- 13,17 ----
  				  char *basedir,
  				  stream_stop_callback stream_stop,
  				  int standby_message_timeout,
! 				  bool rename_partial,
! 				  bool syncstandby);
