You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: pemfile_provider.go
    path of file: ./repos/sharingan/grpc-server/v1.33.2/security/advancedtls
    
    the code of the file until where you have to start completion: /*
 *
 * Copyright 2020 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eith
    
func NewPEMFileProvider(o PEMFileProviderOptions) (*PEMFileProvider, error) {
	if o.CertFile == "" && o.KeyFile == "" && o.TrustFile == "" {
		return nil, fmt.Errorf("at least one credential file needs to be specified")
	}
	if keySpecified, certSpecified := o.KeyFile != "", o.CertFile != ""; keySpecified != certSpecified {
		return nil, fmt.Errorf("private key file and identity cert file should be both specified or not specified")
	}
	if o.IdentityInterval == 0 {
		o.IdentityInterval = defaultIdentityInterval
	}
	if o.RootInterval == 0 {
		o.RootInterval = defaultRootInterval
	}
	provider := &PEMFileProvider{}
	if o.CertFile != "" && o.KeyFile != "" {
		provider.identityDistributor = certprovider.NewDistributor()
	}
	if o.TrustFile != "" {
		provider.rootDistributor = certprovider.NewDistributor()
	}
	// A goroutine to pull file changes.
	identityTicker := time.NewTicker(o.IdentityInterval)
	rootTicker := time.NewTicker(o.RootInterval)
	ctx, cancel := context.WithCancel(context.Background())
	// We pass a copy of PEMFileProviderOptions to the goroutine in case users
	// change it after we start reloading.
	go func() {
		for {
			select {
			case <-ctx.Done():
				identityTicker.Stop()
				rootTicker.Stop()
				return
			case <-identityTicker.C:
				if provider.identityDistributor == nil {
					continue
				}
				// Read identity certs from PEM files.
				identityCert, err := readKeyCertPairFunc(o.CertFile, o.KeyFile)
				if err != nil {
					// If the reading produces an error, we will skip the update for this
					// round and log the error.
					logger.Warningf("tls.LoadX509KeyPair reads %s and %s failed: %v", o.CertFile, o.KeyFile, err)
					continue
				}
				provider.identityDistributor.Set(&certprovider.KeyMaterial{Certs: []tls.Certificate{identityCert}}, nil)
			case <-rootTicker.C:
				if provider.rootDistributor == nil {
					continue
				}
				// Read root certs from PEM files.
				trustPool, err := readTrustCertFunc(o.TrustFile)
				if err != nil {
					// If the reading produces an error, we will skip the update for this
					// round and log the error.
					logger.Warningf("readTrustCertFunc reads %v failed: %v", o.TrustFile, err)
					continue
				}
				provider.rootDistributor.Set(&certprovider.KeyMaterial{Roots: trustPool}, nil)
			default:
			}
		}
	}()
	provider.cancel = cancel
	return provider, nil
}