All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori@linux.vnet.ibm.com>
To: Aurelien Jarno <aurelien@aurel32.net>
Cc: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>,
	Marcelo Tosatti <mtosatti@redhat.com>,
	qemu-devel@nongnu.org, Paul Brook <paul@codesourcery.com>,
	Arun Bharadwaj <arun@linux.vnet.ibm.com>,
	Paulo Bonzini <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 3/7] Add support for glib based threading and convert qemu thread to use it
Date: Tue, 25 Jan 2011 09:34:01 -0600	[thread overview]
Message-ID: <4D3EED69.3030407@linux.vnet.ibm.com> (raw)
In-Reply-To: <20110125142448.GI23331@hall.aurel32.net>

On 01/25/2011 08:24 AM, Aurelien Jarno wrote:
> On Mon, Jan 24, 2011 at 03:00:41PM -0600, Anthony Liguori wrote:
>    
>> GLib is an extremely common library that has a portable thread implementation
>> along with tons of other goodies.
>>
>> GLib and GObject have a fantastic amount of infrastructure we can leverage in
>> QEMU including an object oriented programming infrastructure.
>>
>> Short term, it has a very nice thread pool implementation that we could leverage
>> in something like virtio-9p.
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>
>> diff --git a/Makefile b/Makefile
>> index 6d601ee..bf24d1b 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -104,6 +104,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
>>
>>   QEMU_CFLAGS+=$(CURL_CFLAGS)
>>
>> +QEMU_CFLAGS+=$(GLIB_CFLAGS)
>> +
>>   ui/cocoa.o: ui/cocoa.m
>>
>>   ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>> diff --git a/Makefile.objs b/Makefile.objs
>> index c3e52c5..283e62a 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -316,3 +316,5 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>>
>> +vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
>> +
>> diff --git a/Makefile.target b/Makefile.target
>> index e15b1c4..2c1c90e 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -204,6 +204,7 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
>> +QEMU_CFLAGS += $(GLIB_CFLAGS)
>>
>>   # xen backend driver support
>>   obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
>> diff --git a/configure b/configure
>> index d5ac074..820fde9 100755
>> --- a/configure
>> +++ b/configure
>> @@ -1658,6 +1658,17 @@ EOF
>>   fi
>>
>>   ##########################################
>> +# glib support probe
>> +if $pkg_config --modversion gthread-2.0>  /dev/null 2>&1 ; then
>> +    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
>> +    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
>> +    libs_softmmu="$glib_libs $libs_softmmu"
>> +else
>> +    echo "glib-2.0 required to compile QEMU"
>> +    exit 1
>> +fi
>> +
>> +##########################################
>>   # kvm probe
>>   if test "$kvm" != "no" ; then
>>       cat>  $TMPC<<EOF
>> @@ -2677,6 +2688,7 @@ if test "$bluez" = "yes" ; then
>>     echo "CONFIG_BLUEZ=y">>  $config_host_mak
>>     echo "BLUEZ_CFLAGS=$bluez_cflags">>  $config_host_mak
>>   fi
>> +echo "GLIB_CFLAGS=$glib_cflags">>  $config_host_mak
>>   if test "$xen" = "yes" ; then
>>     echo "CONFIG_XEN=y">>  $config_host_mak
>>   fi
>> diff --git a/qemu-thread.c b/qemu-thread.c
>> index fbc78fe..2c521ab 100644
>> --- a/qemu-thread.c
>> +++ b/qemu-thread.c
>> @@ -10,183 +10,142 @@
>>    * See the COPYING file in the top-level directory.
>>    *
>>    */
>> -#include<stdlib.h>
>> -#include<stdio.h>
>> -#include<errno.h>
>> -#include<time.h>
>> -#include<signal.h>
>> -#include<stdint.h>
>> -#include<string.h>
>>      
> Why removing<signal.h>?
>    

It looked like unnecessary includes crept in so I remove them all.  It 
still built for me but apparently not for you.  I'll update accordingly.

Maybe we should put signal.h in qemu-common.h?

Regards,

Anthony Liguori

