+/* Implementation of the supports_set_thread_options target
+ method. */
+
+bool
+remote_target::supports_set_thread_options (gdb_thread_options options)
+{
+ remote_state *rs = get_remote_state ();
+ return (m_features.packet_support (PACKET_QThreadOptions) == PACKET_ENABLE
+ && (rs->supported_thread_options & options) == options);
+}
+
+/* For coalescing reasons, actually sending the options to the target
+ happens at resume time, via this function. See target_resume for
+ all-stop, and target_commit_resumed for non-stop. */
+
+void
+remote_target::commit_requested_thread_options ()
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (m_features.packet_support (PACKET_QThreadOptions) != PACKET_ENABLE)
+ return;
+
+ char *p = rs->buf.data ();
+ char *endp = p + get_remote_packet_size ();
+
+ /* Clear options for all threads by default. Note that unlike
+ vCont, the rightmost options that match a thread apply, so we
+ don't have to worry about whether we can use wildcard ptids. */
+ strcpy (p, "QThreadOptions;0");
+ p += strlen (p);
+
+ /* Send the QThreadOptions packet stored in P. */
+ auto flush = [&] ()
+ {
+ *p++ = '\0';
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, 0);
+
+ switch (m_features.packet_ok (rs->buf, PACKET_QThreadOptions))
+ {
+ case PACKET_OK:
+ if (strcmp (rs->buf.data (), "OK") != 0)
+ error (_("Remote refused setting thread options: %s"), rs->buf.data ());
+ break;
+ case PACKET_ERROR:
+ error (_("Remote failure reply: %s"), rs->buf.data ());
+ case PACKET_UNKNOWN:
+ gdb_assert_not_reached ("PACKET_UNKNOWN");
+ break;
+ }
+ };
+
+ /* Prepare P for another QThreadOptions packet. */
+ auto restart = [&] ()
+ {
+ p = rs->buf.data ();
+ strcpy (p, "QThreadOptions");
+ p += strlen (p);
+ };
+
+ /* Now set non-zero options for threads that need them. We don't
+ bother with the case of all threads of a process wanting the same
+ non-zero options as that's not an expected scenario. */
+ for (thread_info *tp : all_non_exited_threads (this))
+ {
+ gdb_thread_options options = tp->thread_options ();
+
+ if (options == 0)
+ continue;
+
+ /* It might be possible to we have more threads with options
+ than can fit a single QThreadOptions packet. So build each
+ options/thread pair in this separate buffer to make sure it
+ fits. */
+ constexpr size_t max_options_size = 100;
+ char obuf[max_options_size];
+ char *obuf_p = obuf;
+ char *obuf_endp = obuf + max_options_size;
+
+ *obuf_p++ = ';';
+ obuf_p += xsnprintf (obuf_p, obuf_endp - obuf_p, "%s",
+ phex_nz (options, sizeof (options)));
+ if (tp->ptid != magic_null_ptid)
+ {
+ *obuf_p++ = ':';
+ obuf_p = write_ptid (obuf_p, obuf_endp, tp->ptid);
+ }
+
+ size_t osize = obuf_p - obuf;
+ if (osize > endp - p)
+ {
+ /* This new options/thread pair doesn't fit the packet
+ buffer. Send what we have already. */
+ flush ();
+ restart ();
+
+ /* Should now fit. */
+ gdb_assert (osize <= endp - p);
+ }
+
+ memcpy (p, obuf, osize);
+ p += osize;
+ }
+
+ flush ();
+}
+