>> -#include "qemu-thread.h"
>>
>> -static void error_exit(int err, const char *msg)
>> -{
>> -    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
>> -    exit(1);
>> -}
>> +#include "qemu-common.h"
>> +#include "qemu-thread.h"
>>
>>   void qemu_mutex_init(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_init(&mutex->lock, NULL);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_init(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_destroy(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_destroy(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_free(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_lock(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_lock(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_lock(&mutex->lock);
>>   }
>>
>>   int qemu_mutex_trylock(QemuMutex *mutex)
>>   {
>> -    return pthread_mutex_trylock(&mutex->lock);
>> -}
>> -
>> -static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
>> -{
>> -    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
>> -    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
>> -    if (ts->tv_nsec>= 1000000000) {
>> -        ts->tv_nsec -= 1000000000;
>> -        ts->tv_sec++;
>> -    }
>> -}
>> -
>> -int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
>> -{
>> -    int err;
>> -    struct timespec ts;
>> -
>> -    clock_gettime(CLOCK_REALTIME,&ts);
>> -    timespec_add_ms(&ts, msecs);
>> -
>> -    err = pthread_mutex_timedlock(&mutex->lock,&ts);
>> -    if (err&&  err != ETIMEDOUT)
>> -        error_exit(err, __func__);
>> -    return err;
>> +    return g_static_mutex_trylock(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_unlock(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_unlock(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_unlock(&mutex->lock);
>>   }
>>
>>   void qemu_cond_init(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_init(&cond->cond, NULL);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    cond->cond = g_cond_new();
>>   }
>>
>>   void qemu_cond_destroy(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_destroy(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_free(cond->cond);
>>   }
>>
>>   void qemu_cond_signal(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_signal(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_signal(cond->cond);
>>   }
>>
>>   void qemu_cond_broadcast(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_broadcast(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_broadcast(cond->cond);
>>   }
>>
>>   void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_wait(&cond->cond,&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_wait(cond->cond, g_static_mutex_get_mutex(&mutex->lock));
>>   }
>>
>>   int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
>>   {
>> -    struct timespec ts;
>> -    int err;
>> +    GTimeVal abs_time;
>> +
>> +    assert(cond->cond != NULL);
>>
>> -    clock_gettime(CLOCK_REALTIME,&ts);
>> -    timespec_add_ms(&ts, msecs);
>> +    g_get_current_time(&abs_time);
>> +    g_time_val_add(&abs_time, msecs * 1000); /* MSEC to USEC */
>>
>> -    err = pthread_cond_timedwait(&cond->cond,&mutex->lock,&ts);
>> -    if (err&&  err != ETIMEDOUT)
>> -        error_exit(err, __func__);
>> -    return err;
>> +    return g_cond_timed_wait(cond->cond,
>> +                             g_static_mutex_get_mutex(&mutex->lock),&abs_time);
>> +}
>> +
>> +struct trampoline_data
>> +{
>> +    QemuThread *thread;
>> +    void *(*startfn)(void *);
>> +    void *opaque;
>> +    QemuMutex lock;
>> +};
>> +
>> +static gpointer thread_trampoline(gpointer data)
>> +{
>> +    struct trampoline_data *td = data;
>> +    gpointer retval;
>> +
>> +    td->thread->tid = pthread_self();
>> +    qemu_mutex_unlock(&td->lock);
>> +
>> +    retval = td->startfn(td->opaque);
>> +    qemu_free(td);
>> +
>> +    return retval;
>>   }
>>
>>   void qemu_thread_create(QemuThread *thread,
>> -                       void *(*start_routine)(void*),
>> -                       void *arg)
>> +                        void *(*start_routine)(void*),
>> +                        void *arg)
>>   {
>> -    int err;
>> +    struct trampoline_data *td = qemu_malloc(sizeof(*td));
>> +    sigset_t set, old;
>>
>> -    /* Leave signal handling to the iothread.  */
>> -    sigset_t set, oldset;
>> +    td->startfn = start_routine;
>> +    td->opaque = arg;
>> +    td->thread = thread;
>> +    qemu_mutex_init(&td->lock);
>> +
>> +    /* on behalf of the new thread */
>> +    qemu_mutex_lock(&td->lock);
>>
>>       sigfillset(&set);
>>      
> If it is still in use here? This simply doesn't build:
>
> qemu-thread.c: In function ‘q_thread_create_nosignal’:
> qemu-thread.c:34: error: implicit declaration of function ‘sigfillset’
> qemu-thread.c:34: error: nested extern declaration of ‘sigfillset’
> qemu-thread.c:35: error: implicit declaration of function ‘pthread_sigmask’
> qemu-thread.c:35: error: nested extern declaration of ‘pthread_sigmask’
> qemu-thread.c:35: error: ‘SIG_SETMASK’ undeclared (first use in this function)
> qemu-thread.c:35: error: (Each undeclared identifier is reported only once
> qemu-thread.c:35: error: for each function it appears in.)
> qemu-thread.c: In function ‘qemu_sthread_create’:
> qemu-thread.c:80: error: ‘SIG_SETMASK’ undeclared (first use in this function)
> qemu-thread.c: In function ‘qemu_sthread_signal’:
> qemu-thread.c:96: error: implicit declaration of function ‘pthread_kill’
> qemu-thread.c:96: error: nested extern declaration of ‘pthread_kill’
>
>
>    
>> -    pthread_sigmask(SIG_SETMASK,&set,&oldset);
>> -    err = pthread_create(&thread->thread, NULL, start_routine, arg);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    pthread_sigmask(SIG_SETMASK,&set,&old);
>> +    thread->thread = g_thread_create(thread_trampoline, td, TRUE, NULL);
>> +    pthread_sigmask(SIG_SETMASK,&old, NULL);
>> +
>> +    /* we're transfering ownership of this lock to the thread so we no
>> +     * longer hold it here */
>>
>> -    pthread_sigmask(SIG_SETMASK,&oldset, NULL);
>> +    qemu_mutex_lock(&td->lock);
>> +    /* validate tid */
>> +    qemu_mutex_unlock(&td->lock);
>> +
>> +    qemu_mutex_destroy(&td->lock);
>>   }
>>
>>   void qemu_thread_signal(QemuThread *thread, int sig)
>>   {
>> -    int err;
>> -
>> -    err = pthread_kill(thread->thread, sig);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    pthread_kill(thread->tid, sig);
>>   }
>>
>>   void qemu_thread_self(QemuThread *thread)
>>   {
>> -    thread->thread = pthread_self();
>> +    thread->thread = g_thread_self();
>> +    thread->tid = pthread_self();
>>   }
>>
>>   int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
>>   {
>> -   return pthread_equal(thread1->thread, thread2->thread);
>> +    return (thread1->thread == thread2->thread);
>>   }
>>
>>   void qemu_thread_exit(void *retval)
>>   {
>> -    pthread_exit(retval);
>> +    g_thread_exit(retval);
>>   }
>> diff --git a/qemu-thread.h b/qemu-thread.h
>> index 19bb30c..dc22a60 100644
>> --- a/qemu-thread.h
>> +++ b/qemu-thread.h
>> @@ -1,18 +1,19 @@
>>   #ifndef __QEMU_THREAD_H
>>   #define __QEMU_THREAD_H 1
>> -#include "semaphore.h"
>> -#include "pthread.h"
>> +#include<glib.h>
>> +#include<pthread.h>
>>
>>   struct QemuMutex {
>> -    pthread_mutex_t lock;
>> +    GStaticMutex lock;
>>   };
>>
>>   struct QemuCond {
>> -    pthread_cond_t cond;
>> +    GCond *cond;
>>   };
>>
>>   struct QemuThread {
>> -    pthread_t thread;
>> +    GThread *thread;
>> +    pthread_t tid;
>>   };
>>
>>   typedef struct QemuMutex QemuMutex;
>> diff --git a/vl.c b/vl.c
>> index 0292184..bbe0931 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -165,6 +165,8 @@ int main(int argc, char **argv)
>>
>>   #include "ui/qemu-spice.h"
>>
>> +#include<glib.h>
>> +
>>   //#define DEBUG_NET
>>   //#define DEBUG_SLIRP
>>
>> @@ -1918,6 +1920,8 @@ int main(int argc, char **argv, char **envp)
>>       atexit(qemu_run_exit_notifiers);
>>       error_set_progname(argv[0]);
>>
>> +    g_thread_init(NULL);
>> +
>>       init_clocks();
>>
>>       qemu_cache_utils_init(envp);
>> -- 
>> 1.7.0.4
>>
>>
>>
>>      
>    

  reply	other threads:[~2011-01-25 15:34 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-24 21:00 [Qemu-devel] [RFC 0/7] Introduce hard dependency on glib Anthony Liguori
2011-01-24 21:00 ` [Qemu-devel] [PATCH 1/7] io-thread: make sure to initialize qemu_work_cond and qemu_cpu_cond Anthony Liguori
2011-02-08  8:53   ` [Qemu-devel] " Jan Kiszka
2011-02-08  9:01     ` Anthony Liguori
2011-01-24 21:00 ` [Qemu-devel] [PATCH 2/7] Enable I/O thread and VNC threads by default Anthony Liguori
2011-01-24 22:28   ` [Qemu-devel] " Anthony Liguori
2011-01-25  9:17     ` Edgar E. Iglesias
2011-01-25 13:34       ` Marcelo Tosatti
2011-02-07 10:12         ` Marcelo Tosatti
2011-02-07 16:03           ` Marcelo Tosatti
2011-02-07 16:23             ` Paolo Bonzini
2011-02-07 17:10               ` Jan Kiszka
2011-02-07 21:02                 ` Anthony Liguori
2011-02-07 21:45                   ` Aurelien Jarno
2011-02-08  2:09                     ` Anthony Liguori
2011-02-08  7:26                       ` Aurelien Jarno
2011-02-08  8:08                         ` Paolo Bonzini
2011-02-08  8:50                           ` Jan Kiszka
2011-02-08  9:05                             ` Aurelien Jarno
2011-02-08  9:12                               ` Anthony Liguori
2011-02-08  9:49                                 ` Paolo Bonzini
2011-02-08  9:51                               ` Jan Kiszka
2011-02-08  9:58                                 ` Aurelien Jarno
2011-02-08 10:03                                   ` Jan Kiszka
2011-02-08 10:06                                     ` Aurelien Jarno
2011-02-08 10:16                                       ` Alexander Graf
2011-02-08 10:17                                       ` Stefan Hajnoczi
2011-02-08 10:27                                         ` Aurelien Jarno
2011-02-08 10:31                                           ` Paolo Bonzini
2011-02-08 10:40                                           ` Jan Kiszka
2011-02-08 18:05                                           ` Anthony Liguori
2011-02-08 11:29                                             ` Aurelien Jarno
2011-02-08 12:38                                             ` Riku Voipio
2011-02-08 10:21                                       ` Jan Kiszka
2011-02-08 10:26                                         ` Aurelien Jarno
2011-02-08 10:30                                           ` Jan Kiszka
2011-02-08 17:58                                       ` Anthony Liguori
2011-02-08 11:07                                         ` Tristan Gingold
2011-02-08 11:46                                           ` Aurelien Jarno
2011-02-08 12:07                                             ` Paolo Bonzini
2011-02-08 19:21                                             ` Anthony Liguori
2011-02-08 11:15                                         ` Aurelien Jarno
2011-02-08 12:10                                           ` Paolo Bonzini
2011-02-08 13:31                                             ` Aurelien Jarno
2011-02-08 15:08                                               ` Aurelien Jarno
2011-02-09 17:35                                                 ` Aurelien Jarno
2011-02-09 20:07                                                   ` Anthony Liguori
2011-02-11  0:03                                                     ` Marcelo Tosatti
2011-02-08 19:17                                           ` Anthony Liguori
2011-02-08 13:30                                             ` Aurelien Jarno
2011-02-08 20:54                                               ` Anthony Liguori
2011-02-08 15:09                                                 ` Aurelien Jarno
2011-02-09 17:13                                                   ` Blue Swirl
2011-02-09 22:16                                                     ` [Qemu-devel] " Stefan Weil
2011-02-10  7:34                                                       ` Paolo Bonzini
2011-02-10  9:54                                                       ` Paolo Bonzini
2011-02-10 19:46                                                         ` Stefan Weil
2011-02-08 10:06                                   ` [Qemu-devel] " Paolo Bonzini
2011-02-07 18:35             ` Edgar E. Iglesias
2011-02-07 20:44             ` Aurelien Jarno
2011-02-07 21:30             ` Scott Wood
2011-02-07 20:47           ` Edgar E. Iglesias
2011-01-25  8:33   ` [Qemu-devel] [PATCH 0/2] vnc: the lost parts Corentin Chary
2011-01-25  8:33   ` [Qemu-devel] [PATCH 1/2] vl.c: set NULL upon deleting handlers in qemu_set_fd_handler2() Corentin Chary
2011-01-25 10:03     ` Stefan Hajnoczi
2011-01-25 10:13       ` Corentin Chary
2011-01-25 10:26         ` Stefan Hajnoczi
2011-01-25 12:05           ` Yoshiaki Tamura
2011-01-25  8:33   ` [Qemu-devel] [PATCH 2/2] vnc: qemu can die if the client is disconnected while updating screen Corentin Chary
2011-01-24 21:00 ` [Qemu-devel] [PATCH 3/7] Add support for glib based threading and convert qemu thread to use it Anthony Liguori
2011-01-25 14:24   ` Aurelien Jarno
2011-01-25 15:34     ` Anthony Liguori [this message]
2011-02-02 17:32   ` [Qemu-devel] " Paolo Bonzini
2011-02-02 17:35     ` Anthony Liguori
2011-01-24 21:00 ` [Qemu-devel] [PATCH 4/7] Get rid of QemuMutex and teach its callers about GStaticMutex Anthony Liguori
2011-01-24 22:24   ` [Qemu-devel] " Jan Kiszka
2011-01-25  0:02     ` Anthony Liguori
2011-01-25  7:39       ` Jan Kiszka
2011-01-24 21:00 ` [Qemu-devel] [PATCH 5/7] threads: get rid of QemuCond and teach callers about GCond Anthony Liguori
2011-01-24 21:00 ` [Qemu-devel] [PATCH 6/7] Teach vnc server to use GThread directly Anthony Liguori
2011-01-26 10:39   ` Stefan Hajnoczi
2011-01-24 21:00 ` [Qemu-devel] [PATCH 7/7] Rename QemuThread to QemuSThread to indicate that it is not a generic thread Anthony Liguori
2011-01-24 21:28 ` [Qemu-devel] Re: [RFC 0/7] Introduce hard dependency on glib Paolo Bonzini
2011-01-24 22:01   ` Anthony Liguori
2011-01-25 10:41     ` Paolo Bonzini
2011-01-25 11:14       ` Daniel P. Berrange
2011-01-25 11:21         ` Paolo Bonzini
2011-01-25  0:24 ` [Qemu-devel] " Anthony Liguori
2011-01-25  6:51   ` Edgar E. Iglesias
2011-01-25 10:24 ` Stefan Hajnoczi
2011-01-25 11:51 ` Gerd Hoffmann
2011-01-25 12:04   ` Daniel P. Berrange
2011-01-25 14:48   ` Stefano Stabellini
2011-01-25 17:48     ` Anthony Liguori
2011-01-25 18:12       ` Stefano Stabellini
2011-01-25 14:23 ` Aurelien Jarno
2011-01-25 15:35   ` Anthony Liguori
     [not found] ` <20110126044710.GU9566@redhat.com>
2011-01-26 15:53   ` Anthony Liguori
2011-01-26 21:23     ` Stefan Hajnoczi
2011-01-26 22:12       ` Anthony Liguori
2011-01-26 17:48 ` Johannes Stezenbach

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D3EED69.3030407@linux.vnet.ibm.com \
    --to=aliguori@linux.vnet.ibm.com \
    --cc=arun@linux.vnet.ibm.com \
    --cc=aurelien@aurel32.net \
    --cc=mtosatti@redhat.com \
    --cc=paul@codesourcery.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.